From 5a898f2419cf0ab22bcdbaa61859d08078d08e6a Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 12 Jun 2008 00:26:08 +0000 Subject: [PATCH 001/100] Add Boost.Unordered to release branch. [SVN r46342] --- doc/ref.xml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/doc/ref.xml b/doc/ref.xml index b541208a..da982b62 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -636,10 +636,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) float - float - + void + Changes the container's maximum load factor, using z as a hint. - + @@ -1381,10 +1381,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) float - float - + void + Changes the container's maximum load factor, using z as a hint. - + @@ -2175,10 +2175,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) float - float - + void + Changes the container's maximum load factor, using z as a hint. - + @@ -2936,10 +2936,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) float - float - + void + Changes the container's maximum load factor, using z as a hint. - + From c8d0cb88add8f52fcc5b24f2d519459754135687 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 15 Jun 2008 19:21:12 +0000 Subject: [PATCH 002/100] Merge unordered 'move_from' fix from trunk [46410]. [SVN r46413] --- include/boost/unordered_map.hpp | 4 ++-- include/boost/unordered_set.hpp | 4 ++-- test/unordered/compile_map.cpp | 15 +++++++++++++++ test/unordered/compile_set.cpp | 13 +++++++++++++ 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/include/boost/unordered_map.hpp b/include/boost/unordered_map.hpp index c172881f..bd6cfb2f 100644 --- a/include/boost/unordered_map.hpp +++ b/include/boost/unordered_map.hpp @@ -122,7 +122,7 @@ namespace boost } #else unordered_map(boost::unordered_detail::move_from > other) - : base(other.base, boost::unordered_detail::move_tag()) + : base(other.source.base, boost::unordered_detail::move_tag()) { } @@ -507,7 +507,7 @@ namespace boost } #else unordered_multimap(boost::unordered_detail::move_from > other) - : base(other.base, boost::unordered_detail::move_tag()) + : base(other.source.base, boost::unordered_detail::move_tag()) { } diff --git a/include/boost/unordered_set.hpp b/include/boost/unordered_set.hpp index 5acdf55b..61922f85 100644 --- a/include/boost/unordered_set.hpp +++ b/include/boost/unordered_set.hpp @@ -119,7 +119,7 @@ namespace boost } #else unordered_set(boost::unordered_detail::move_from > other) - : base(other.base, boost::unordered_detail::move_tag()) + : base(other.source.base, boost::unordered_detail::move_tag()) { } @@ -476,7 +476,7 @@ namespace boost } #else unordered_multiset(boost::unordered_detail::move_from > other) - : base(other.base, boost::unordered_detail::move_tag()) + : base(other.source.base, boost::unordered_detail::move_tag()) { } diff --git a/test/unordered/compile_map.cpp b/test/unordered/compile_map.cpp index 9e12d4c4..0e870fc6 100644 --- a/test/unordered/compile_map.cpp +++ b/test/unordered/compile_map.cpp @@ -13,6 +13,21 @@ #include "../objects/minimal.hpp" #include "./compile_tests.hpp" +// Explicit instantiation to catch compile-time errors + +template class boost::unordered_map< + test::minimal::assignable, + test::minimal::default_copy_constructible, + test::minimal::hash, + test::minimal::equal_to, + test::minimal::allocator >; +template class boost::unordered_multimap< + test::minimal::assignable, + test::minimal::copy_constructible, + test::minimal::hash, + test::minimal::equal_to, + test::minimal::allocator >; + UNORDERED_AUTO_TEST(test0) { typedef std::pair, + test::minimal::equal_to, + test::minimal::allocator >; +template class boost::unordered_multiset< + test::minimal::assignable, + test::minimal::hash, + test::minimal::equal_to, + test::minimal::allocator >; + UNORDERED_AUTO_TEST(test0) { test::minimal::assignable assignable = test::minimal::assignable::create(); From 4f27a146ef65271fb50cb19d3b0f64277f3709a9 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 23 Jun 2008 17:44:53 +0000 Subject: [PATCH 003/100] Merge from trunk. Fix some inspect errors, try to avoid instantiating the equality operators when not required, and some bookkeeping. ................ r42539 | danieljames | 2008-01-06 17:48:11 +0000 (Sun, 06 Jan 2008) | 2 lines Add the unordered library to the maintainers list. ................ r46579 | danieljames | 2008-06-21 16:32:11 +0100 (Sat, 21 Jun 2008) | 10 lines Define unordered containers' friend functions outside of the class. On some compilers, friend functions are being instantiated when the main class is explicitly instantiated. This is slightly problematic because the equality functions (which are an extension) put extra requirements on the types used. So I'm going to try defining the functions outside of the class, in the hope that they won't get instantiated. If someone wants non-member functions to be instantiated, I think it's reasonable to expect them to explicitly instantiate them, especially as compilers don't seem to be consistent about this. ................ r46587 | danieljames | 2008-06-21 20:58:39 +0100 (Sat, 21 Jun 2008) | 8 lines Get the test to pass when pair's default constructor creates two instances of the member classes. With some standard libraries I was getting two copies of the object after creating a default pair, probably because it was creating an instance for its default parameter. So only test after creating the pair object - since it isn't our concern how many instances that creates. ................ r46588 | danieljames | 2008-06-21 21:11:26 +0100 (Sat, 21 Jun 2008) | 1 line Markup an expected failure for unordered. ................ r46594 | danieljames | 2008-06-21 23:02:15 +0100 (Sat, 21 Jun 2008) | 19 lines Merge inspect fixes for the unordered library. Merged revisions 46470-46592 via svnmerge from https://svn.boost.org/svn/boost/branches/unordered/trunk ................ r46589 | danieljames | 2008-06-21 21:37:42 +0100 (Sat, 21 Jun 2008) | 2 lines Fix some inspect errors (tabs and missing copyright/license). ................ r46591 | danieljames | 2008-06-21 21:47:51 +0100 (Sat, 21 Jun 2008) | 1 line Move memory.hpp into the helpers subdirectory. ................ r46592 | danieljames | 2008-06-21 22:08:53 +0100 (Sat, 21 Jun 2008) | 1 line Prevent inspect errors for unnamed namespaces in some of the test header files. ................ ................ r46607 | danieljames | 2008-06-22 14:54:45 +0100 (Sun, 22 Jun 2008) | 9 lines Extract the hash and equality functions from hash_table_data_*. As these are extensions and add extra requirements to the container elements, they shouldn't be part of hash_table_data_* so that they won't get instantiated if an unordered container is explicitly instantiated. Merged revisions 46594-46604 via svnmerge from https://svn.boost.org/svn/boost/branches/unordered/trunk ................ r46608 | danieljames | 2008-06-22 16:00:02 +0100 (Sun, 22 Jun 2008) | 5 lines Remove the svnmerge integration information for the unordered branch. Now that the unordered library is moving towards release, the main development version is in trunk. New features will be developed on a new branch. ................ [SVN r46629] --- doc/bibliography.xml | 5 + examples/hash_functions/fnv-1.hpp | 7 +- .../unordered/detail/hash_table_impl.hpp | 237 +++++++++++------- include/boost/unordered_map.hpp | 116 ++++++--- include/boost/unordered_set.hpp | 114 ++++++--- test/helpers/count.hpp | 5 + test/helpers/equivalent.hpp | 5 + test/{objects => helpers}/memory.hpp | 0 test/objects/exception.hpp | 2 +- test/objects/test.hpp | 7 +- test/unordered/equality_tests.cpp | 180 ++++++------- test/unordered/unnecessary_copy_tests.cpp | 5 +- 12 files changed, 422 insertions(+), 261 deletions(-) rename test/{objects => helpers}/memory.hpp (100%) diff --git a/doc/bibliography.xml b/doc/bibliography.xml index 9a874073..1f2f077e 100644 --- a/doc/bibliography.xml +++ b/doc/bibliography.xml @@ -1,3 +1,8 @@ +
Bibliography diff --git a/examples/hash_functions/fnv-1.hpp b/examples/hash_functions/fnv-1.hpp index 3c9ce63b..9caf1687 100644 --- a/examples/hash_functions/fnv-1.hpp +++ b/examples/hash_functions/fnv-1.hpp @@ -1,4 +1,9 @@ -// See: http://www.isthe.com/chongo/tech/comp/fnv/ + +// Copyright 2008 Daniel James. +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Algorithm from: http://www.isthe.com/chongo/tech/comp/fnv/ #include diff --git a/include/boost/unordered/detail/hash_table_impl.hpp b/include/boost/unordered/detail/hash_table_impl.hpp index 530f5025..fc8443ee 100644 --- a/include/boost/unordered/detail/hash_table_impl.hpp +++ b/include/boost/unordered/detail/hash_table_impl.hpp @@ -1493,8 +1493,6 @@ namespace boost { / static_cast(data_.bucket_manager_.bucket_count()); } - private: - // key extractors // no throw @@ -2127,100 +2125,6 @@ namespace boost { } } - // - // equals - // - -private: -#if BOOST_UNORDERED_EQUIVALENT_KEYS - static inline bool group_equals(link_ptr it1, link_ptr it2, - type_wrapper*) - { - return data::group_count(it1) == data::group_count(it2); - } - - static inline bool group_equals(link_ptr it1, link_ptr it2, void*) - { - link_ptr end1 = data::next_group(it1); - link_ptr end2 = data::next_group(it2); - do { - if(data::get_value(it1).second != data::get_value(it2).second) return false; - it1 = it1->next_; - it2 = it2->next_; - } while(it1 != end1 && it2 != end2); - return it1 == end1 && it2 == end2; - } -#else - static inline bool group_equals(link_ptr, link_ptr, - type_wrapper*) - { - return true; - } - - static inline bool group_equals(link_ptr it1, link_ptr it2, void*) - { - return data::get_value(it1).second == data::get_value(it2).second; - } -#endif - -public: - bool equals(BOOST_UNORDERED_TABLE const& other) const - { - if(size() != other.size()) return false; - - for(bucket_ptr i = data_.cached_begin_bucket_, - j = data_.buckets_end(); i != j; ++i) - { - for(link_ptr it(i->next_); BOOST_UNORDERED_BORLAND_BOOL(it); it = data::next_group(it)) - { - link_ptr other_pos = other.find_iterator(other.extract_key(data::get_value(it))); - if(!BOOST_UNORDERED_BORLAND_BOOL(other_pos) || - !group_equals(it, other_pos, (type_wrapper*)0)) - return false; - } - } - - return true; - } - - inline std::size_t group_hash(link_ptr it, type_wrapper*) const - { - std::size_t seed = data::group_count(it); - std::size_t hashed_key = hash_function()(data::get_value(it)); - boost::hash_combine(seed, hashed_key); - return seed; - } - - inline std::size_t group_hash(link_ptr it, void*) const - { - std::size_t seed = hash_function()(data::get_value(it).first); - - link_ptr end = data::next_group(it); - - do { - boost::hash_combine(seed, data::get_value(it).second); - it = it->next_; - } while(it != end); - - return seed; - } - - std::size_t hash_value() const - { - std::size_t seed = 0; - - for(bucket_ptr i = data_.cached_begin_bucket_, - j = data_.buckets_end(); i != j; ++i) - { - for(link_ptr it(i->next_); BOOST_UNORDERED_BORLAND_BOOL(it); it = data::next_group(it)) - seed ^= group_hash(it, (type_wrapper*)0); - } - - return seed; - } - - private: - // strong exception safety, no side effects bool equal(key_type const& k, value_type const& v) const { @@ -2255,6 +2159,147 @@ public: } }; + // + // Equals - unordered container equality comparison. + // + +#if BOOST_UNORDERED_EQUIVALENT_KEYS + template + inline bool group_equals( + BOOST_UNORDERED_TABLE_DATA*, + typename BOOST_UNORDERED_TABLE_DATA::link_ptr it1, + typename BOOST_UNORDERED_TABLE_DATA::link_ptr it2, + KeyType*, + type_wrapper*) + { + typedef BOOST_UNORDERED_TABLE_DATA data; + return data::group_count(it1) == data::group_count(it2); + } + + template + inline bool group_equals( + BOOST_UNORDERED_TABLE_DATA*, + typename BOOST_UNORDERED_TABLE_DATA::link_ptr it1, + typename BOOST_UNORDERED_TABLE_DATA::link_ptr it2, + KeyType*, + void*) + { + typedef BOOST_UNORDERED_TABLE_DATA data; + typename BOOST_UNORDERED_TABLE_DATA::link_ptr end1 = data::next_group(it1); + typename BOOST_UNORDERED_TABLE_DATA::link_ptr end2 = data::next_group(it2); + + do { + if(data::get_value(it1).second != data::get_value(it2).second) return false; + it1 = it1->next_; + it2 = it2->next_; + } while(it1 != end1 && it2 != end2); + return it1 == end1 && it2 == end2; + } +#else + template + inline bool group_equals( + BOOST_UNORDERED_TABLE_DATA*, + typename BOOST_UNORDERED_TABLE_DATA::link_ptr, + typename BOOST_UNORDERED_TABLE_DATA::link_ptr, + KeyType*, + type_wrapper*) + { + return true; + } + + template + inline bool group_equals( + BOOST_UNORDERED_TABLE_DATA*, + typename BOOST_UNORDERED_TABLE_DATA::link_ptr it1, + typename BOOST_UNORDERED_TABLE_DATA::link_ptr it2, + KeyType*, + void*) + { + typedef BOOST_UNORDERED_TABLE_DATA data; + return data::get_value(it1).second == data::get_value(it2).second; + } +#endif + + template + bool equals(BOOST_UNORDERED_TABLE const& t1, + BOOST_UNORDERED_TABLE const& t2) + { + typedef BOOST_UNORDERED_TABLE_DATA data; + typedef typename data::bucket_ptr bucket_ptr; + typedef typename data::link_ptr link_ptr; + + if(t1.size() != t2.size()) return false; + + for(bucket_ptr i = t1.data_.cached_begin_bucket_, + j = t1.data_.buckets_end(); i != j; ++i) + { + for(link_ptr it(i->next_); BOOST_UNORDERED_BORLAND_BOOL(it); it = data::next_group(it)) + { + link_ptr other_pos = t2.find_iterator(t2.extract_key(data::get_value(it))); + if(!BOOST_UNORDERED_BORLAND_BOOL(other_pos) || + !group_equals((data*)0, it, other_pos, (K*)0, (type_wrapper*)0)) + return false; + } + } + + return true; + } + + // + // hash_value - unordered container hash function. + // + + template + std::size_t group_hash(BOOST_UNORDERED_TABLE const& t, + typename BOOST_UNORDERED_TABLE_DATA::link_ptr it, + type_wrapper*) + { + typedef BOOST_UNORDERED_TABLE_DATA data; + std::size_t seed = data::group_count(it); + std::size_t hashed_key = t.hash_function()(data::get_value(it)); + boost::hash_combine(seed, hashed_key); + return seed; + } + + template + std::size_t group_hash(BOOST_UNORDERED_TABLE const& t, + typename BOOST_UNORDERED_TABLE_DATA::link_ptr it, + void*) + { + typedef BOOST_UNORDERED_TABLE_DATA data; + typedef typename data::link_ptr link_ptr; + + std::size_t seed = t.hash_function()(data::get_value(it).first); + + link_ptr end = data::next_group(it); + + do { + boost::hash_combine(seed, data::get_value(it).second); + it = it->next_; + } while(it != end); + + return seed; + } + + template + std::size_t hash_value(BOOST_UNORDERED_TABLE const& t) + { + typedef BOOST_UNORDERED_TABLE_DATA data; + typedef typename data::link_ptr link_ptr; + typedef typename data::bucket_ptr bucket_ptr; + + std::size_t seed = 0; + + for(bucket_ptr i = t.data_.cached_begin_bucket_, + j = t.data_.buckets_end(); i != j; ++i) + { + for(link_ptr it(i->next_); BOOST_UNORDERED_BORLAND_BOOL(it); it = data::next_group(it)) + seed ^= group_hash(t, it, (type_wrapper*)0); + } + + return seed; + } + // Iterators template class BOOST_UNORDERED_ITERATOR; diff --git a/include/boost/unordered_map.hpp b/include/boost/unordered_map.hpp index bd6cfb2f..cf6562b3 100644 --- a/include/boost/unordered_map.hpp +++ b/include/boost/unordered_map.hpp @@ -32,6 +32,38 @@ namespace boost class Hash = hash, class Pred = std::equal_to, class Alloc = std::allocator > > + class unordered_map; + template + bool operator==(unordered_map const&, + unordered_map const&); + template + bool operator!=(unordered_map const&, + unordered_map const&); + template + std::size_t hash_value(unordered_map const&); + template + void swap(unordered_map&, + unordered_map&); + + template , + class Pred = std::equal_to, + class Alloc = std::allocator > > + class unordered_multimap; + template + bool operator==(unordered_multimap const&, + unordered_multimap const&); + template + bool operator!=(unordered_multimap const&, + unordered_multimap const&); + template + std::size_t hash_value(unordered_multimap const&); + template + void swap(unordered_multimap&, + unordered_multimap&); + + template class unordered_map { typedef boost::unordered_detail::hash_types_unique_keys< @@ -390,34 +422,39 @@ namespace boost base.rehash(n); } - friend bool operator==(unordered_map const& m1, unordered_map const& m2) - { - return m1.base.equals(m2.base); - } - - friend bool operator!=(unordered_map const& m1, unordered_map const& m2) - { - return !m1.base.equals(m2.base); - } - - friend std::size_t hash_value(unordered_map const& m) - { - return m.base.hash_value(); - } + friend bool operator==<>(unordered_map const&, unordered_map const&); + friend bool operator!=<>(unordered_map const&, unordered_map const&); + friend std::size_t hash_value<>(unordered_map const&); }; // class template unordered_map template - void swap(unordered_map &m1, + inline bool operator==(unordered_map const& m1, + unordered_map const& m2) + { + return boost::unordered_detail::equals(m1.base, m2.base); + } + + template + inline bool operator!=(unordered_map const& m1, + unordered_map const& m2) + { + return !boost::unordered_detail::equals(m1.base, m2.base); + } + + template + inline std::size_t hash_value(unordered_map const& m) + { + return boost::unordered_detail::hash_value(m.base); + } + + template + inline void swap(unordered_map &m1, unordered_map &m2) { m1.swap(m2); } - template , - class Pred = std::equal_to, - class Alloc = std::allocator > > + template class unordered_multimap { typedef boost::unordered_detail::hash_types_equivalent_keys< @@ -759,24 +796,33 @@ namespace boost base.rehash(n); } - friend bool operator==(unordered_multimap const& m1, unordered_multimap const& m2) - { - return m1.base.equals(m2.base); - } - - friend bool operator!=(unordered_multimap const& m1, unordered_multimap const& m2) - { - return !m1.base.equals(m2.base); - } - - friend std::size_t hash_value(unordered_multimap const& m) - { - return m.base.hash_value(); - } + friend bool operator==<>(unordered_multimap const&, unordered_multimap const&); + friend bool operator!=<>(unordered_multimap const&, unordered_multimap const&); + friend std::size_t hash_value<>(unordered_multimap const&); }; // class template unordered_multimap template - void swap(unordered_multimap &m1, + inline bool operator==(unordered_multimap const& m1, + unordered_multimap const& m2) + { + return boost::unordered_detail::equals(m1.base, m2.base); + } + + template + inline bool operator!=(unordered_multimap const& m1, + unordered_multimap const& m2) + { + return !boost::unordered_detail::equals(m1.base, m2.base); + } + + template + inline std::size_t hash_value(unordered_multimap const& m) + { + return boost::unordered_detail::hash_value(m.base); + } + + template + inline void swap(unordered_multimap &m1, unordered_multimap &m2) { m1.swap(m2); diff --git a/include/boost/unordered_set.hpp b/include/boost/unordered_set.hpp index 61922f85..f68502e3 100644 --- a/include/boost/unordered_set.hpp +++ b/include/boost/unordered_set.hpp @@ -31,6 +31,37 @@ namespace boost class Hash = hash, class Pred = std::equal_to, class Alloc = std::allocator > + class unordered_set; + template + bool operator==(unordered_set const&, + unordered_set const&); + template + bool operator!=(unordered_set const&, + unordered_set const&); + template + std::size_t hash_value(unordered_set const& m); + template + void swap(unordered_set &m1, + unordered_set &m2); + + template , + class Pred = std::equal_to, + class Alloc = std::allocator > + class unordered_multiset; + template + bool operator==(unordered_multiset const&, + unordered_multiset const&); + template + bool operator!=(unordered_multiset const&, + unordered_multiset const&); + template + std::size_t hash_value(unordered_multiset const& m); + template + void swap(unordered_multiset &m1, + unordered_multiset &m2); + + template class unordered_set { typedef boost::unordered_detail::hash_types_unique_keys< @@ -361,33 +392,39 @@ namespace boost base.rehash(n); } - friend bool operator==(unordered_set const& m1, unordered_set const& m2) - { - return m1.base.equals(m2.base); - } - - friend bool operator!=(unordered_set const& m1, unordered_set const& m2) - { - return !m1.base.equals(m2.base); - } - - friend std::size_t hash_value(unordered_set const& m) - { - return m.base.hash_value(); - } + friend bool operator==<>(unordered_set const&, unordered_set const&); + friend bool operator!=<>(unordered_set const&, unordered_set const&); + friend std::size_t hash_value<>(unordered_set const&); }; // class template unordered_set template - void swap(unordered_set &m1, + inline bool operator==(unordered_set const& m1, + unordered_set const& m2) + { + return boost::unordered_detail::equals(m1.base, m2.base); + } + + template + inline bool operator!=(unordered_set const& m1, + unordered_set const& m2) + { + return !boost::unordered_detail::equals(m1.base, m2.base); + } + + template + inline std::size_t hash_value(unordered_set const& m) + { + return boost::unordered_detail::hash_value(m.base); + } + + template + inline void swap(unordered_set &m1, unordered_set &m2) { m1.swap(m2); } - template , - class Pred = std::equal_to, - class Alloc = std::allocator > + template class unordered_multiset { typedef boost::unordered_detail::hash_types_equivalent_keys< @@ -715,24 +752,33 @@ namespace boost base.rehash(n); } - friend bool operator==(unordered_multiset const& m1, unordered_multiset const& m2) - { - return m1.base.equals(m2.base); - } - - friend bool operator!=(unordered_multiset const& m1, unordered_multiset const& m2) - { - return !m1.base.equals(m2.base); - } - - friend std::size_t hash_value(unordered_multiset const& m) - { - return m.base.hash_value(); - } + friend bool operator==<>(unordered_multiset const&, unordered_multiset const&); + friend bool operator!=<>(unordered_multiset const&, unordered_multiset const&); + friend std::size_t hash_value<>(unordered_multiset const&); }; // class template unordered_multiset template - void swap(unordered_multiset &m1, + inline bool operator==(unordered_multiset const& m1, + unordered_multiset const& m2) + { + return boost::unordered_detail::equals(m1.base, m2.base); + } + + template + inline bool operator!=(unordered_multiset const& m1, + unordered_multiset const& m2) + { + return !boost::unordered_detail::equals(m1.base, m2.base); + } + + template + inline std::size_t hash_value(unordered_multiset const& m) + { + return boost::unordered_detail::hash_value(m.base); + } + + template + inline void swap(unordered_multiset &m1, unordered_multiset &m2) { m1.swap(m2); diff --git a/test/helpers/count.hpp b/test/helpers/count.hpp index 6e3478da..15bff3b0 100644 --- a/test/helpers/count.hpp +++ b/test/helpers/count.hpp @@ -53,6 +53,11 @@ namespace test { struct globally_counted_object : counted_object {}; + // This won't be a problem as I'm only using a single compile unit + // in each test (this is actually require by the minimal test + // framework). + // + // boostinspect:nounnamed namespace { object_count& global_object_count = globally_counted_object::count_; } diff --git a/test/helpers/equivalent.hpp b/test/helpers/equivalent.hpp index ec605fc2..dedadc77 100644 --- a/test/helpers/equivalent.hpp +++ b/test/helpers/equivalent.hpp @@ -44,6 +44,11 @@ namespace test } }; + // This won't be a problem as I'm only using a single compile unit + // in each test (this is actually require by the minimal test + // framework). + // + // boostinspect:nounnamed namespace { equivalent_type equivalent; } diff --git a/test/objects/memory.hpp b/test/helpers/memory.hpp similarity index 100% rename from test/objects/memory.hpp rename to test/helpers/memory.hpp diff --git a/test/objects/exception.hpp b/test/objects/exception.hpp index 9e10c4e4..c75880d3 100644 --- a/test/objects/exception.hpp +++ b/test/objects/exception.hpp @@ -14,7 +14,7 @@ #include #include "../helpers/fwd.hpp" #include "../helpers/allocator.hpp" -#include "./memory.hpp" +#include "../helpers/memory.hpp" namespace test { diff --git a/test/objects/test.hpp b/test/objects/test.hpp index fd1b6ddf..04bdd4bb 100644 --- a/test/objects/test.hpp +++ b/test/objects/test.hpp @@ -12,7 +12,7 @@ #include #include "../helpers/fwd.hpp" #include "../helpers/count.hpp" -#include "./memory.hpp" +#include "../helpers/memory.hpp" #include namespace test @@ -156,6 +156,11 @@ namespace test namespace detail { + // This won't be a problem as I'm only using a single compile unit + // in each test (this is actually require by the minimal test + // framework). + // + // boostinspect:nounnamed namespace { test::detail::memory_tracker > tracker; } diff --git a/test/unordered/equality_tests.cpp b/test/unordered/equality_tests.cpp index c1738a27..ff0e6b57 100644 --- a/test/unordered/equality_tests.cpp +++ b/test/unordered/equality_tests.cpp @@ -25,118 +25,118 @@ namespace equality_tests }; #define UNORDERED_EQUALITY_SET_TEST(seq1, op, seq2) \ - do { \ - boost::unordered_set set1, set2; \ - BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \ - BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \ - BOOST_CHECK(set1 op set2); \ - } while(false) + do { \ + boost::unordered_set set1, set2; \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \ + BOOST_CHECK(set1 op set2); \ + } while(false) #define UNORDERED_EQUALITY_MULTISET_TEST(seq1, op, seq2) \ - do { \ - boost::unordered_multiset set1, set2; \ - BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \ - BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \ - BOOST_CHECK(set1 op set2); \ - } while(false) + do { \ + boost::unordered_multiset set1, set2; \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \ + BOOST_CHECK(set1 op set2); \ + } while(false) #define UNORDERED_EQUALITY_MAP_TEST(seq1, op, seq2) \ - do { \ - boost::unordered_map map1, map2; \ - BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \ - BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \ - BOOST_CHECK(map1 op map2); \ - } while(false) + do { \ + boost::unordered_map map1, map2; \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \ + BOOST_CHECK(map1 op map2); \ + } while(false) #define UNORDERED_EQUALITY_MULTIMAP_TEST(seq1, op, seq2) \ - do { \ - boost::unordered_multimap map1, map2; \ - BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \ - BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \ - BOOST_CHECK(map1 op map2); \ - } while(false) + do { \ + boost::unordered_multimap map1, map2; \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \ + BOOST_CHECK(map1 op map2); \ + } while(false) #define UNORDERED_SET_INSERT(r, set, item) set.insert(item); #define UNORDERED_MAP_INSERT(r, map, item) \ - map.insert(std::pair BOOST_PP_SEQ_TO_TUPLE(item)); + map.insert(std::pair BOOST_PP_SEQ_TO_TUPLE(item)); - UNORDERED_AUTO_TEST(equality_size_tests) - { - boost::unordered_set x1, x2; - BOOST_CHECK(x1 == x2); - BOOST_CHECK(!(x1 != x2)); + UNORDERED_AUTO_TEST(equality_size_tests) + { + boost::unordered_set x1, x2; + BOOST_CHECK(x1 == x2); + BOOST_CHECK(!(x1 != x2)); - x1.insert(1); - BOOST_CHECK(x1 != x2); - BOOST_CHECK(!(x1 == x2)); - BOOST_CHECK(x2 != x1); - BOOST_CHECK(!(x2 == x1)); - - x2.insert(1); - BOOST_CHECK(x1 == x2); - BOOST_CHECK(!(x1 != x2)); - - x2.insert(2); - BOOST_CHECK(x1 != x2); - BOOST_CHECK(!(x1 == x2)); - BOOST_CHECK(x2 != x1); - BOOST_CHECK(!(x2 == x1)); - } - - UNORDERED_AUTO_TEST(equality_key_value_tests) - { - UNORDERED_EQUALITY_MULTISET_TEST((1), !=, (2)); - UNORDERED_EQUALITY_SET_TEST((2), ==, (2)); - UNORDERED_EQUALITY_MAP_TEST(((1)(1))((2)(1)), !=, ((1)(1))((3)(1))); - } - + x1.insert(1); + BOOST_CHECK(x1 != x2); + BOOST_CHECK(!(x1 == x2)); + BOOST_CHECK(x2 != x1); + BOOST_CHECK(!(x2 == x1)); + + x2.insert(1); + BOOST_CHECK(x1 == x2); + BOOST_CHECK(!(x1 != x2)); + + x2.insert(2); + BOOST_CHECK(x1 != x2); + BOOST_CHECK(!(x1 == x2)); + BOOST_CHECK(x2 != x1); + BOOST_CHECK(!(x2 == x1)); + } + + UNORDERED_AUTO_TEST(equality_key_value_tests) + { + UNORDERED_EQUALITY_MULTISET_TEST((1), !=, (2)); + UNORDERED_EQUALITY_SET_TEST((2), ==, (2)); + UNORDERED_EQUALITY_MAP_TEST(((1)(1))((2)(1)), !=, ((1)(1))((3)(1))); + } + UNORDERED_AUTO_TEST(equality_collision_test) { - UNORDERED_EQUALITY_MULTISET_TEST( - (1), !=, (501)); - UNORDERED_EQUALITY_MULTISET_TEST( - (1)(251), !=, (1)(501)); - UNORDERED_EQUALITY_MULTIMAP_TEST( - ((251)(1))((1)(1)), !=, ((501)(1))((1)(1))); - UNORDERED_EQUALITY_MULTISET_TEST( - (1)(501), ==, (1)(501)); - UNORDERED_EQUALITY_SET_TEST( - (1)(501), ==, (501)(1)); + UNORDERED_EQUALITY_MULTISET_TEST( + (1), !=, (501)); + UNORDERED_EQUALITY_MULTISET_TEST( + (1)(251), !=, (1)(501)); + UNORDERED_EQUALITY_MULTIMAP_TEST( + ((251)(1))((1)(1)), !=, ((501)(1))((1)(1))); + UNORDERED_EQUALITY_MULTISET_TEST( + (1)(501), ==, (1)(501)); + UNORDERED_EQUALITY_SET_TEST( + (1)(501), ==, (501)(1)); } - UNORDERED_AUTO_TEST(equality_group_size_test) - { - UNORDERED_EQUALITY_MULTISET_TEST( - (10)(20)(20), !=, (10)(10)(20)); - UNORDERED_EQUALITY_MULTIMAP_TEST( - ((10)(1))((20)(1))((20)(1)), !=, - ((10)(1))((20)(1))((10)(1))); - UNORDERED_EQUALITY_MULTIMAP_TEST( - ((20)(1))((10)(1))((10)(1)), ==, - ((10)(1))((20)(1))((10)(1))); + UNORDERED_AUTO_TEST(equality_group_size_test) + { + UNORDERED_EQUALITY_MULTISET_TEST( + (10)(20)(20), !=, (10)(10)(20)); + UNORDERED_EQUALITY_MULTIMAP_TEST( + ((10)(1))((20)(1))((20)(1)), !=, + ((10)(1))((20)(1))((10)(1))); + UNORDERED_EQUALITY_MULTIMAP_TEST( + ((20)(1))((10)(1))((10)(1)), ==, + ((10)(1))((20)(1))((10)(1))); } UNORDERED_AUTO_TEST(equality_map_value_test) { - UNORDERED_EQUALITY_MAP_TEST( - ((1)(1)), !=, ((1)(2))); - UNORDERED_EQUALITY_MAP_TEST( - ((1)(1)), ==, ((1)(1))); - UNORDERED_EQUALITY_MULTIMAP_TEST( - ((1)(1)), !=, ((1)(2))); - UNORDERED_EQUALITY_MULTIMAP_TEST( - ((1)(1))((1)(1)), !=, ((1)(1))((1)(2))); - UNORDERED_EQUALITY_MULTIMAP_TEST( - ((1)(2))((1)(1)), !=, ((1)(1))((1)(2))); - } + UNORDERED_EQUALITY_MAP_TEST( + ((1)(1)), !=, ((1)(2))); + UNORDERED_EQUALITY_MAP_TEST( + ((1)(1)), ==, ((1)(1))); + UNORDERED_EQUALITY_MULTIMAP_TEST( + ((1)(1)), !=, ((1)(2))); + UNORDERED_EQUALITY_MULTIMAP_TEST( + ((1)(1))((1)(1)), !=, ((1)(1))((1)(2))); + UNORDERED_EQUALITY_MULTIMAP_TEST( + ((1)(2))((1)(1)), !=, ((1)(1))((1)(2))); + } UNORDERED_AUTO_TEST(equality_predicate_test) { - UNORDERED_EQUALITY_SET_TEST( - (1), ==, (1001)); - UNORDERED_EQUALITY_MAP_TEST( - ((1)(2))((1001)(1)), ==, ((1001)(2))((1)(1))); - } + UNORDERED_EQUALITY_SET_TEST( + (1), ==, (1001)); + UNORDERED_EQUALITY_MAP_TEST( + ((1)(2))((1001)(1)), ==, ((1001)(2))((1)(1))); + } } diff --git a/test/unordered/unnecessary_copy_tests.cpp b/test/unordered/unnecessary_copy_tests.cpp index 87e6d158..18d36525 100644 --- a/test/unordered/unnecessary_copy_tests.cpp +++ b/test/unordered/unnecessary_copy_tests.cpp @@ -84,12 +84,11 @@ namespace unnecessary_copy_tests template void unnecessary_copy_insert_test(T*) { - reset(); T x; BOOST_DEDUCED_TYPENAME T::value_type a; - COPY_COUNT(1); + reset(); x.insert(a); - COPY_COUNT(2); + COPY_COUNT(1); } boost::unordered_set* set; From 56b9e0da1a393dc5de7109a051d8091b849fcf3e Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 4 Jul 2008 17:04:47 +0000 Subject: [PATCH 004/100] Merge some small fixes from trunk. Merged revisions 46740,46742,47002,47040 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r46740 | danieljames | 2008-06-26 20:20:56 +0100 (Thu, 26 Jun 2008) | 1 line Fix a character encoding error. ........ r46742 | danieljames | 2008-06-26 20:25:38 +0100 (Thu, 26 Jun 2008) | 6 lines Give the asio documentation its own target. The asio documentation is built with the rest of the combined documentation but is really separate. So give it its own target so that separate parts can be built separately. ........ r47040 | danieljames | 2008-07-03 15:34:56 +0100 (Thu, 03 Jul 2008) | 1 line Workaround for some template syntax not supported in old versions of Visual C++ 6.5 ........ [SVN r47078] --- include/boost/unordered_map.hpp | 12 ++++++++++++ include/boost/unordered_set.hpp | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/include/boost/unordered_map.hpp b/include/boost/unordered_map.hpp index cf6562b3..093c7697 100644 --- a/include/boost/unordered_map.hpp +++ b/include/boost/unordered_map.hpp @@ -422,9 +422,15 @@ namespace boost base.rehash(n); } +#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) + friend bool operator==(unordered_map const&, unordered_map const&); + friend bool operator!=(unordered_map const&, unordered_map const&); + friend std::size_t hash_value(unordered_map const&); +#else friend bool operator==<>(unordered_map const&, unordered_map const&); friend bool operator!=<>(unordered_map const&, unordered_map const&); friend std::size_t hash_value<>(unordered_map const&); +#endif }; // class template unordered_map template @@ -796,9 +802,15 @@ namespace boost base.rehash(n); } +#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) + friend bool operator==(unordered_multimap const&, unordered_multimap const&); + friend bool operator!=(unordered_multimap const&, unordered_multimap const&); + friend std::size_t hash_value(unordered_multimap const&); +#else friend bool operator==<>(unordered_multimap const&, unordered_multimap const&); friend bool operator!=<>(unordered_multimap const&, unordered_multimap const&); friend std::size_t hash_value<>(unordered_multimap const&); +#endif }; // class template unordered_multimap template diff --git a/include/boost/unordered_set.hpp b/include/boost/unordered_set.hpp index f68502e3..1addae10 100644 --- a/include/boost/unordered_set.hpp +++ b/include/boost/unordered_set.hpp @@ -392,9 +392,15 @@ namespace boost base.rehash(n); } +#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) + friend bool operator==(unordered_set const&, unordered_set const&); + friend bool operator!=(unordered_set const&, unordered_set const&); + friend std::size_t hash_value(unordered_set const&); +#else friend bool operator==<>(unordered_set const&, unordered_set const&); friend bool operator!=<>(unordered_set const&, unordered_set const&); friend std::size_t hash_value<>(unordered_set const&); +#endif }; // class template unordered_set template @@ -752,9 +758,15 @@ namespace boost base.rehash(n); } +#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) + friend bool operator==(unordered_multiset const&, unordered_multiset const&); + friend bool operator!=(unordered_multiset const&, unordered_multiset const&); + friend std::size_t hash_value(unordered_multiset const&); +#else friend bool operator==<>(unordered_multiset const&, unordered_multiset const&); friend bool operator!=<>(unordered_multiset const&, unordered_multiset const&); friend std::size_t hash_value<>(unordered_multiset const&); +#endif }; // class template unordered_multiset template From 4e4f99d51f29aff0d4fbe162362cce54dd6f1529 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 6 Jul 2008 22:00:18 +0000 Subject: [PATCH 005/100] Make the unordered constructors from allocators explicit. And clean of the FNV-1 example & documentation a little. Merged revisions 47085,47132,47143-47146 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r47085 | danieljames | 2008-07-04 23:57:20 +0100 (Fri, 04 Jul 2008) | 4 lines Require explicit conversion from allocators. (Not what it says in the draft standard, but I think that might be a defect). ........ r47132 | danieljames | 2008-07-06 13:41:09 +0100 (Sun, 06 Jul 2008) | 2 lines 'Bias' should be 'basis'. ........ r47143 | danieljames | 2008-07-06 22:06:52 +0100 (Sun, 06 Jul 2008) | 1 line Clean up the FNV-1 comments. ........ r47144 | danieljames | 2008-07-06 22:07:31 +0100 (Sun, 06 Jul 2008) | 1 line I've only got one hash function for release, so no need for its own directory. ........ r47145 | danieljames | 2008-07-06 22:08:11 +0100 (Sun, 06 Jul 2008) | 1 line Remove the hash_functions directory (for now). ........ r47146 | danieljames | 2008-07-06 22:29:47 +0100 (Sun, 06 Jul 2008) | 1 line Update the docs for the new location of FNV-1. ........ [SVN r47150] --- doc/hash_equality.qbk | 4 +- doc/ref.xml | 10 ++--- doc/src_code/dictionary.cpp | 2 +- examples/fnv1.hpp | 66 ++++++++++++++++++++++++++++ examples/hash_functions/fnv-1.hpp | 71 ------------------------------- include/boost/unordered_map.hpp | 5 +-- include/boost/unordered_set.hpp | 6 +-- 7 files changed, 78 insertions(+), 86 deletions(-) create mode 100644 examples/fnv1.hpp delete mode 100644 examples/hash_functions/fnv-1.hpp diff --git a/doc/hash_equality.qbk b/doc/hash_equality.qbk index ca69f61f..7ca4396f 100644 --- a/doc/hash_equality.qbk +++ b/doc/hash_equality.qbk @@ -23,8 +23,8 @@ but not the equality predicate. For example, if you wanted to use the [import src_code/dictionary.cpp] [case_sensitive_dictionary_fnv] -An example implementation of FNV-1, and some other hash functions are supplied -in the examples directory. +There is an [@../../libs/unordered/examples/fnv1.hpp implementation +of FNV-1] in the examples directory. If you wish to use a different equality function, you will also need to use a matching hash function. For diff --git a/doc/ref.xml b/doc/ref.xml index da982b62..008e7c7c 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -181,7 +181,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The copy constructor. Copies the contained elements, hash function, predicate, maximum load factor and allocator. - + Allocator const& @@ -928,7 +928,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The copy constructor. Copies the contained elements, hash function, predicate, maximum load factor and allocator. - + Allocator const& @@ -1685,7 +1685,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The copy constructor. Copies the contained elements, hash function, predicate, maximum load factor and allocator. - + Allocator const& @@ -2483,7 +2483,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The copy constructor. Copies the contained elements, hash function, predicate, maximum load factor and allocator. - + Allocator const& @@ -3062,4 +3062,4 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - \ No newline at end of file + diff --git a/doc/src_code/dictionary.cpp b/doc/src_code/dictionary.cpp index 721952a0..1f8ead92 100644 --- a/doc/src_code/dictionary.cpp +++ b/doc/src_code/dictionary.cpp @@ -6,7 +6,7 @@ #include #include #include -#include "../../examples/hash_functions/fnv-1.hpp" +#include "../../examples/fnv1.hpp" //[case_insensitive_functions struct iequal_to diff --git a/examples/fnv1.hpp b/examples/fnv1.hpp new file mode 100644 index 00000000..60bf8985 --- /dev/null +++ b/examples/fnv1.hpp @@ -0,0 +1,66 @@ + +// Copyright 2008 Daniel James. +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// This code is also released into the public domain. + +// Algorithm from: http://www.isthe.com/chongo/tech/comp/fnv/ + +#include + +namespace hash +{ + template + struct basic_fnv_1 + { + std::size_t operator()(std::string const& text) const + { + std::size_t hash = OffsetBasis; + for(std::string::const_iterator it = text.begin(), end = text.end(); + it != end; ++it) + { + hash *= FnvPrime; + hash ^= *it; + } + + return hash; + } + }; + + template + struct basic_fnv_1a + { + std::size_t operator()(std::string const& text) const + { + std::size_t hash = OffsetBasis; + for(std::string::const_iterator it = text.begin(), end = text.end(); + it != end; ++it) + { + hash ^= *it; + hash *= FnvPrime; + } + + return hash; + } + }; + + // For 32 bit machines: + const std::size_t fnv_prime = 16777619u; + const std::size_t fnv_offset_basis = 2166136261u; + + // For 64 bit machines: + // const std::size_t fnv_prime = 1099511628211u; + // const std::size_t fnv_offset_basis = 14695981039346656037u; + + // For 128 bit machines: + // const std::size_t fnv_prime = 309485009821345068724781401u; + // const std::size_t fnv_offset_basis = 275519064689413815358837431229664493455u; + + // For 256 bit machines: + // const std::size_t fnv_prime = 374144419156711147060143317175368453031918731002211u; + // const std::size_t fnv_offset_basis = 100029257958052580907070968620625704837092796014241193945225284501741471925557u; + + typedef basic_fnv_1 fnv_1; + typedef basic_fnv_1a fnv_1a; +} diff --git a/examples/hash_functions/fnv-1.hpp b/examples/hash_functions/fnv-1.hpp deleted file mode 100644 index 9caf1687..00000000 --- a/examples/hash_functions/fnv-1.hpp +++ /dev/null @@ -1,71 +0,0 @@ - -// Copyright 2008 Daniel James. -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// Algorithm from: http://www.isthe.com/chongo/tech/comp/fnv/ - -#include - -namespace hash -{ - template - struct basic_fnv_1 - { - std::size_t operator()(std::string const& text) const - { - std::size_t hash = OffsetBias; - for(std::string::const_iterator it = text.begin(), end = text.end(); - it != end; ++it) - { - hash *= FnvPrime; - hash ^= *it; - } - - return hash; - } - }; - - template - struct basic_fnv_1a - { - std::size_t operator()(std::string const& text) const - { - std::size_t hash = OffsetBias; - for(std::string::const_iterator it = text.begin(), end = text.end(); - it != end; ++it) - { - hash ^= *it; - hash *= FnvPrime; - } - - return hash; - } - }; - - // TODO: Select Bias & Prime base on the size of std::size_t. - // - // 32 bit FNV_prime = 16777619 - // 64 bit FNV_prime = 1099511628211 - // 128 bit FNV_prime = 309485009821345068724781401 - // 256 bit FNV_prime = 374144419156711147060143317175368453031918731002211 - // - // 32 bit offset_basis = 2166136261 - // 64 bit offset_basis = 14695981039346656037 - // 128 bit offset_basis = 275519064689413815358837431229664493455 - // 256 bit offset_basis = 100029257958052580907070968620625704837092796014241193945225284501741471925557 - - const std::size_t fnv_prime = 16777619; - // 64 bit FNV_prime = 1099511628211 - // 128 bit FNV_prime = 309485009821345068724781401 - // 256 bit FNV_prime = 374144419156711147060143317175368453031918731002211 - - const std::size_t fnv_offset_bias = 2166136261u; - // 64 bit offset_basis = 14695981039346656037 - // 128 bit offset_basis = 275519064689413815358837431229664493455 - // 256 bit offset_basis = 100029257958052580907070968620625704837092796014241193945225284501741471925557 - - typedef basic_fnv_1 fnv_1; - typedef basic_fnv_1a fnv_1a; - -} diff --git a/include/boost/unordered_map.hpp b/include/boost/unordered_map.hpp index 093c7697..5f711650 100644 --- a/include/boost/unordered_map.hpp +++ b/include/boost/unordered_map.hpp @@ -107,8 +107,7 @@ namespace boost { } - // TODO: Should this be explicit? - unordered_map(allocator_type const& a) + explicit unordered_map(allocator_type const& a) : base(boost::unordered_detail::default_initial_bucket_count, hasher(), key_equal(), a) { @@ -504,7 +503,7 @@ namespace boost { } - unordered_multimap(allocator_type const& a) + explicit unordered_multimap(allocator_type const& a) : base(boost::unordered_detail::default_initial_bucket_count, hasher(), key_equal(), a) { diff --git a/include/boost/unordered_set.hpp b/include/boost/unordered_set.hpp index 1addae10..0f34c0fd 100644 --- a/include/boost/unordered_set.hpp +++ b/include/boost/unordered_set.hpp @@ -104,8 +104,7 @@ namespace boost { } - // TODO: Should this be explicit? - unordered_set(allocator_type const& a) + explicit unordered_set(allocator_type const& a) : base(boost::unordered_detail::default_initial_bucket_count, hasher(), key_equal(), a) { @@ -473,8 +472,7 @@ namespace boost { } - // TODO: Should this be explicit? - unordered_multiset(allocator_type const& a) + explicit unordered_multiset(allocator_type const& a) : base(boost::unordered_detail::default_initial_bucket_count, hasher(), key_equal(), a) { From f20f72bade175b72b41febc2f802b5e1d297a7f1 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 13 Jul 2008 21:08:33 +0000 Subject: [PATCH 006/100] Merge some documentation updates and fixes from trunk. Merged revisions 47364,47402-47403 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r47364 | danieljames | 2008-07-12 20:32:15 +0100 (Sat, 12 Jul 2008) | 1 line Fix a PDF link that I missed before. (in static assert) ........ r47402 | danieljames | 2008-07-13 20:42:56 +0100 (Sun, 13 Jul 2008) | 2 lines Note that emplace is only available on a few compilers. ........ r47403 | danieljames | 2008-07-13 21:07:45 +0100 (Sun, 13 Jul 2008) | 2 lines Update the implementation details. ........ [SVN r47405] --- doc/rationale.qbk | 37 +++++++++++++++---------------------- doc/ref.xml | 8 ++++++++ 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/doc/rationale.qbk b/doc/rationale.qbk index 81ece1ed..908bb5e3 100644 --- a/doc/rationale.qbk +++ b/doc/rationale.qbk @@ -96,6 +96,17 @@ efficiency advantage of power of 2 hash tables. So, this implementation uses a prime number for the hash table size. +[h2 Equality operators and hash functions] + +`operator==` and `operator!=` are not included in the standard, but I've +added them as I think they could be useful and can be efficiently +implemented. They are specified +differently to the standard associative containers, comparing keys +using the equality predicate rather than `operator==`. This is inconsistent +with the other containers but it is probably closer to user's expectations. +I have also added a `hash_value` free function so that the containers can be +hashed by [classref boost::hash]. + [h2 Active Issues and Proposals] [h3 Removing unused allocator functions] @@ -181,32 +192,14 @@ It is not specified if `unordered_multiset` and `unordered_multimap` preserve th of elements with equivalent keys (i.e. if they're stable under `insert` and `erase`). This is [@http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#518 issue 581]. The current proposal is that insert, erase and rehash are stable - so they are here. +(Update: during the release of this version, this requirement was added to +[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2691.pdf +the lastest working draft]). [h3 const_local_iterator cbegin, cend missing from TR1] -[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2482.html#691 +[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2684.html#691 Issue 691] is that `cbegin` and `cend` are missing for local iterators. The current resolution is that they'll be added, so I've added them. -[h2 Future Developments] - -[h3 Support for `emplace`] - -In __n2369__ a new member function, `emplace` was added to the containers to -allow placement insert, as described in __n2345__. To fully implement this -`std::forward` is required, along with new functions in `std::allocator` and -new constructors in `std::pair`. But partial support is possible - especially -if I don't use the `construct` member of allocators. - -[h3 Equality operator] - -While `operator==` and `operator!=` are not included in the standard, it's -possible to implement them for all the containers - this is helped by having -stable order of elements with equivalent keys. They will need to be specified -differently to the standard associative containers, probably comparing keys -using the equality predicate rather than `operator==`. This is inconsistent -with the other containers but it is probably closer to user's expectations. - -If these are added then a `hash_value` free function should also be added. - [endsect] diff --git a/doc/ref.xml b/doc/ref.xml index 008e7c7c..f33aec2a 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -284,6 +284,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. Pointers and references to elements are never invalidated. + Only available on compilers with support for variadic template arguments and rvalue references. @@ -312,6 +313,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 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. Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. Pointers and references to elements are never invalidated. + Only available on compilers with support for variadic template arguments and rvalue references. @@ -1030,6 +1032,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. Pointers and references to elements are never invalidated. + Only available on compilers with support for variadic template arguments and rvalue references. @@ -1058,6 +1061,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 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. Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. Pointers and references to elements are never invalidated. + Only available on compilers with support for variadic template arguments and rvalue references. @@ -1788,6 +1792,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. Pointers and references to elements are never invalidated. + Only available on compilers with support for variadic template arguments and rvalue references. @@ -1816,6 +1821,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 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. Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. Pointers and references to elements are never invalidated. + Only available on compilers with support for variadic template arguments and rvalue references. @@ -2585,6 +2591,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. Pointers and references to elements are never invalidated. + Only available on compilers with support for variadic template arguments and rvalue references. @@ -2613,6 +2620,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 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. Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. Pointers and references to elements are never invalidated. + Only available on compilers with support for variadic template arguments and rvalue references. From 6571648bac3ff65d94bef7e43217ff779c8df6dc Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 17 Jul 2008 23:33:51 +0000 Subject: [PATCH 007/100] Remove hash_value for unordered containers. Merged revisions 47463,47465,47522 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r47463 | danieljames | 2008-07-15 22:26:54 +0100 (Tue, 15 Jul 2008) | 1 line Better hash function for unordered containers. Still a bit rubbish. ........ r47465 | danieljames | 2008-07-15 23:03:15 +0100 (Tue, 15 Jul 2008) | 4 lines On second thoughts, I'll just completely remove hash_value for ordered containers. It's low quality and not very generic (it uses boost::hash for mapped values). Should be a painless change. ........ r47522 | danieljames | 2008-07-18 00:08:32 +0100 (Fri, 18 Jul 2008) | 1 line Remove a mention of the hash functions which I missed before. ........ [SVN r47523] --- doc/changes.qbk | 3 +- doc/rationale.qbk | 2 - doc/ref.xml | 80 ------------------- .../unordered/detail/hash_table_impl.hpp | 55 ------------- include/boost/unordered_map.hpp | 20 ----- include/boost/unordered_set.hpp | 20 ----- test/unordered/compile_tests.hpp | 5 -- 7 files changed, 1 insertion(+), 184 deletions(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index 682e36e6..e29b7a85 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -31,7 +31,6 @@ First official release. * Emplace support when rvalue references and variadic template are available. * More efficient node allocation when rvalue references and variadic template are available. -* Added equality operators and hash functions - ([@http://svn.boost.org/trac/boost/ticket/1557 Ticket 1557]). +* Added equality operators. [endsect] diff --git a/doc/rationale.qbk b/doc/rationale.qbk index 908bb5e3..63ca6441 100644 --- a/doc/rationale.qbk +++ b/doc/rationale.qbk @@ -104,8 +104,6 @@ implemented. They are specified differently to the standard associative containers, comparing keys using the equality predicate rather than `operator==`. This is inconsistent with the other containers but it is probably closer to user's expectations. -I have also added a `hash_value` free function so that the containers can be -hashed by [classref boost::hash]. [h2 Active Issues and Proposals] diff --git a/doc/ref.xml b/doc/ref.xml index f33aec2a..d7dd9259 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -702,25 +702,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) This is a boost extension. - - - - unordered_set<Value, Hash, Pred, Alloc> const& - - std::size_t - - This is a boost extension. - - @@ -1449,25 +1430,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) This is a boost extension. - - - - unordered_multiset<Value, Hash, Pred, Alloc> const& - - std::size_t - - This is a boost extension. - - @@ -2249,27 +2211,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) This is a boost extension. - - - - unordered_map<Key, Mapped, Hash, Pred, Alloc> const& - - std::size_t - - This is a boost extension. - - @@ -3012,27 +2953,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) This is a boost extension. - - - - unordered_multimap<Key, Mapped, Hash, Pred, Alloc> const& - - std::size_t - - This is a boost extension. - - diff --git a/include/boost/unordered/detail/hash_table_impl.hpp b/include/boost/unordered/detail/hash_table_impl.hpp index fc8443ee..e78962fb 100644 --- a/include/boost/unordered/detail/hash_table_impl.hpp +++ b/include/boost/unordered/detail/hash_table_impl.hpp @@ -2245,61 +2245,6 @@ namespace boost { return true; } - // - // hash_value - unordered container hash function. - // - - template - std::size_t group_hash(BOOST_UNORDERED_TABLE const& t, - typename BOOST_UNORDERED_TABLE_DATA::link_ptr it, - type_wrapper*) - { - typedef BOOST_UNORDERED_TABLE_DATA data; - std::size_t seed = data::group_count(it); - std::size_t hashed_key = t.hash_function()(data::get_value(it)); - boost::hash_combine(seed, hashed_key); - return seed; - } - - template - std::size_t group_hash(BOOST_UNORDERED_TABLE const& t, - typename BOOST_UNORDERED_TABLE_DATA::link_ptr it, - void*) - { - typedef BOOST_UNORDERED_TABLE_DATA data; - typedef typename data::link_ptr link_ptr; - - std::size_t seed = t.hash_function()(data::get_value(it).first); - - link_ptr end = data::next_group(it); - - do { - boost::hash_combine(seed, data::get_value(it).second); - it = it->next_; - } while(it != end); - - return seed; - } - - template - std::size_t hash_value(BOOST_UNORDERED_TABLE const& t) - { - typedef BOOST_UNORDERED_TABLE_DATA data; - typedef typename data::link_ptr link_ptr; - typedef typename data::bucket_ptr bucket_ptr; - - std::size_t seed = 0; - - for(bucket_ptr i = t.data_.cached_begin_bucket_, - j = t.data_.buckets_end(); i != j; ++i) - { - for(link_ptr it(i->next_); BOOST_UNORDERED_BORLAND_BOOL(it); it = data::next_group(it)) - seed ^= group_hash(t, it, (type_wrapper*)0); - } - - return seed; - } - // Iterators template class BOOST_UNORDERED_ITERATOR; diff --git a/include/boost/unordered_map.hpp b/include/boost/unordered_map.hpp index 5f711650..484cf42f 100644 --- a/include/boost/unordered_map.hpp +++ b/include/boost/unordered_map.hpp @@ -40,8 +40,6 @@ namespace boost bool operator!=(unordered_map const&, unordered_map const&); template - std::size_t hash_value(unordered_map const&); - template void swap(unordered_map&, unordered_map&); @@ -58,8 +56,6 @@ namespace boost bool operator!=(unordered_multimap const&, unordered_multimap const&); template - std::size_t hash_value(unordered_multimap const&); - template void swap(unordered_multimap&, unordered_multimap&); @@ -424,11 +420,9 @@ namespace boost #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) friend bool operator==(unordered_map const&, unordered_map const&); friend bool operator!=(unordered_map const&, unordered_map const&); - friend std::size_t hash_value(unordered_map const&); #else friend bool operator==<>(unordered_map const&, unordered_map const&); friend bool operator!=<>(unordered_map const&, unordered_map const&); - friend std::size_t hash_value<>(unordered_map const&); #endif }; // class template unordered_map @@ -446,12 +440,6 @@ namespace boost return !boost::unordered_detail::equals(m1.base, m2.base); } - template - inline std::size_t hash_value(unordered_map const& m) - { - return boost::unordered_detail::hash_value(m.base); - } - template inline void swap(unordered_map &m1, unordered_map &m2) @@ -804,11 +792,9 @@ namespace boost #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) friend bool operator==(unordered_multimap const&, unordered_multimap const&); friend bool operator!=(unordered_multimap const&, unordered_multimap const&); - friend std::size_t hash_value(unordered_multimap const&); #else friend bool operator==<>(unordered_multimap const&, unordered_multimap const&); friend bool operator!=<>(unordered_multimap const&, unordered_multimap const&); - friend std::size_t hash_value<>(unordered_multimap const&); #endif }; // class template unordered_multimap @@ -826,12 +812,6 @@ namespace boost return !boost::unordered_detail::equals(m1.base, m2.base); } - template - inline std::size_t hash_value(unordered_multimap const& m) - { - return boost::unordered_detail::hash_value(m.base); - } - template inline void swap(unordered_multimap &m1, unordered_multimap &m2) diff --git a/include/boost/unordered_set.hpp b/include/boost/unordered_set.hpp index 0f34c0fd..5b82f002 100644 --- a/include/boost/unordered_set.hpp +++ b/include/boost/unordered_set.hpp @@ -39,8 +39,6 @@ namespace boost bool operator!=(unordered_set const&, unordered_set const&); template - std::size_t hash_value(unordered_set const& m); - template void swap(unordered_set &m1, unordered_set &m2); @@ -56,8 +54,6 @@ namespace boost bool operator!=(unordered_multiset const&, unordered_multiset const&); template - std::size_t hash_value(unordered_multiset const& m); - template void swap(unordered_multiset &m1, unordered_multiset &m2); @@ -394,11 +390,9 @@ namespace boost #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) friend bool operator==(unordered_set const&, unordered_set const&); friend bool operator!=(unordered_set const&, unordered_set const&); - friend std::size_t hash_value(unordered_set const&); #else friend bool operator==<>(unordered_set const&, unordered_set const&); friend bool operator!=<>(unordered_set const&, unordered_set const&); - friend std::size_t hash_value<>(unordered_set const&); #endif }; // class template unordered_set @@ -416,12 +410,6 @@ namespace boost return !boost::unordered_detail::equals(m1.base, m2.base); } - template - inline std::size_t hash_value(unordered_set const& m) - { - return boost::unordered_detail::hash_value(m.base); - } - template inline void swap(unordered_set &m1, unordered_set &m2) @@ -759,11 +747,9 @@ namespace boost #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) friend bool operator==(unordered_multiset const&, unordered_multiset const&); friend bool operator!=(unordered_multiset const&, unordered_multiset const&); - friend std::size_t hash_value(unordered_multiset const&); #else friend bool operator==<>(unordered_multiset const&, unordered_multiset const&); friend bool operator!=<>(unordered_multiset const&, unordered_multiset const&); - friend std::size_t hash_value<>(unordered_multiset const&); #endif }; // class template unordered_multiset @@ -781,12 +767,6 @@ namespace boost return !boost::unordered_detail::equals(m1.base, m2.base); } - template - inline std::size_t hash_value(unordered_multiset const& m) - { - return boost::unordered_detail::hash_value(m.base); - } - template inline void swap(unordered_multiset &m1, unordered_multiset &m2) diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index 5e65a72d..34265fca 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -168,11 +168,6 @@ void equality_test(X& r) test::check_return_type::equals(a == b); test::check_return_type::equals(a != b); -#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) - test::check_return_type::equals(boost::hash_value(a)); -#else - test::check_return_type::equals(hash_value(a)); -#endif } template From dd2a994874265d9bf5e04c703feea309c81208ed Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 25 Jul 2008 22:47:41 +0000 Subject: [PATCH 008/100] Merge in some small documentation fixes. Merged revisions 47054,47750,47766,47800,47807,47811-47813 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r47750 | danieljames | 2008-07-24 11:14:15 +0100 (Thu, 24 Jul 2008) | 2 lines Remove some old information that's no longer true. ........ r47766 | danieljames | 2008-07-24 19:16:09 +0100 (Thu, 24 Jul 2008) | 1 line Link to Igor Zlatkovic's xsltproc packages. ........ r47800 | danieljames | 2008-07-25 11:24:50 +0100 (Fri, 25 Jul 2008) | 1 line Fix a link. ........ r47807 | danieljames | 2008-07-25 18:52:11 +0100 (Fri, 25 Jul 2008) | 1 line Convert a few 'unacceptable' characters to underscores in generated documentation filenames. ........ r47811 | danieljames | 2008-07-25 22:13:27 +0100 (Fri, 25 Jul 2008) | 1 line Avoid some more unacceptable characters. ........ r47812 | danieljames | 2008-07-25 22:15:39 +0100 (Fri, 25 Jul 2008) | 1 line Merge asio details from the release branch. ........ r47813 | danieljames | 2008-07-25 22:25:58 +0100 (Fri, 25 Jul 2008) | 1 line Fix a typo. ........ [SVN r47819] --- doc/changes.qbk | 2 +- doc/intro.qbk | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index e29b7a85..8fd4c2a9 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -10,7 +10,7 @@ Initial review version, for the review conducted from 7th December 2007 to 16th December 2007. -[h2 1.35.0 Add-on - 31st Match 2008] +[h2 1.35.0 Add-on - 31st March 2008] Unofficial release uploaded to vault, to be used with Boost 1.35.0. Incorporated many of the suggestions from the review. diff --git a/doc/intro.qbk b/doc/intro.qbk index 58fcb987..5f918138 100644 --- a/doc/intro.qbk +++ b/doc/intro.qbk @@ -36,9 +36,7 @@ which are implemented using hash tables, and they have now been added to the __draft__. This library supplies an almost complete implementation of the specification in -the __draft__, (it doesn't support `emplace` yet, see the [link -unordered.rationale.future_developments Implementation Rationale] section for more -details). If accepted the containers should also be added to __boost-tr1__. +the __draft__. `unordered_set` and `unordered_multiset` are defined in the header <[headerref boost/unordered_set.hpp]> From 93141c26b9b964ec12be15930709ae737a40629d Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 30 Jul 2008 22:29:27 +0000 Subject: [PATCH 009/100] Merge a couple of simple documentation fixes. Merged revisions 47881-47882 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r47881 | danieljames | 2008-07-30 10:44:26 +0100 (Wed, 30 Jul 2008) | 1 line Fix a link and a header. ........ r47882 | danieljames | 2008-07-30 11:46:27 +0100 (Wed, 30 Jul 2008) | 1 line Use the correct library page for the asio documentation. ........ [SVN r47900] --- doc/comparison.qbk | 2 +- doc/rationale.qbk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/comparison.qbk b/doc/comparison.qbk index d995e16c..3cea831e 100644 --- a/doc/comparison.qbk +++ b/doc/comparison.qbk @@ -72,7 +72,7 @@ [ [Can be compared using the `==`, `!=`, `<`, `<=`, `>`, `>=` operators.] [No comparison operators are defined in the standard, although - [link unordered.rationale.equality_operator + [link unordered.rationale.equality_operators implementations might extend the containers to support `==` and `!=`].] ] diff --git a/doc/rationale.qbk b/doc/rationale.qbk index 63ca6441..62774a66 100644 --- a/doc/rationale.qbk +++ b/doc/rationale.qbk @@ -96,7 +96,7 @@ efficiency advantage of power of 2 hash tables. So, this implementation uses a prime number for the hash table size. -[h2 Equality operators and hash functions] +[h2 Equality operators] `operator==` and `operator!=` are not included in the standard, but I've added them as I think they could be useful and can be efficiently From 517e39fc232f43f28609af4849a5bac6367edc34 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 18 Sep 2008 11:30:59 +0000 Subject: [PATCH 010/100] Merged revisions 48081-48082,48791,48802-48803,48853 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r48081 | danieljames | 2008-08-11 08:52:37 +0100 (Mon, 11 Aug 2008) | 2 lines Rename 'emplace' with hint to 'emplace_hint'. ........ r48082 | danieljames | 2008-08-11 08:53:05 +0100 (Mon, 11 Aug 2008) | 2 lines More recent version of the working draft. ........ r48791 | danieljames | 2008-09-15 22:48:46 +0100 (Mon, 15 Sep 2008) | 1 line Fix a workaround macro. ........ r48802 | danieljames | 2008-09-16 22:45:53 +0100 (Tue, 16 Sep 2008) | 1 line Forward headers for the unordered containers. ........ r48803 | danieljames | 2008-09-16 22:49:41 +0100 (Tue, 16 Sep 2008) | 1 line Move the unordered headers into the unordered directory. ........ r48853 | danieljames | 2008-09-18 12:23:12 +0100 (Thu, 18 Sep 2008) | 1 line Update unordered changelog. ........ [SVN r48854] --- doc/changes.qbk | 9 + doc/intro.qbk | 2 +- doc/ref.xml | 16 +- include/boost/unordered/unordered_map.hpp | 788 +++++++++++++++++ include/boost/unordered/unordered_map_fwd.hpp | 53 ++ include/boost/unordered/unordered_set.hpp | 745 ++++++++++++++++ include/boost/unordered/unordered_set_fwd.hpp | 51 ++ include/boost/unordered_map.hpp | 808 +----------------- include/boost/unordered_set.hpp | 763 +---------------- test/objects/minimal.hpp | 2 +- test/unordered/Jamfile.v2 | 2 + test/unordered/compile_tests.hpp | 2 +- test/unordered/fwd_map_test.cpp | 62 ++ test/unordered/fwd_set_test.cpp | 84 ++ 14 files changed, 1807 insertions(+), 1580 deletions(-) create mode 100644 include/boost/unordered/unordered_map.hpp create mode 100644 include/boost/unordered/unordered_map_fwd.hpp create mode 100644 include/boost/unordered/unordered_set.hpp create mode 100644 include/boost/unordered/unordered_set_fwd.hpp create mode 100644 test/unordered/fwd_map_test.cpp create mode 100644 test/unordered/fwd_set_test.cpp diff --git a/doc/changes.qbk b/doc/changes.qbk index 8fd4c2a9..b55a5170 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -33,4 +33,13 @@ First official release. are available. * Added equality operators. +[h2 Boost 1.37.0] + +* Rename overload of `emplace` with hint, to `emplace_hint` as specified in + [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2691.pdf n2691]. +* Provide forwarding headers at `` and + ``. +* Move all the implementation inside `boost/unordered`, to assist + modularization and hopefully make it easier to track changes in subversion. + [endsect] diff --git a/doc/intro.qbk b/doc/intro.qbk index 5f918138..6e4b4ce1 100644 --- a/doc/intro.qbk +++ b/doc/intro.qbk @@ -9,7 +9,7 @@ [@http://www.boost.org/doc/html/boost_tr1.html Boost.TR1]] [def __draft__ - [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2007/n2461.pdf + [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2691.pdf Working Draft of the C++ Standard]] [def __hash-table__ [@http://en.wikipedia.org/wiki/Hash_table hash table]] diff --git a/doc/ref.xml b/doc/ref.xml index d7dd9259..67ef3640 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -24,7 +24,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) For the normative reference see chapter 23 of - the working draft of the C++ standard [n2461]. + the working draft of the C++ standard [n2691]. Template Parameters @@ -287,7 +287,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Only available on compilers with support for variadic template arguments and rvalue references. - + - + An unordered associative container that associates keys with another value. The same key can be stored multiple times. - + For the normative reference see chapter 23 of the working draft of the C++ standard [n2691]. @@ -2330,11 +2330,11 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) typename allocator_type::reference - lvalue of value_type. + lvalue of value_type. typename allocator_type::const_reference - const lvalue of value_type. + const lvalue of value_type. implementation-defined From 60e3e96b48aad04a5eeb654f0dad02862129b6f3 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 30 Mar 2009 17:54:49 +0000 Subject: [PATCH 019/100] Tweak unordered for some compilers. Fixes #2756. Merged revisions 51982-51983,51995 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r51982 | danieljames | 2009-03-26 07:00:21 +0000 (Thu, 26 Mar 2009) | 3 lines Revert [51409] It isn't working on Borland. ........ r51983 | danieljames | 2009-03-26 07:00:46 +0000 (Thu, 26 Mar 2009) | 1 line Try to destruct values in a way that all compilers might like. ........ r51995 | danieljames | 2009-03-26 21:09:51 +0000 (Thu, 26 Mar 2009) | 1 line Give up and use another macro to destruct values. ........ [SVN r52065] --- include/boost/unordered/detail/hash_table.hpp | 48 +------- .../unordered/detail/hash_table_impl.hpp | 109 ++++++++++++------ 2 files changed, 76 insertions(+), 81 deletions(-) diff --git a/include/boost/unordered/detail/hash_table.hpp b/include/boost/unordered/detail/hash_table.hpp index 1bdcced8..c6ded509 100644 --- a/include/boost/unordered/detail/hash_table.hpp +++ b/include/boost/unordered/detail/hash_table.hpp @@ -224,53 +224,15 @@ namespace boost { functions_ptr func_; // The currently active functions. }; +#if defined(BOOST_MSVC) +# define BOOST_UNORDERED_DESTRUCT(x, type) (x)->~type(); +#else +# define BOOST_UNORDERED_DESTRUCT(x, type) boost::unordered_detail::destroy(x) template void destroy(T* x) { x->~T(); } - - // Some classes for the data structure - - template - struct bucket_impl - { - private: - bucket_impl& operator=(bucket_impl const&); - public: - typedef BOOST_DEDUCED_TYPENAME - boost::unordered_detail::rebind_wrap::type - bucket_allocator; - typedef BOOST_DEDUCED_TYPENAME - allocator_pointer::type bucket_ptr; - typedef bucket_ptr link_ptr; - - link_ptr next_; - - bucket_impl() : next_() - { - BOOST_UNORDERED_MSVC_RESET_PTR(next_); - } - - bucket_impl(bucket_impl const& x) : next_(x.next_) - { - // Only copy construct when allocating. - BOOST_ASSERT(!x.next_); - } - - bool empty() const - { - return !this->next_; - } - }; - - template - struct value_base { - typename boost::aligned_storage< - sizeof(T), - boost::alignment_of::value>::type data_; - - void* address() { return this; } - }; +#endif } } diff --git a/include/boost/unordered/detail/hash_table_impl.hpp b/include/boost/unordered/detail/hash_table_impl.hpp index c7ab515d..a8e86ad4 100644 --- a/include/boost/unordered/detail/hash_table_impl.hpp +++ b/include/boost/unordered/detail/hash_table_impl.hpp @@ -6,7 +6,6 @@ #if BOOST_UNORDERED_EQUIVALENT_KEYS #define BOOST_UNORDERED_TABLE hash_table_equivalent_keys -#define BOOST_UNORDERED_TABLE_NODE node_equivalent_keys #define BOOST_UNORDERED_TABLE_DATA hash_table_data_equivalent_keys #define BOOST_UNORDERED_ITERATOR hash_iterator_equivalent_keys #define BOOST_UNORDERED_CONST_ITERATOR hash_const_iterator_equivalent_keys @@ -14,7 +13,6 @@ #define BOOST_UNORDERED_CONST_LOCAL_ITERATOR hash_const_local_iterator_equivalent_keys #else #define BOOST_UNORDERED_TABLE hash_table_unique_keys -#define BOOST_UNORDERED_TABLE_NODE node_unique_keys #define BOOST_UNORDERED_TABLE_DATA hash_table_data_unique_keys #define BOOST_UNORDERED_ITERATOR hash_iterator_unique_keys #define BOOST_UNORDERED_CONST_ITERATOR hash_const_iterator_unique_keys @@ -25,32 +23,6 @@ namespace boost { namespace unordered_detail { - template - struct BOOST_UNORDERED_TABLE_NODE : - value_base::type>, - bucket_impl - { - typedef BOOST_DEDUCED_TYPENAME bucket_impl::link_ptr link_ptr; - typedef BOOST_DEDUCED_TYPENAME allocator_value_type::type value_type; - - typedef BOOST_DEDUCED_TYPENAME - boost::unordered_detail::rebind_wrap::type - node_allocator; - -#if BOOST_UNORDERED_EQUIVALENT_KEYS - BOOST_UNORDERED_TABLE_NODE() : group_prev_() - { - BOOST_UNORDERED_MSVC_RESET_PTR(group_prev_); - } - - link_ptr group_prev_; -#endif - - value_type& value() { - return *static_cast(this->address()); - } - }; - // // Hash Table Data // @@ -62,24 +34,86 @@ namespace boost { public: typedef BOOST_UNORDERED_TABLE_DATA data; + struct node; + struct bucket; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef Alloc value_allocator; - typedef bucket_impl bucket; - typedef BOOST_DEDUCED_TYPENAME bucket::bucket_allocator bucket_allocator; - typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME bucket::link_ptr link_ptr; - - typedef BOOST_UNORDERED_TABLE_NODE node; - typedef BOOST_DEDUCED_TYPENAME node::node_allocator node_allocator; + typedef BOOST_DEDUCED_TYPENAME + boost::unordered_detail::rebind_wrap::type + node_allocator; + typedef BOOST_DEDUCED_TYPENAME + boost::unordered_detail::rebind_wrap::type + bucket_allocator; typedef BOOST_DEDUCED_TYPENAME allocator_value_type::type value_type; typedef BOOST_DEDUCED_TYPENAME allocator_pointer::type node_ptr; + typedef BOOST_DEDUCED_TYPENAME allocator_pointer::type bucket_ptr; typedef BOOST_DEDUCED_TYPENAME allocator_reference::type reference; typedef BOOST_DEDUCED_TYPENAME allocator_reference::type bucket_reference; + typedef bucket_ptr link_ptr; + + // Hash Bucket + // + // all no throw + + struct bucket + { + private: + bucket& operator=(bucket const&); + public: + link_ptr next_; + + bucket() : next_() + { + BOOST_UNORDERED_MSVC_RESET_PTR(next_); + } + + bucket(bucket const& x) : next_(x.next_) + { + // Only copy construct when allocating. + BOOST_ASSERT(!x.next_); + } + + bool empty() const + { + return !this->next_; + } + }; + + // Value Base + + struct value_base { + typename boost::aligned_storage< + sizeof(value_type), + boost::alignment_of::value>::type data_; + + void* address() { return this; } + }; + + // Hash Node + // + // all no throw + + struct node : value_base, bucket { +#if BOOST_UNORDERED_EQUIVALENT_KEYS + public: + node() : group_prev_() + { + BOOST_UNORDERED_MSVC_RESET_PTR(group_prev_); + } + + link_ptr group_prev_; +#endif + + value_type& value() { + return *static_cast(this->address()); + } + }; + // allocators // // Stores all the allocators that we're going to need. @@ -96,7 +130,7 @@ namespace boost { void destroy(link_ptr ptr) { node* raw_ptr = static_cast(&*ptr); - boost::unordered_detail::destroy(&raw_ptr->value()); + BOOST_UNORDERED_DESTRUCT(&raw_ptr->value(), value_type); node_ptr n(node_alloc_.address(*raw_ptr)); node_alloc_.destroy(n); node_alloc_.deallocate(n, 1); @@ -138,7 +172,7 @@ namespace boost { { if (node_) { if (value_constructed_) { - boost::unordered_detail::destroy(&node_->value()); + BOOST_UNORDERED_DESTRUCT(&node_->value(), value_type); } if (node_constructed_) @@ -2291,7 +2325,6 @@ namespace boost { } #undef BOOST_UNORDERED_TABLE -#undef BOOST_UNORDERED_TABLE_NODE #undef BOOST_UNORDERED_TABLE_DATA #undef BOOST_UNORDERED_ITERATOR #undef BOOST_UNORDERED_CONST_ITERATOR From b475ba05c00e27513a31cd70aeb0ba7ebb1a4692 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 11 Apr 2009 08:49:33 +0000 Subject: [PATCH 020/100] Merge quickbook and hash changelogs. Tweak gcc detection in container_fwd.hpp Merged revisions 52084,52245-52246,52304,52320,52323 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r52084 | danieljames | 2009-03-31 20:43:58 +0100 (Tue, 31 Mar 2009) | 1 line Changelog for unordered and hash. ........ r52245 | danieljames | 2009-04-08 06:51:31 +0100 (Wed, 08 Apr 2009) | 5 lines Detect gcc stdlib for gcc 4.0.1. For some reason the normal macros aren't defined for the standard library that comes with gcc 4.0.1 (although maybe just on BSDs?). So try to detect the library for that compiler. ........ r52246 | danieljames | 2009-04-08 11:56:22 +0100 (Wed, 08 Apr 2009) | 7 lines Include for some versions of gcc's library. Sometimes gcc's doesn't define the C++ macros, so check for it and include in that case. Also remove a workaround from container_fwd.hpp Fixes #2924. ........ r52304 | danieljames | 2009-04-10 20:25:32 +0100 (Fri, 10 Apr 2009) | 4 lines Don't use debug containers on darwin. I'm getting errors from the darwin 4.2 debug containers which appear to a problem with its implementation. ........ r52320 | danieljames | 2009-04-11 08:53:59 +0100 (Sat, 11 Apr 2009) | 1 line Don't need to include utility now that select_stdlib has been fixed. ........ r52323 | danieljames | 2009-04-11 09:26:20 +0100 (Sat, 11 Apr 2009) | 1 line Also don't need to check for _GLIBCXX_CSTDDEF. ........ [SVN r52324] --- doc/changes.qbk | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/changes.qbk b/doc/changes.qbk index cb48dad4..7b467f6c 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -62,4 +62,11 @@ First official release. * Add support for C++0x initializer lists where they're available (currently only g++ 4.4 in C++0x mode). +[h2 Boost 1.39.0] + +* [@https://svn.boost.org/trac/boost/ticket/2756 Ticket 2756]: Avoid a warning + on Visual C++ 2009. +* Some other minor internal changes to the implementation, tests and + documentation. + [endsect] From ab62d334958e906af0aaee6f9a5dd50d4910505d Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 12 Apr 2009 10:25:38 +0000 Subject: [PATCH 021/100] Merged revisions 52224 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r52224 | danieljames | 2009-04-06 23:51:36 +0100 (Mon, 06 Apr 2009) | 1 line Avoid an unnecessary copy in 'operator[]' ........ [SVN r52346] --- .../boost/unordered/detail/hash_table_impl.hpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/hash_table_impl.hpp b/include/boost/unordered/detail/hash_table_impl.hpp index a8e86ad4..e7cdc5b9 100644 --- a/include/boost/unordered/detail/hash_table_impl.hpp +++ b/include/boost/unordered/detail/hash_table_impl.hpp @@ -215,6 +215,22 @@ namespace boost { } #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_); @@ -1757,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(value_type(k, mapped_type())); + a.construct_pair(k, (mapped_type*) 0); // reserve has basic exception safety if the hash function // throws, strong otherwise. From 694398f0e1d67132b1153d7beceb41adbdef4808 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 12 Apr 2009 10:54:44 +0000 Subject: [PATCH 022/100] Some small documentation fixes for the release. Merged revisions 52348-52350 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r52348 | danieljames | 2009-04-12 11:50:31 +0100 (Sun, 12 Apr 2009) | 1 line Use a test file that's actually valid C++. ........ r52349 | danieljames | 2009-04-12 11:50:43 +0100 (Sun, 12 Apr 2009) | 3 lines Revert support for static mutable variables. Of course there's no such thing. ........ r52350 | danieljames | 2009-04-12 11:50:57 +0100 (Sun, 12 Apr 2009) | 1 line Note change to operator[] in the unordered release notes. ........ [SVN r52351] --- doc/changes.qbk | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changes.qbk b/doc/changes.qbk index 7b467f6c..396eb887 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -68,5 +68,6 @@ First official release. on Visual C++ 2009. * Some other minor internal changes to the implementation, tests and documentation. +* Avoid an unnecessary copy in `operator[]`. [endsect] From fb71e0618d04fee12803b1622f83a070f95fcc35 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 1 May 2009 19:00:57 +0000 Subject: [PATCH 023/100] Last minute merge, remove google analytics script tags and fixes #2975. Merged revisions 52665,52674 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r52665 | danieljames | 2009-04-29 22:16:10 +0100 (Wed, 29 Apr 2009) | 1 line Remove google analytics script tags. ........ r52674 | danieljames | 2009-04-30 06:10:57 +0100 (Thu, 30 Apr 2009) | 1 line Fix the prime number list length in unordered. ........ [SVN r52707] --- include/boost/unordered/detail/hash_table.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/hash_table.hpp b/include/boost/unordered/detail/hash_table.hpp index c6ded509..04696176 100644 --- a/include/boost/unordered/detail/hash_table.hpp +++ b/include/boost/unordered/detail/hash_table.hpp @@ -87,7 +87,7 @@ namespace boost { 1610612741ul, 3221225473ul, 4294967291ul }; template - std::ptrdiff_t const prime_list_template::length = 28; + std::ptrdiff_t const prime_list_template::length = 40; typedef prime_list_template prime_list; From 4e6b5de1962422e4969c40518ee00b1e9a8e1622 Mon Sep 17 00:00:00 2001 From: "Troy D. Straszheim" Date: Fri, 15 May 2009 00:21:14 +0000 Subject: [PATCH 024/100] tuning up cmakefiles for unordered, utility [SVN r53008] --- CMakeLists.txt | 2 +- test/CMakeLists.txt | 61 ++--------------------------------- test/exception/CMakeLists.txt | 19 +++++++++++ test/unordered/CMakeLists.txt | 37 +++++++++++++++++++++ 4 files changed, 59 insertions(+), 60 deletions(-) create mode 100644 test/exception/CMakeLists.txt create mode 100644 test/unordered/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 20891f58..59196994 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ set (lib_headers boost_library_project( unordered # SRCDIRS - # TESTDIRS + TESTDIRS test HEADERS ${lib_headers} # DOCDIRS # DESCRIPTION diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e164a7bf..51973cb0 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -12,64 +12,7 @@ ENDIF( ${CMAKE_CXX_COMPILER} MATCHES "icpc" ) set (swap_compile_flags "${test_compile_flags} -DBOOST_UNORDERED_SWAP_METHOD=2") -#------------------------------------------------------------------------------- -# Unordered Tests -set (unordered_tests - fwd_set_test - fwd_map_test - compile_set - compile_map - link_test_1 - link_test_2 - simple_tests - equivalent_keys_tests - constructor_tests - copy_tests - move_tests.cpp - assign_tests - insert_tests - insert_stable_tests - unnecessary_copy_tests - erase_tests - erase_equiv_tests - find_tests - at_tests - bucket_tests - load_factor_tests - rehash_tests - equality_tests -) -#-- Create an executable test for each source -foreach(test ${unordered_tests}) - boost_test_run(${test} "unordered/${test}.cpp" - COMPILE_FLAGS ${test_compile_flags} - DEPENDS boost_unit_test_framework) -endforeach(test ${unordered_tests}) -#-- run the swap test -boost_test_run(swap_tests - COMPILE_FLAGS ${swap_compile_flags} - DEPENDS boost_unit_test_framework) -#------------------------------------------------------------------------------- -# Exception Tests -set (exception_tests - constructor_exception_tests - copy_exception_tests - assign_exception_tests - insert_exception_tests - erase_exception_tests - rehash_exception_tests -) - -#-- Create an executable test for each source -foreach(test ${exception_tests}) - boost_test_run(${test} "exception/${test}.cpp" - COMPILE_FLAGS ${test_compile_flags} - DEPENDS boost_unit_test_framework) -endforeach(test ${unordered_tests}) - -#-- run the swap test -boost_test_run(swap_swap_exception_tests - COMPILE_FLAGS ${swap_compile_flags} - DEPENDS boost_unit_test_framework) +add_subdirectory(exception) +add_subdirectory(unordered) \ No newline at end of file diff --git a/test/exception/CMakeLists.txt b/test/exception/CMakeLists.txt new file mode 100644 index 00000000..ec36ff62 --- /dev/null +++ b/test/exception/CMakeLists.txt @@ -0,0 +1,19 @@ + +foreach(test + constructor_exception_tests + copy_exception_tests + assign_exception_tests + insert_exception_tests + erase_exception_tests + rehash_exception_tests + ) + boost_test_run(${test} + COMPILE_FLAGS ${test_compile_flags} + DEPENDS boost_unit_test_framework) +endforeach(test ${unordered_tests}) + +#-- run the swap test +boost_test_run(swap_exception_tests + COMPILE_FLAGS ${swap_compile_flags} + DEPENDS boost_unit_test_framework) + diff --git a/test/unordered/CMakeLists.txt b/test/unordered/CMakeLists.txt new file mode 100644 index 00000000..f3c58ad1 --- /dev/null +++ b/test/unordered/CMakeLists.txt @@ -0,0 +1,37 @@ +#------------------------------------------------------------------------------- +# Unordered Tests +foreach(test + fwd_set_test + fwd_map_test + compile_set + compile_map + simple_tests + equivalent_keys_tests + constructor_tests + copy_tests + move_tests + assign_tests + insert_tests + insert_stable_tests + unnecessary_copy_tests + erase_tests + erase_equiv_tests + find_tests + at_tests + bucket_tests + load_factor_tests + rehash_tests + equality_tests + ) + boost_test_run(${test} + COMPILE_FLAGS ${test_compile_flags} + DEPENDS boost_unit_test_framework) +endforeach() + +boost_test_run(link_test link_test_1.cpp link_test_2.cpp) + +#-- run the swap test +boost_test_run(swap_tests + COMPILE_FLAGS ${swap_compile_flags} + DEPENDS boost_unit_test_framework) + From f02cc7775daf4f00dfbe4dbbfba7561dc5519146 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 16 May 2009 13:38:37 +0000 Subject: [PATCH 025/100] Long term fix for the incorrect length of prime list. Merged revisions 52658,52669,52673,52711 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r52658 | danieljames | 2009-04-29 11:05:17 +0100 (Wed, 29 Apr 2009) | 1 line Fix the length of the prime number list. ........ r52669 | danieljames | 2009-04-29 22:43:41 +0100 (Wed, 29 Apr 2009) | 3 lines Don't test prime_list::length on Visual C++. Checking the array size doesn't seem to work on it. ........ r52673 | danieljames | 2009-04-30 06:08:40 +0100 (Thu, 30 Apr 2009) | 1 line Revert changes to unordered, as the test fails on most compilers. ........ r52711 | danieljames | 2009-05-01 21:50:32 +0100 (Fri, 01 May 2009) | 5 lines Use a preprocessor sequence for the primes. This feels like overkill but it seems to be the most reliable way to ensure that the length is correct. I obviously can't be trusted to get it right, and the template hack seems to prevent Boost.Range from working. ........ [SVN r53043] --- include/boost/unordered/detail/hash_table.hpp | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/include/boost/unordered/detail/hash_table.hpp b/include/boost/unordered/detail/hash_table.hpp index 04696176..f64e3e83 100644 --- a/include/boost/unordered/detail/hash_table.hpp +++ b/include/boost/unordered/detail/hash_table.hpp @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include @@ -76,18 +78,25 @@ namespace boost { static std::ptrdiff_t const length; }; - template - std::size_t const prime_list_template::value[] = { - 5ul, 11ul, 17ul, 29ul, 37ul, 53ul, 67ul, 79ul, - 97ul, 131ul, 193ul, 257ul, 389ul, 521ul, 769ul, - 1031ul, 1543ul, 2053ul, 3079ul, 6151ul, 12289ul, 24593ul, - 49157ul, 98317ul, 196613ul, 393241ul, 786433ul, - 1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul, - 50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul, - 1610612741ul, 3221225473ul, 4294967291ul }; +#define BOOST_UNORDERED_PRIMES \ + (5ul)(11ul)(17ul)(29ul)(37ul)(53ul)(67ul)(79ul) \ + (97ul)(131ul)(193ul)(257ul)(389ul)(521ul)(769ul) \ + (1031ul)(1543ul)(2053ul)(3079ul)(6151ul)(12289ul)(24593ul) \ + (49157ul)(98317ul)(196613ul)(393241ul)(786433ul) \ + (1572869ul)(3145739ul)(6291469ul)(12582917ul)(25165843ul) \ + (50331653ul)(100663319ul)(201326611ul)(402653189ul)(805306457ul) \ + (1610612741ul)(3221225473ul)(4294967291ul) template - std::ptrdiff_t const prime_list_template::length = 40; + std::size_t const prime_list_template::value[] = { + BOOST_PP_SEQ_ENUM(BOOST_UNORDERED_PRIMES) + }; + + template + std::ptrdiff_t const prime_list_template::length + = BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES); + +#undef BOOST_UNORDERED_PRIMES typedef prime_list_template prime_list; From e911a8011b960098208606d2c93d391eb47329e3 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 25 May 2009 19:57:04 +0000 Subject: [PATCH 026/100] 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] --- doc/changes.qbk | 10 + include/boost/unordered/detail/config.hpp | 8 + include/boost/unordered/detail/hash_table.hpp | 27 +- .../unordered/detail/hash_table_impl.hpp | 603 ++++++++++++------ include/boost/unordered/unordered_map.hpp | 116 +++- include/boost/unordered/unordered_set.hpp | 115 +++- test/helpers/count.hpp | 7 + test/objects/exception.hpp | 2 +- test/objects/minimal.hpp | 2 +- test/objects/test.hpp | 2 +- test/unordered/compile_tests.hpp | 8 - test/unordered/unnecessary_copy_tests.cpp | 64 +- 12 files changed, 718 insertions(+), 246 deletions(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index 396eb887..a8b81eef 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -69,5 +69,15 @@ 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 f277feae..68c9875a 100644 --- a/include/boost/unordered/detail/config.hpp +++ b/include/boost/unordered/detail/config.hpp @@ -19,4 +19,12 @@ # 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 f64e3e83..8a458f7f 100644 --- a/include/boost/unordered/detail/hash_table.hpp +++ b/include/boost/unordered/detail/hash_table.hpp @@ -12,6 +12,11 @@ #endif #include +#include + +#if !defined(BOOST_UNORDERED_EMPLACE_LIMIT) +#define BOOST_UNORDERED_EMPLACE_LIMIT 5 +#endif #include #include @@ -28,8 +33,12 @@ #include #include #include +#include +#include #include #include +#include +#include #include #include #include @@ -37,11 +46,19 @@ #include -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) -#include -#include -#include -#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) + #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 e7cdc5b9..bc842dc8 100644 --- a/include/boost/unordered/detail/hash_table_impl.hpp +++ b/include/boost/unordered/detail/hash_table_impl.hpp @@ -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 void construct(Args&&... args) { - 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(std::forward(args)...); value_constructed_ = true; } -#else - template - void construct(V const& v) + +#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) { - 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); + 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 - template - void construct_pair(K const& k, M*) + void construct() { - 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()); + construct_preamble(); + new(node_->address()) value_type; 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 + node_ptr get() const { BOOST_ASSERT(node_); @@ -1427,8 +1530,29 @@ 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); @@ -1445,40 +1569,67 @@ namespace boost { { return v.first; } - -#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&...) + + // 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) { 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 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) + 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) { return v.first; } - template - static no_key extract_key(Args const&...) + // 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&...) { - return no_key(); + return k; } + +#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: @@ -1582,72 +1733,78 @@ namespace boost { #if BOOST_UNORDERED_EQUIVALENT_KEYS -#if !(defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)) - // Insert (equivalent key containers) +#if defined(BOOST_UNORDERED_STD_FORWARD) + + // Emplace (equivalent key containers) + // (I'm using an overloaded emplace for both 'insert' and 'emplace') // if hash function throws, basic exception safety // strong otherwise - iterator_base insert(value_type const& v) + template + iterator_base emplace(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(v); + a.construct(std::forward(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 // strong otherwise - iterator_base insert_hint(iterator_base const& it, value_type const& v) + template + iterator_base emplace_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(v); + a.construct(std::forward(args)...); - return insert_hint_impl(it, a); + return emplace_hint_impl(it, a); } #else - // 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); +#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_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); - } + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_INSERT_IMPL, _) +#undef BOOST_UNORDERED_INSERT_IMPL #endif - iterator_base insert_impl(node_constructor& a) + iterator_base emplace_impl(node_constructor& a) { key_type const& k = extract_key(a.get()->value()); 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 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 insert_impl(a); + 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) @@ -1707,7 +1864,7 @@ namespace boost { { size_type distance = unordered_detail::distance(i, j); if(distance == 1) { - insert(*i); + emplace(*i); } else { // Only require basic exception safety here @@ -1737,7 +1894,7 @@ namespace boost { { // If only inserting 1 element, get the required // safety since insert is only called once. - for (; i != j; ++i) insert(*i); + for (; i != j; ++i) emplace(*i); } public: @@ -1773,7 +1930,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_pair(k, (mapped_type*) 0); + a.construct(k); // reserve has basic exception safety if the hash function // 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) - - // 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. + // Emplace (unique keys) + // (I'm using an overloaded emplace for both 'insert' and 'emplace') // if hash function throws, basic exception safety // strong otherwise template - std::pair insert(Args&&... args) + std::pair emplace(Args&&... args) { - return insert_impl( + return emplace_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 - std::pair 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)...), + std::forward(args)...).first; + } + + template + std::pair emplace_impl(key_type const& k, Args&&... args) { // No side effects in this initial code size_type hash_value = hash_function()(k); @@ -1894,13 +2007,110 @@ namespace boost { } template - std::pair insert_impl(no_key, Args&&... args) + std::pair emplace_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); @@ -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 - 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 @@ -1963,6 +2160,13 @@ 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_); @@ -1992,6 +2196,36 @@ 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: @@ -2078,8 +2312,9 @@ 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 f787de2a..5a282879 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -21,6 +21,10 @@ #include #endif +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) +#include +#endif + #if defined(BOOST_MSVC) #pragma warning(push) #if BOOST_MSVC >= 1400 @@ -135,7 +139,7 @@ namespace boost #endif #endif -#if !defined(BOOST_NO_INITIALIZER_LISTS) +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) unordered_map(std::initializer_list list, size_type n = boost::unordered_detail::default_initial_bucket_count, const hasher &hf = hasher(), @@ -219,30 +223,74 @@ namespace boost // modifiers -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) +#if defined(BOOST_UNORDERED_STD_FORWARD) template std::pair emplace(Args&&... args) { return boost::unordered_detail::pair_cast( - base.insert(std::forward(args)...)); + base.emplace(std::forward(args)...)); } template iterator emplace_hint(const_iterator hint, Args&&... args) { - return iterator(base.insert_hint(get(hint), std::forward(args)...)); + return iterator(base.emplace_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.insert(obj)); + base.emplace(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 @@ -541,7 +589,7 @@ namespace boost #endif #endif -#if !defined(BOOST_NO_INITIALIZER_LISTS) +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) unordered_multimap(std::initializer_list list, size_type n = boost::unordered_detail::default_initial_bucket_count, const hasher &hf = hasher(), @@ -626,28 +674,72 @@ namespace boost // modifiers -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) +#if defined(BOOST_UNORDERED_STD_FORWARD) template iterator emplace(Args&&... args) { - return iterator(base.insert(std::forward(args)...)); + return iterator(base.emplace(std::forward(args)...)); } template iterator emplace_hint(const_iterator hint, Args&&... args) { - return iterator(base.insert_hint(get(hint), std::forward(args)...)); + return iterator(base.emplace_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.insert(obj)); + return iterator(base.emplace(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 diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 4e9f39bb..cfe6c9b7 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -21,6 +21,10 @@ #include #endif +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) +#include +#endif + #if defined(BOOST_MSVC) #pragma warning(push) #if BOOST_MSVC >= 1400 @@ -133,7 +137,7 @@ namespace boost #endif #endif -#if !defined(BOOST_NO_INITIALIZER_LISTS) +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) unordered_set(std::initializer_list list, size_type n = boost::unordered_detail::default_initial_bucket_count, const hasher &hf = hasher(), @@ -217,31 +221,75 @@ namespace boost // modifiers -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) +#if defined(BOOST_UNORDERED_STD_FORWARD) template std::pair emplace(Args&&... args) { return boost::unordered_detail::pair_cast( - base.insert(std::forward(args)...)); + base.emplace(std::forward(args)...)); } template iterator emplace_hint(const_iterator hint, Args&&... args) { return iterator( - base.insert_hint(get(hint), std::forward(args)...)); + base.emplace_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.insert(obj)); + base.emplace(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 @@ -511,7 +559,7 @@ namespace boost #endif #endif -#if !defined(BOOST_NO_INITIALIZER_LISTS) +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) unordered_multiset(std::initializer_list list, size_type n = boost::unordered_detail::default_initial_bucket_count, const hasher &hf = hasher(), @@ -595,28 +643,71 @@ namespace boost // modifiers -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) +#if defined(BOOST_UNORDERED_STD_FORWARD) template iterator emplace(Args&&... args) { - return iterator(base.insert(std::forward(args)...)); + return iterator(base.emplace(std::forward(args)...)); } template iterator emplace_hint(const_iterator hint, Args&&... args) { - return iterator(base.insert_hint(get(hint), std::forward(args)...)); + return iterator(base.emplace_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.insert(obj)); + return iterator(base.emplace(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 diff --git a/test/helpers/count.hpp b/test/helpers/count.hpp index 11e00e9f..0589586e 100644 --- a/test/helpers/count.hpp +++ b/test/helpers/count.hpp @@ -6,6 +6,8 @@ #if !defined(BOOST_UNORDERED_TEST_HELPERS_COUNT_HEAD) #define BOOST_UNORDERED_TEST_HELPERS_COUNT_HEAD +#include + namespace test { struct object_count { int instances; @@ -36,6 +38,11 @@ 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 25f783ec..22119e85 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_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) +#if defined(BOOST_UNORDERED_STD_FORWARD) 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 535a7684..252e3564 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_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) +#if defined(BOOST_UNORDERED_STD_FORWARD) 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 28fc5e53..63f7c91b 100644 --- a/test/objects/test.hpp +++ b/test/objects/test.hpp @@ -218,7 +218,7 @@ namespace test new(p) T(t); } -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) +#if defined(BOOST_UNORDERED_STD_FORWARD) 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 486d3e2e..3dd00fdf 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -151,14 +151,12 @@ 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 @@ -175,9 +173,7 @@ 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 @@ -185,9 +181,7 @@ 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 @@ -289,9 +283,7 @@ 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 df4baf3c..3cf707ef 100644 --- a/test/unordered/unnecessary_copy_tests.cpp +++ b/test/unordered/unnecessary_copy_tests.cpp @@ -68,12 +68,22 @@ 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*) { @@ -117,9 +126,19 @@ 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*) { @@ -131,13 +150,11 @@ 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(); @@ -172,10 +189,12 @@ 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; @@ -192,8 +211,12 @@ 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); } @@ -230,24 +253,22 @@ namespace unnecessary_copy_tests x.emplace(source >()); COPY_COUNT(2); MOVE_COUNT(0); - count_copies part; - reset(); - std::pair a_ref(part, part); - x.emplace(a_ref); - COPY_COUNT(0); 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); +#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 @@ -267,10 +288,9 @@ namespace unnecessary_copy_tests COPY_COUNT(1); MOVE_COUNT(0); reset(); - x.emplace(b.first.tag_, b.second.tag_); - COPY_COUNT(2); MOVE_COUNT(0); + x.emplace(count_copies(b.first.tag_), count_copies(b.second.tag_)); + COPY_COUNT(2); MOVE_COUNT(0); } -#endif } RUN_TESTS() From 0b4241833d412697eee5ea3613beeac3bee31831 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 26 May 2009 09:56:59 +0000 Subject: [PATCH 027/100] Rollback [52357] as it depends on macros that aren't in release. Rolled back revisions 52393-52394,52397,52884-52885,53127,53255 via svnmerge from https://svn.boost.org/svn/boost/trunk [SVN r53277] --- doc/changes.qbk | 10 - include/boost/unordered/detail/config.hpp | 8 - include/boost/unordered/detail/hash_table.hpp | 27 +- .../unordered/detail/hash_table_impl.hpp | 609 ++++++------------ include/boost/unordered/unordered_map.hpp | 116 +--- include/boost/unordered/unordered_set.hpp | 115 +--- test/helpers/count.hpp | 7 - test/objects/exception.hpp | 2 +- test/objects/minimal.hpp | 2 +- test/objects/test.hpp | 2 +- test/unordered/compile_tests.hpp | 8 + test/unordered/unnecessary_copy_tests.cpp | 64 +- 12 files changed, 249 insertions(+), 721 deletions(-) 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() From b018f8b17330c19028dfbf14a7eb24ecca64d3d2 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 27 May 2009 21:31:08 +0000 Subject: [PATCH 028/100] Second try at merging emplace support. Note that the previously rolled back commit was [53257], not [52357]. Merged revisions 52393-52394,52397,52884-52885,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. ........ r53255 | danieljames | 2009-05-25 20:45:06 +0100 (Mon, 25 May 2009) | 1 line Unordered change log. ........ [SVN r53328] --- doc/changes.qbk | 10 + include/boost/unordered/detail/hash_table.hpp | 26 +- .../unordered/detail/hash_table_impl.hpp | 601 ++++++++++++------ include/boost/unordered/unordered_map.hpp | 104 ++- include/boost/unordered/unordered_set.hpp | 103 ++- test/helpers/count.hpp | 7 + test/unordered/compile_tests.hpp | 8 - test/unordered/unnecessary_copy_tests.cpp | 64 +- 8 files changed, 689 insertions(+), 234 deletions(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index 396eb887..a8b81eef 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -69,5 +69,15 @@ 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/hash_table.hpp b/include/boost/unordered/detail/hash_table.hpp index f64e3e83..bb4072c6 100644 --- a/include/boost/unordered/detail/hash_table.hpp +++ b/include/boost/unordered/detail/hash_table.hpp @@ -13,6 +13,10 @@ #include +#if !defined(BOOST_UNORDERED_EMPLACE_LIMIT) +#define BOOST_UNORDERED_EMPLACE_LIMIT 5 +#endif + #include #include #include @@ -28,8 +32,12 @@ #include #include #include +#include +#include #include #include +#include +#include #include #include #include @@ -37,11 +45,19 @@ #include -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) -#include -#include -#include -#include +#if !(defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)) + +#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) + #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 e7cdc5b9..81327302 100644 --- a/include/boost/unordered/detail/hash_table_impl.hpp +++ b/include/boost/unordered/detail/hash_table_impl.hpp @@ -181,56 +181,159 @@ 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_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) template void construct(Args&&... args) { - 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(std::forward(args)...); value_constructed_ = true; } -#else - template - void construct(V const& v) + +#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) { - 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); + 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 - template - void construct_pair(K const& k, M*) + void construct() { - 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()); + construct_preamble(); + new(node_->address()) value_type; 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 + node_ptr get() const { BOOST_ASSERT(node_); @@ -1427,8 +1530,29 @@ 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); @@ -1445,40 +1569,67 @@ namespace boost { { return v.first; } - -#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&...) + + // 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) { 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 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) + 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) { return v.first; } - template - static no_key extract_key(Args const&...) + // For maps if there is more than one argument, the key can be the first argument. + +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) + 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&...) { - return no_key(); + return k; } + +#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: @@ -1582,72 +1733,78 @@ namespace boost { #if BOOST_UNORDERED_EQUIVALENT_KEYS -#if !(defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)) - // Insert (equivalent key containers) +#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') // if hash function throws, basic exception safety // strong otherwise - iterator_base insert(value_type const& v) + template + iterator_base emplace(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(v); + a.construct(std::forward(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 // strong otherwise - iterator_base insert_hint(iterator_base const& it, value_type const& v) + template + iterator_base emplace_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(v); + a.construct(std::forward(args)...); - return insert_hint_impl(it, a); + return emplace_hint_impl(it, a); } #else - // 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); +#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_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); - } + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_INSERT_IMPL, _) +#undef BOOST_UNORDERED_INSERT_IMPL #endif - iterator_base insert_impl(node_constructor& a) + iterator_base emplace_impl(node_constructor& a) { key_type const& k = extract_key(a.get()->value()); 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 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 insert_impl(a); + 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) @@ -1707,7 +1864,7 @@ namespace boost { { size_type distance = unordered_detail::distance(i, j); if(distance == 1) { - insert(*i); + emplace(*i); } else { // Only require basic exception safety here @@ -1737,7 +1894,7 @@ namespace boost { { // If only inserting 1 element, get the required // safety since insert is only called once. - for (; i != j; ++i) insert(*i); + for (; i != j; ++i) emplace(*i); } public: @@ -1773,7 +1930,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_pair(k, (mapped_type*) 0); + a.construct(k); // reserve has basic exception safety if the hash function // throws, strong otherwise. @@ -1786,81 +1943,37 @@ 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 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. + // Emplace (unique keys) + // (I'm using an overloaded emplace for both 'insert' and 'emplace') // if hash function throws, basic exception safety // strong otherwise template - std::pair insert(Args&&... args) + std::pair emplace(Args&&... args) { - return insert_impl( + return emplace_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 - std::pair 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)...), + std::forward(args)...).first; + } + + template + std::pair emplace_impl(key_type const& k, Args&&... args) { // No side effects in this initial code size_type hash_value = hash_function()(k); @@ -1894,13 +2007,110 @@ namespace boost { } template - std::pair insert_impl(no_key, Args&&... args) + std::pair emplace_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); @@ -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 - 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 @@ -1963,6 +2160,13 @@ 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_); @@ -1992,6 +2196,36 @@ 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: @@ -2078,8 +2312,9 @@ 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 f787de2a..a7ebd691 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -224,25 +224,69 @@ namespace boost std::pair emplace(Args&&... args) { return boost::unordered_detail::pair_cast( - base.insert(std::forward(args)...)); + base.emplace(std::forward(args)...)); } template iterator emplace_hint(const_iterator hint, Args&&... args) { - return iterator(base.insert_hint(get(hint), std::forward(args)...)); + return iterator(base.emplace_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.insert(obj)); + base.emplace(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 @@ -630,24 +674,68 @@ namespace boost template iterator emplace(Args&&... args) { - return iterator(base.insert(std::forward(args)...)); + return iterator(base.emplace(std::forward(args)...)); } template iterator emplace_hint(const_iterator hint, Args&&... args) { - return iterator(base.insert_hint(get(hint), std::forward(args)...)); + return iterator(base.emplace_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.insert(obj)); + return iterator(base.emplace(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 diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 4e9f39bb..f39a76df 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -222,26 +222,70 @@ namespace boost std::pair emplace(Args&&... args) { return boost::unordered_detail::pair_cast( - base.insert(std::forward(args)...)); + base.emplace(std::forward(args)...)); } template iterator emplace_hint(const_iterator hint, Args&&... args) { return iterator( - base.insert_hint(get(hint), std::forward(args)...)); + base.emplace_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.insert(obj)); + base.emplace(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 @@ -599,24 +643,67 @@ namespace boost template iterator emplace(Args&&... args) { - return iterator(base.insert(std::forward(args)...)); + return iterator(base.emplace(std::forward(args)...)); } template iterator emplace_hint(const_iterator hint, Args&&... args) { - return iterator(base.insert_hint(get(hint), std::forward(args)...)); + return iterator(base.emplace_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.insert(obj)); + return iterator(base.emplace(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 diff --git a/test/helpers/count.hpp b/test/helpers/count.hpp index 11e00e9f..0589586e 100644 --- a/test/helpers/count.hpp +++ b/test/helpers/count.hpp @@ -6,6 +6,8 @@ #if !defined(BOOST_UNORDERED_TEST_HELPERS_COUNT_HEAD) #define BOOST_UNORDERED_TEST_HELPERS_COUNT_HEAD +#include + namespace test { struct object_count { int instances; @@ -36,6 +38,11 @@ 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/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index 486d3e2e..3dd00fdf 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -151,14 +151,12 @@ 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 @@ -175,9 +173,7 @@ 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 @@ -185,9 +181,7 @@ 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 @@ -289,9 +283,7 @@ 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 df4baf3c..3cf707ef 100644 --- a/test/unordered/unnecessary_copy_tests.cpp +++ b/test/unordered/unnecessary_copy_tests.cpp @@ -68,12 +68,22 @@ 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*) { @@ -117,9 +126,19 @@ 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*) { @@ -131,13 +150,11 @@ 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(); @@ -172,10 +189,12 @@ 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; @@ -192,8 +211,12 @@ 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); } @@ -230,24 +253,22 @@ namespace unnecessary_copy_tests x.emplace(source >()); COPY_COUNT(2); MOVE_COUNT(0); - count_copies part; - reset(); - std::pair a_ref(part, part); - x.emplace(a_ref); - COPY_COUNT(0); 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); +#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 @@ -267,10 +288,9 @@ namespace unnecessary_copy_tests COPY_COUNT(1); MOVE_COUNT(0); reset(); - x.emplace(b.first.tag_, b.second.tag_); - COPY_COUNT(2); MOVE_COUNT(0); + x.emplace(count_copies(b.first.tag_), count_copies(b.second.tag_)); + COPY_COUNT(2); MOVE_COUNT(0); } -#endif } RUN_TESTS() From ae09b0dd243e961e31f480e440973c366c89c4c3 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 30 May 2009 17:34:12 +0000 Subject: [PATCH 029/100] Merge latest changes for unordered. Improved compatability and a few tweaks. Merged revisions 53127,53253,53256,53311,53314,53316-53318 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r53127 | danieljames | 2009-05-20 07:43:38 +0100 (Wed, 20 May 2009) | 1 line Better configuration for boost.unordered. ........ r53253 | danieljames | 2009-05-25 20:14:07 +0100 (Mon, 25 May 2009) | 3 lines Add explicit destructors to the unordered containers. Refs #2908. Isn't really needed but it doesn't hurt. ........ r53256 | danieljames | 2009-05-25 20:45:23 +0100 (Mon, 25 May 2009) | 1 line Unordered change log for explicit destructors. ........ r53311 | danieljames | 2009-05-27 18:42:01 +0100 (Wed, 27 May 2009) | 1 line Missing changelog entry. ........ r53314 | danieljames | 2009-05-27 18:44:09 +0100 (Wed, 27 May 2009) | 1 line Use lightweight_test for unordered. ........ r53316 | danieljames | 2009-05-27 19:19:32 +0100 (Wed, 27 May 2009) | 1 line Some workarounds for old versions of Borland. ........ r53317 | danieljames | 2009-05-27 19:32:22 +0100 (Wed, 27 May 2009) | 1 line Fix a change accidentally included in the last commit. ........ r53318 | danieljames | 2009-05-27 19:32:38 +0100 (Wed, 27 May 2009) | 1 line Remove an unused function. ........ [SVN r53465] --- doc/changes.qbk | 3 + include/boost/unordered/detail/config.hpp | 8 ++ include/boost/unordered/detail/hash_table.hpp | 3 +- .../unordered/detail/hash_table_impl.hpp | 20 +-- include/boost/unordered/unordered_map.hpp | 26 +++- include/boost/unordered/unordered_set.hpp | 26 +++- test/exception/erase_exception_tests.cpp | 2 +- test/exception/insert_exception_tests.cpp | 16 +-- test/exception/swap_exception_tests.cpp | 4 +- test/helpers/exception_test.hpp | 26 ---- test/helpers/list.hpp | 4 +- test/helpers/memory.hpp | 18 +-- test/helpers/test.hpp | 15 +-- test/helpers/tracker.hpp | 4 +- test/objects/exception.hpp | 2 +- test/objects/minimal.hpp | 2 +- test/objects/test.hpp | 2 +- test/unordered/assign_tests.cpp | 22 +-- test/unordered/at_tests.cpp | 4 +- test/unordered/bucket_tests.cpp | 14 +- test/unordered/compile_tests.hpp | 10 +- test/unordered/constructor_tests.cpp | 126 +++++++++--------- test/unordered/copy_tests.cpp | 36 ++--- test/unordered/equality_tests.cpp | 42 +++--- test/unordered/erase_equiv_tests.cpp | 12 +- test/unordered/erase_tests.cpp | 44 +++--- test/unordered/find_tests.cpp | 20 +-- test/unordered/fwd_map_test.cpp | 16 +-- test/unordered/fwd_set_test.cpp | 22 +-- test/unordered/insert_stable_tests.cpp | 28 ++-- test/unordered/insert_tests.cpp | 36 ++--- test/unordered/load_factor_tests.cpp | 10 +- test/unordered/move_tests.cpp | 48 +++---- test/unordered/rehash_tests.cpp | 12 +- test/unordered/simple_tests.cpp | 46 +++---- 35 files changed, 363 insertions(+), 366 deletions(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index a8b81eef..956e0eae 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -79,5 +79,8 @@ First official release. 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. +* Better configuration for C++0x features when the headers aren't available. +* [@https://svn.boost.org/trac/boost/ticket/2908 Ticket 2908]: + Add explicit destructors to all containers. [endsect] diff --git a/include/boost/unordered/detail/config.hpp b/include/boost/unordered/detail/config.hpp index f277feae..68c9875a 100644 --- a/include/boost/unordered/detail/config.hpp +++ b/include/boost/unordered/detail/config.hpp @@ -19,4 +19,12 @@ # 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 bb4072c6..8a458f7f 100644 --- a/include/boost/unordered/detail/hash_table.hpp +++ b/include/boost/unordered/detail/hash_table.hpp @@ -12,6 +12,7 @@ #endif #include +#include #if !defined(BOOST_UNORDERED_EMPLACE_LIMIT) #define BOOST_UNORDERED_EMPLACE_LIMIT 5 @@ -45,7 +46,7 @@ #include -#if !(defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)) +#if !(defined(BOOST_UNORDERED_STD_FORWARD)) #include #include diff --git a/include/boost/unordered/detail/hash_table_impl.hpp b/include/boost/unordered/detail/hash_table_impl.hpp index 81327302..cee3e051 100644 --- a/include/boost/unordered/detail/hash_table_impl.hpp +++ b/include/boost/unordered/detail/hash_table_impl.hpp @@ -89,7 +89,7 @@ namespace boost { struct value_base { typename boost::aligned_storage< sizeof(value_type), - boost::alignment_of::value>::type data_; + ::boost::alignment_of::value>::type data_; void* address() { return this; } }; @@ -198,7 +198,7 @@ namespace boost { } } -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) +#if defined(BOOST_UNORDERED_STD_FORWARD) template void construct(Args&&... args) { @@ -257,13 +257,6 @@ namespace boost { #else - void construct() - { - construct_preamble(); - new(node_->address()) value_type; - value_constructed_ = true; - } - #define BOOST_UNORDERED_CONSTRUCT_IMPL(z, n, _) \ template < \ BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ @@ -292,8 +285,7 @@ namespace boost { new(node_->address()) value_type( \ BOOST_UNORDERED_CALL_PARAMS(z, n) \ ); \ - } \ - \ + } #define BOOST_UNORDERED_CONSTRUCT_IMPL2(z, n, _) \ template static BOOST_DEDUCED_TYPENAME boost::mpl::if_< @@ -1733,7 +1725,7 @@ namespace boost { #if BOOST_UNORDERED_EQUIVALENT_KEYS -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) +#if defined(BOOST_UNORDERED_STD_FORWARD) // Emplace (equivalent key containers) // (I'm using an overloaded emplace for both 'insert' and 'emplace') @@ -1943,7 +1935,7 @@ namespace boost { } } -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) +#if defined(BOOST_UNORDERED_STD_FORWARD) // Emplace (unique keys) // (I'm using an overloaded emplace for both 'insert' and 'emplace') diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index a7ebd691..d2793c56 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -21,6 +21,10 @@ #include #endif +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) +#include +#endif + #if defined(BOOST_MSVC) #pragma warning(push) #if BOOST_MSVC >= 1400 @@ -35,6 +39,9 @@ namespace boost template class unordered_map { +#if BOOST_WORKAROUND(__BORLANDC__, < 0x0582) + public: +#endif typedef boost::unordered_detail::hash_types_unique_keys< std::pair, Key, Hash, Pred, Alloc > implementation; @@ -104,6 +111,8 @@ namespace boost { } + ~unordered_map() {} + #if defined(BOOST_HAS_RVALUE_REFS) unordered_map(unordered_map&& other) : base(other.base, boost::unordered_detail::move_tag()) @@ -135,7 +144,7 @@ namespace boost #endif #endif -#if !defined(BOOST_NO_INITIALIZER_LISTS) +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) unordered_map(std::initializer_list list, size_type n = boost::unordered_detail::default_initial_bucket_count, const hasher &hf = hasher(), @@ -219,7 +228,7 @@ namespace boost // modifiers -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) +#if defined(BOOST_UNORDERED_STD_FORWARD) template std::pair emplace(Args&&... args) { @@ -455,7 +464,7 @@ namespace boost #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) friend bool operator==(unordered_map const&, unordered_map const&); friend bool operator!=(unordered_map const&, unordered_map const&); -#else +#elif !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) friend bool operator==(unordered_map const&, unordered_map const&); friend bool operator!=(unordered_map const&, unordered_map const&); #endif @@ -485,6 +494,9 @@ namespace boost template class unordered_multimap { +#if BOOST_WORKAROUND(__BORLANDC__, < 0x0582) + public: +#endif typedef boost::unordered_detail::hash_types_equivalent_keys< std::pair, Key, Hash, Pred, Alloc > implementation; @@ -554,6 +566,8 @@ namespace boost { } + ~unordered_multimap() {} + #if defined(BOOST_HAS_RVALUE_REFS) unordered_multimap(unordered_multimap&& other) : base(other.base, boost::unordered_detail::move_tag()) @@ -585,7 +599,7 @@ namespace boost #endif #endif -#if !defined(BOOST_NO_INITIALIZER_LISTS) +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) unordered_multimap(std::initializer_list list, size_type n = boost::unordered_detail::default_initial_bucket_count, const hasher &hf = hasher(), @@ -670,7 +684,7 @@ namespace boost // modifiers -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) +#if defined(BOOST_UNORDERED_STD_FORWARD) template iterator emplace(Args&&... args) { @@ -889,7 +903,7 @@ namespace boost #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) friend bool operator==(unordered_multimap const&, unordered_multimap const&); friend bool operator!=(unordered_multimap const&, unordered_multimap const&); -#else +#elif !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) friend bool operator==(unordered_multimap const&, unordered_multimap const&); friend bool operator!=(unordered_multimap const&, unordered_multimap const&); #endif diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index f39a76df..07ed746b 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -21,6 +21,10 @@ #include #endif +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) +#include +#endif + #if defined(BOOST_MSVC) #pragma warning(push) #if BOOST_MSVC >= 1400 @@ -35,6 +39,9 @@ namespace boost template class unordered_set { +#if BOOST_WORKAROUND(__BORLANDC__, < 0x0582) + public: +#endif typedef boost::unordered_detail::hash_types_unique_keys< Value, Value, Hash, Pred, Alloc > implementation; @@ -101,6 +108,8 @@ namespace boost : base(f, l, n, hf, eql, a) { } + + ~unordered_set() {} #if defined(BOOST_HAS_RVALUE_REFS) unordered_set(unordered_set&& other) @@ -133,7 +142,7 @@ namespace boost #endif #endif -#if !defined(BOOST_NO_INITIALIZER_LISTS) +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) unordered_set(std::initializer_list list, size_type n = boost::unordered_detail::default_initial_bucket_count, const hasher &hf = hasher(), @@ -217,7 +226,7 @@ namespace boost // modifiers -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) +#if defined(BOOST_UNORDERED_STD_FORWARD) template std::pair emplace(Args&&... args) { @@ -427,7 +436,7 @@ namespace boost #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) friend bool operator==(unordered_set const&, unordered_set const&); friend bool operator!=(unordered_set const&, unordered_set const&); -#else +#elif !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) friend bool operator==(unordered_set const&, unordered_set const&); friend bool operator!=(unordered_set const&, unordered_set const&); #endif @@ -457,6 +466,9 @@ namespace boost template class unordered_multiset { +#if BOOST_WORKAROUND(__BORLANDC__, < 0x0582) + public: +#endif typedef boost::unordered_detail::hash_types_equivalent_keys< Value, Value, Hash, Pred, Alloc > implementation; @@ -524,6 +536,8 @@ namespace boost { } + ~unordered_multiset() {} + #if defined(BOOST_HAS_RVALUE_REFS) unordered_multiset(unordered_multiset&& other) : base(other.base, boost::unordered_detail::move_tag()) @@ -555,7 +569,7 @@ namespace boost #endif #endif -#if !defined(BOOST_NO_INITIALIZER_LISTS) +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) unordered_multiset(std::initializer_list list, size_type n = boost::unordered_detail::default_initial_bucket_count, const hasher &hf = hasher(), @@ -639,7 +653,7 @@ namespace boost // modifiers -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) +#if defined(BOOST_UNORDERED_STD_FORWARD) template iterator emplace(Args&&... args) { @@ -845,7 +859,7 @@ namespace boost #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) friend bool operator==(unordered_multiset const&, unordered_multiset const&); friend bool operator!=(unordered_multiset const&, unordered_multiset const&); -#else +#elif !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) friend bool operator==(unordered_multiset const&, unordered_multiset const&); friend bool operator!=(unordered_multiset const&, unordered_multiset const&); #endif diff --git a/test/exception/erase_exception_tests.cpp b/test/exception/erase_exception_tests.cpp index 3f227263..6746d628 100644 --- a/test/exception/erase_exception_tests.cpp +++ b/test/exception/erase_exception_tests.cpp @@ -25,7 +25,7 @@ struct erase_test_base : public test::exception_base void check(T const& x) const { std::string scope(test::scope); - BOOST_CHECK(scope.find("hash::") != std::string::npos || + BOOST_TEST(scope.find("hash::") != std::string::npos || scope.find("equal_to::") != std::string::npos || scope == "operator==(object, object)"); diff --git a/test/exception/insert_exception_tests.cpp b/test/exception/insert_exception_tests.cpp index 8965e070..c44d56ba 100644 --- a/test/exception/insert_exception_tests.cpp +++ b/test/exception/insert_exception_tests.cpp @@ -128,10 +128,10 @@ struct insert_test_rehash1 : public insert_test_base size_type bucket_count = x.bucket_count(); size_type initial_elements = static_cast( ceil(bucket_count * (double) x.max_load_factor()) - 1); - BOOST_REQUIRE(initial_elements < this->values.size()); + BOOST_TEST(initial_elements < this->values.size()); x.insert(this->values.begin(), boost::next(this->values.begin(), initial_elements)); - BOOST_REQUIRE(bucket_count == x.bucket_count()); + BOOST_TEST(bucket_count == x.bucket_count()); return x; } @@ -150,7 +150,7 @@ struct insert_test_rehash1 : public insert_test_base // This isn't actually a failure, but it means the test isn't doing its // job. - BOOST_REQUIRE(x.bucket_count() != bucket_count); + BOOST_TEST(x.bucket_count() != bucket_count); } }; @@ -173,7 +173,7 @@ struct insert_test_rehash2 : public insert_test_rehash1 // This isn't actually a failure, but it means the test isn't doing its // job. - BOOST_REQUIRE(x.bucket_count() != bucket_count); + BOOST_TEST(x.bucket_count() != bucket_count); } }; @@ -197,10 +197,10 @@ struct insert_test_rehash3 : public insert_test_base size_type initial_elements = rehash_bucket_count - 5; - BOOST_REQUIRE(initial_elements < this->values.size()); + BOOST_TEST(initial_elements < this->values.size()); x.insert(this->values.begin(), boost::next(this->values.begin(), initial_elements)); - BOOST_REQUIRE(original_bucket_count == x.bucket_count()); + BOOST_TEST(original_bucket_count == x.bucket_count()); return x; } @@ -212,12 +212,12 @@ struct insert_test_rehash3 : public insert_test_base // This isn't actually a failure, but it means the test isn't doing its // job. - BOOST_REQUIRE(x.bucket_count() != bucket_count); + BOOST_TEST(x.bucket_count() != bucket_count); } void check(T const& x) const { if(x.size() < rehash_bucket_count) { - //BOOST_CHECK(x.bucket_count() == original_bucket_count); + //BOOST_TEST(x.bucket_count() == original_bucket_count); } test::check_equivalent_keys(x); } diff --git a/test/exception/swap_exception_tests.cpp b/test/exception/swap_exception_tests.cpp index 0e77e588..2025b8bd 100644 --- a/test/exception/swap_exception_tests.cpp +++ b/test/exception/swap_exception_tests.cpp @@ -22,7 +22,7 @@ struct self_swap_base : public test::exception_base std::string scope(test::scope); #if BOOST_UNORDERED_SWAP_METHOD != 2 - BOOST_CHECK( + BOOST_TEST( scope == "hash::operator(hash)" || scope == "hash::operator=(hash)" || scope == "equal_to::operator(equal_to)" || @@ -77,7 +77,7 @@ struct swap_base : public test::exception_base std::string scope(test::scope); #if BOOST_UNORDERED_SWAP_METHOD != 2 - BOOST_CHECK( + BOOST_TEST( scope == "hash::operator(hash)" || scope == "hash::operator=(hash)" || scope == "equal_to::operator(equal_to)" || diff --git a/test/helpers/exception_test.hpp b/test/helpers/exception_test.hpp index 699d5abb..a235526c 100644 --- a/test/helpers/exception_test.hpp +++ b/test/helpers/exception_test.hpp @@ -8,25 +8,10 @@ #include "./test.hpp" -#if defined(BOOST_UNORDERED_FULL_TEST) -# define BOOST_TEST_MAIN -# include -# include -#endif - #include #include #include -#if defined(BOOST_UNORDERED_FULL_TEST) -# define UNORDERED_EXCEPTION_TEST_CASE(name, test_func, type) \ - UNORDERED_AUTO_TEST(name) \ - { \ - test_func< type > fixture; \ - ::test::exception_safety(fixture, BOOST_STRINGIZE(test_func)); \ - } -# define UNORDERED_EPOINT_IMPL BOOST_ITEST_EPOINT -#else # define UNORDERED_EXCEPTION_TEST_CASE(name, test_func, type) \ UNORDERED_AUTO_TEST(name) \ { \ @@ -34,7 +19,6 @@ ::test::lightweight::exception_safety(fixture, BOOST_STRINGIZE(test_func)); \ } # define UNORDERED_EPOINT_IMPL ::test::lightweight::epoint -#endif #define UNORDERED_EXCEPTION_TEST_POSTFIX RUN_TESTS() @@ -178,16 +162,7 @@ namespace test { } } }; - - -#if defined(BOOST_UNORDERED_FULL_TEST) - template - void exception_safety(Test const& f, char const* name) { - test_runner runner(f); - ::boost::itest::exception_safety(runner, name); - } -#else // Quick exception testing based on lightweight test namespace lightweight { @@ -237,7 +212,6 @@ namespace test { } while(!success); } } -#endif } #endif diff --git a/test/helpers/list.hpp b/test/helpers/list.hpp index 5a3b6e83..f4985841 100644 --- a/test/helpers/list.hpp +++ b/test/helpers/list.hpp @@ -81,7 +81,7 @@ namespace test T* operator->() const { return &ptr_->value_; } list_iterator& operator++() { ptr_ = ptr_->next_; return *this; } - list_iterator& operator++(int) { + list_iterator operator++(int) { list_iterator tmp = *this; ptr_ = ptr_->next_; return tmp; } bool operator==(const_iterator y) const { return ptr_ == y.ptr_; } bool operator!=(const_iterator y) const { return ptr_ != y.ptr_; } @@ -108,7 +108,7 @@ namespace test T const* operator->() const { return &ptr_->value_; } list_const_iterator& operator++() { ptr_ = ptr_->next_; return *this; } - list_const_iterator& operator++(int) { + list_const_iterator operator++(int) { list_const_iterator tmp = *this; ptr_ = ptr_->next_; return tmp; } bool operator==(const_iterator y) const { return ptr_ == y.ptr_; } bool operator!=(const_iterator y) const { return ptr_ != y.ptr_; } diff --git a/test/helpers/memory.hpp b/test/helpers/memory.hpp index f4ac8a11..a37eccba 100644 --- a/test/helpers/memory.hpp +++ b/test/helpers/memory.hpp @@ -103,7 +103,7 @@ namespace test void allocator_unref() { - BOOST_CHECK(count_allocators > 0); + BOOST_TEST(count_allocators > 0); if(count_allocators > 0) { --count_allocators; if(count_allocators == 0) { @@ -116,9 +116,9 @@ namespace test count_constructions = 0; allocated_memory.clear(); - BOOST_CHECK(no_allocations_left); - BOOST_CHECK(no_constructions_left); - BOOST_CHECK(allocated_memory_empty); + BOOST_TEST(no_allocations_left); + BOOST_TEST(no_constructions_left); + BOOST_TEST(allocated_memory_empty); } } } @@ -144,12 +144,12 @@ namespace test if(pos == allocated_memory.end()) { BOOST_ERROR("Deallocating unknown pointer."); } else { - BOOST_CHECK(pos->first.start == ptr); - BOOST_CHECK(pos->first.end == (char*) ptr + n * size); - BOOST_CHECK(pos->second.tag_ == tag); + BOOST_TEST(pos->first.start == ptr); + BOOST_TEST(pos->first.end == (char*) ptr + n * size); + BOOST_TEST(pos->second.tag_ == tag); allocated_memory.erase(pos); } - BOOST_CHECK(count_allocations > 0); + BOOST_TEST(count_allocations > 0); if(count_allocations > 0) --count_allocations; } @@ -160,7 +160,7 @@ namespace test void track_destroy(void* /*ptr*/, std::size_t /*size*/, int /*tag*/) { - BOOST_CHECK(count_constructions > 0); + BOOST_TEST(count_constructions > 0); if(count_constructions > 0) --count_constructions; } }; diff --git a/test/helpers/test.hpp b/test/helpers/test.hpp index 136cf756..40b642b6 100644 --- a/test/helpers/test.hpp +++ b/test/helpers/test.hpp @@ -6,15 +6,7 @@ #if !defined(BOOST_UNORDERED_TEST_TEST_HEADER) #define BOOST_UNORDERED_TEST_TEST_HEADER -#if defined(BOOST_UNORDERED_FULL_TEST) - -#include -#define UNORDERED_AUTO_TEST(x) BOOST_AUTO_TEST_CASE(x) -#define RUN_TESTS() - -#else - -#include +#include #include #include #include @@ -30,7 +22,8 @@ }; \ BOOST_PP_CAT(x, _type) x; \ void BOOST_PP_CAT(x, _type)::run() -#define RUN_TESTS() int test_main(int, char**) { ::test::test_list::run_tests(); return 0; } +#define RUN_TESTS() int main(int, char**) \ + { ::test::test_list::run_tests(); return boost::report_errors(); } namespace test { struct registered_test_base { @@ -74,8 +67,6 @@ namespace test { } } -#endif - #include #include #include diff --git a/test/helpers/tracker.hpp b/test/helpers/tracker.hpp index 612f0edc..bf6417aa 100644 --- a/test/helpers/tracker.hpp +++ b/test/helpers/tracker.hpp @@ -49,7 +49,7 @@ namespace test value_list values2(x2.begin(), x2.end()); values1.sort(); values2.sort(); - BOOST_CHECK(values1.size() == values2.size() && + BOOST_TEST(values1.size() == values2.size() && std::equal(values1.begin(), values1.end(), values2.begin(), test::equivalent)); } @@ -61,7 +61,7 @@ namespace test test::list values2(x2.first, x2.second); values1.sort(); values2.sort(); - BOOST_CHECK(values1.size() == values2.size() && + BOOST_TEST(values1.size() == values2.size() && std::equal(values1.begin(), values1.end(), values2.begin(), test::equivalent)); } diff --git a/test/objects/exception.hpp b/test/objects/exception.hpp index 25f783ec..22119e85 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_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) +#if defined(BOOST_UNORDERED_STD_FORWARD) 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 535a7684..252e3564 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_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) +#if defined(BOOST_UNORDERED_STD_FORWARD) 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 28fc5e53..63f7c91b 100644 --- a/test/objects/test.hpp +++ b/test/objects/test.hpp @@ -218,7 +218,7 @@ namespace test new(p) T(t); } -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) +#if defined(BOOST_UNORDERED_STD_FORWARD) 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/assign_tests.cpp b/test/unordered/assign_tests.cpp index b2a4b1c3..09d64408 100644 --- a/test/unordered/assign_tests.cpp +++ b/test/unordered/assign_tests.cpp @@ -27,9 +27,9 @@ void assign_tests1(T*, test::random_generator generator = test::default_generato { T x; x = x; - BOOST_CHECK(x.empty()); - BOOST_CHECK(test::equivalent(x.hash_function(), hf)); - BOOST_CHECK(test::equivalent(x.key_eq(), eq)); + BOOST_TEST(x.empty()); + BOOST_TEST(test::equivalent(x.hash_function(), hf)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); } std::cerr<<"assign_tests1.2\n"; @@ -47,7 +47,7 @@ void assign_tests1(T*, test::random_generator generator = test::default_generato y.max_load_factor(x.max_load_factor() / 20); y = x; tracker.compare(y); - BOOST_CHECK(x.max_load_factor() == y.max_load_factor()); + BOOST_TEST(x.max_load_factor() == y.max_load_factor()); } } @@ -67,8 +67,8 @@ void assign_tests2(T*, test::random_generator generator = test::default_generato T x1(v.begin(), v.end(), 0, hf1, eq1); T x2(0, hf2, eq2); x2 = x1; - BOOST_CHECK(test::equivalent(x2.hash_function(), hf1)); - BOOST_CHECK(test::equivalent(x2.key_eq(), eq1)); + BOOST_TEST(test::equivalent(x2.hash_function(), hf1)); + BOOST_TEST(test::equivalent(x2.key_eq(), eq1)); test::check_container(x2, v); } @@ -78,9 +78,9 @@ void assign_tests2(T*, test::random_generator generator = test::default_generato T x1(v1.begin(), v1.end(), 0, hf1, eq1, al1); T x2(v2.begin(), v2.end(), 0, hf2, eq2, al2); x2 = x1; - BOOST_CHECK(test::equivalent(x2.hash_function(), hf1)); - BOOST_CHECK(test::equivalent(x2.key_eq(), eq1)); - BOOST_CHECK(test::equivalent(x2.get_allocator(), al2)); + BOOST_TEST(test::equivalent(x2.hash_function(), hf1)); + BOOST_TEST(test::equivalent(x2.key_eq(), eq1)); + BOOST_TEST(test::equivalent(x2.get_allocator(), al2)); test::check_container(x2, v1); } } @@ -113,8 +113,8 @@ UNORDERED_AUTO_TEST(assign_initializer_list) x.insert(10); x.insert(20); x = { 1, 2, -10 }; - BOOST_CHECK(x.find(10) == x.end()); - BOOST_CHECK(x.find(-10) != x.end()); + BOOST_TEST(x.find(10) == x.end()); + BOOST_TEST(x.find(-10) != x.end()); } #endif diff --git a/test/unordered/at_tests.cpp b/test/unordered/at_tests.cpp index 798bf9d4..ff9fdc81 100644 --- a/test/unordered/at_tests.cpp +++ b/test/unordered/at_tests.cpp @@ -16,8 +16,8 @@ UNORDERED_AUTO_TEST(at_tests) { x["one"] = 1; x["two"] = 2; - BOOST_CHECK(x.at("one") == 1); - BOOST_CHECK(x.at("two") == 2); + BOOST_TEST(x.at("one") == 1); + BOOST_TEST(x.at("two") == 2); try { x.at("three"); diff --git a/test/unordered/bucket_tests.cpp b/test/unordered/bucket_tests.cpp index e4326ed1..eeaa625a 100644 --- a/test/unordered/bucket_tests.cpp +++ b/test/unordered/bucket_tests.cpp @@ -24,7 +24,7 @@ void tests(X* = 0, test::random_generator generator = test::default_generator) X x(v.begin(), v.end()); - BOOST_CHECK(x.bucket_count() < x.max_bucket_count()); + BOOST_TEST(x.bucket_count() < x.max_bucket_count()); std::cerr<::const_iterator @@ -32,21 +32,21 @@ void tests(X* = 0, test::random_generator generator = test::default_generator) { size_type bucket = x.bucket(test::get_key(*it)); - BOOST_CHECK(bucket < x.bucket_count()); + BOOST_TEST(bucket < x.bucket_count()); if(bucket < x.max_bucket_count()) { // lit? lend?? I need a new naming scheme. const_local_iterator lit = x.begin(bucket), lend = x.end(bucket); while(lit != lend && test::get_key(*it) != test::get_key(*lit)) ++lit; - BOOST_CHECK(lit != lend); + BOOST_TEST(lit != lend); } } for(size_type i = 0; i < x.bucket_count(); ++i) { - BOOST_CHECK(x.bucket_size(i) == (size_type) std::distance(x.begin(i), x.end(i))); - BOOST_CHECK(x.bucket_size(i) == (size_type) std::distance(x.cbegin(i), x.cend(i))); + BOOST_TEST(x.bucket_size(i) == (size_type) std::distance(x.begin(i), x.end(i))); + BOOST_TEST(x.bucket_size(i) == (size_type) std::distance(x.cbegin(i), x.cend(i))); X const& x_ref = x; - BOOST_CHECK(x.bucket_size(i) == (size_type) std::distance(x_ref.begin(i), x_ref.end(i))); - BOOST_CHECK(x.bucket_size(i) == (size_type) std::distance(x_ref.cbegin(i), x_ref.cend(i))); + BOOST_TEST(x.bucket_size(i) == (size_type) std::distance(x_ref.begin(i), x_ref.end(i))); + BOOST_TEST(x.bucket_size(i) == (size_type) std::distance(x_ref.cbegin(i), x_ref.cend(i))); } } diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index 3dd00fdf..b657629b 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -87,10 +87,10 @@ void container_test(X& r, T const&) // I'm not sure about either of these tests... size_type max_diff((std::numeric_limits::max)()); difference_type converted_diff(max_diff); - BOOST_CHECK((std::numeric_limits::max)() + BOOST_TEST((std::numeric_limits::max)() == converted_diff); - BOOST_CHECK( + BOOST_TEST( static_cast( (std::numeric_limits::max)()) > static_cast( @@ -98,8 +98,8 @@ void container_test(X& r, T const&) // I don't test the runtime post-conditions here. X u; - BOOST_CHECK(u.size() == 0); - BOOST_CHECK(X().size() == 0); + BOOST_TEST(u.size() == 0); + BOOST_TEST(X().size() == 0); X a,b; @@ -288,7 +288,7 @@ void unordered_test(X&, Key& k, T& t, Hash& hf, Pred& eq) a.insert(i, j); test::check_return_type::equals(a.erase(k)); - BOOST_CHECK(a.empty()); + BOOST_TEST(a.empty()); if(a.empty()) { a.insert(t); q = a.cbegin(); diff --git a/test/unordered/constructor_tests.cpp b/test/unordered/constructor_tests.cpp index 231365a5..a2005cdc 100644 --- a/test/unordered/constructor_tests.cpp +++ b/test/unordered/constructor_tests.cpp @@ -29,42 +29,42 @@ void constructor_tests1(T*, test::random_generator generator = test::default_gen std::cerr<<"Construct 1\n"; { T x(0, hf, eq); - BOOST_CHECK(x.empty()); - BOOST_CHECK(test::equivalent(x.hash_function(), hf)); - BOOST_CHECK(test::equivalent(x.key_eq(), eq)); - BOOST_CHECK(test::equivalent(x.get_allocator(), al)); + BOOST_TEST(x.empty()); + BOOST_TEST(test::equivalent(x.hash_function(), hf)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + BOOST_TEST(test::equivalent(x.get_allocator(), al)); test::check_equivalent_keys(x); } std::cerr<<"Construct 2\n"; { T x(100, hf); - BOOST_CHECK(x.empty()); - BOOST_CHECK(x.bucket_count() >= 100); - BOOST_CHECK(test::equivalent(x.hash_function(), hf)); - BOOST_CHECK(test::equivalent(x.key_eq(), eq)); - BOOST_CHECK(test::equivalent(x.get_allocator(), al)); + BOOST_TEST(x.empty()); + BOOST_TEST(x.bucket_count() >= 100); + BOOST_TEST(test::equivalent(x.hash_function(), hf)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + BOOST_TEST(test::equivalent(x.get_allocator(), al)); test::check_equivalent_keys(x); } std::cerr<<"Construct 3\n"; { T x(2000); - BOOST_CHECK(x.empty()); - BOOST_CHECK(x.bucket_count() >= 2000); - BOOST_CHECK(test::equivalent(x.hash_function(), hf)); - BOOST_CHECK(test::equivalent(x.key_eq(), eq)); - BOOST_CHECK(test::equivalent(x.get_allocator(), al)); + BOOST_TEST(x.empty()); + BOOST_TEST(x.bucket_count() >= 2000); + BOOST_TEST(test::equivalent(x.hash_function(), hf)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + BOOST_TEST(test::equivalent(x.get_allocator(), al)); test::check_equivalent_keys(x); } std::cerr<<"Construct 4\n"; { T x; - BOOST_CHECK(x.empty()); - BOOST_CHECK(test::equivalent(x.hash_function(), hf)); - BOOST_CHECK(test::equivalent(x.key_eq(), eq)); - BOOST_CHECK(test::equivalent(x.get_allocator(), al)); + BOOST_TEST(x.empty()); + BOOST_TEST(test::equivalent(x.hash_function(), hf)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + BOOST_TEST(test::equivalent(x.get_allocator(), al)); test::check_equivalent_keys(x); } @@ -72,10 +72,10 @@ void constructor_tests1(T*, test::random_generator generator = test::default_gen { test::random_values v(1000, generator); T x(v.begin(), v.end(), 10000, hf, eq); - BOOST_CHECK(x.bucket_count() >= 10000); - BOOST_CHECK(test::equivalent(x.hash_function(), hf)); - BOOST_CHECK(test::equivalent(x.key_eq(), eq)); - BOOST_CHECK(test::equivalent(x.get_allocator(), al)); + BOOST_TEST(x.bucket_count() >= 10000); + BOOST_TEST(test::equivalent(x.hash_function(), hf)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + BOOST_TEST(test::equivalent(x.get_allocator(), al)); test::check_container(x, v); test::check_equivalent_keys(x); } @@ -84,10 +84,10 @@ void constructor_tests1(T*, test::random_generator generator = test::default_gen { test::random_values v(10, generator); T x(v.begin(), v.end(), 10000, hf); - BOOST_CHECK(x.bucket_count() >= 10000); - BOOST_CHECK(test::equivalent(x.hash_function(), hf)); - BOOST_CHECK(test::equivalent(x.key_eq(), eq)); - BOOST_CHECK(test::equivalent(x.get_allocator(), al)); + BOOST_TEST(x.bucket_count() >= 10000); + BOOST_TEST(test::equivalent(x.hash_function(), hf)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + BOOST_TEST(test::equivalent(x.get_allocator(), al)); test::check_container(x, v); test::check_equivalent_keys(x); } @@ -96,10 +96,10 @@ void constructor_tests1(T*, test::random_generator generator = test::default_gen { test::random_values v(100, generator); T x(v.begin(), v.end(), 100); - BOOST_CHECK(x.bucket_count() >= 100); - BOOST_CHECK(test::equivalent(x.hash_function(), hf)); - BOOST_CHECK(test::equivalent(x.key_eq(), eq)); - BOOST_CHECK(test::equivalent(x.get_allocator(), al)); + BOOST_TEST(x.bucket_count() >= 100); + BOOST_TEST(test::equivalent(x.hash_function(), hf)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + BOOST_TEST(test::equivalent(x.get_allocator(), al)); test::check_container(x, v); test::check_equivalent_keys(x); } @@ -108,9 +108,9 @@ void constructor_tests1(T*, test::random_generator generator = test::default_gen { test::random_values v(1, generator); T x(v.begin(), v.end()); - BOOST_CHECK(test::equivalent(x.hash_function(), hf)); - BOOST_CHECK(test::equivalent(x.key_eq(), eq)); - BOOST_CHECK(test::equivalent(x.get_allocator(), al)); + BOOST_TEST(test::equivalent(x.hash_function(), hf)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + BOOST_TEST(test::equivalent(x.get_allocator(), al)); test::check_container(x, v); test::check_equivalent_keys(x); } @@ -118,10 +118,10 @@ void constructor_tests1(T*, test::random_generator generator = test::default_gen std::cerr<<"Construct 9\n"; { T x(0, hf, eq, al); - BOOST_CHECK(x.empty()); - BOOST_CHECK(test::equivalent(x.hash_function(), hf)); - BOOST_CHECK(test::equivalent(x.key_eq(), eq)); - BOOST_CHECK(test::equivalent(x.get_allocator(), al)); + BOOST_TEST(x.empty()); + BOOST_TEST(test::equivalent(x.hash_function(), hf)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + BOOST_TEST(test::equivalent(x.get_allocator(), al)); test::check_equivalent_keys(x); } @@ -129,10 +129,10 @@ void constructor_tests1(T*, test::random_generator generator = test::default_gen { test::random_values v(1000, generator); T x(v.begin(), v.end(), 10000, hf, eq, al); - BOOST_CHECK(x.bucket_count() >= 10000); - BOOST_CHECK(test::equivalent(x.hash_function(), hf)); - BOOST_CHECK(test::equivalent(x.key_eq(), eq)); - BOOST_CHECK(test::equivalent(x.get_allocator(), al)); + BOOST_TEST(x.bucket_count() >= 10000); + BOOST_TEST(test::equivalent(x.hash_function(), hf)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + BOOST_TEST(test::equivalent(x.get_allocator(), al)); test::check_container(x, v); test::check_equivalent_keys(x); } @@ -141,10 +141,10 @@ void constructor_tests1(T*, test::random_generator generator = test::default_gen { test::random_values v(1000, generator); T x(al); - BOOST_CHECK(x.empty()); - BOOST_CHECK(test::equivalent(x.hash_function(), hf)); - BOOST_CHECK(test::equivalent(x.key_eq(), eq)); - BOOST_CHECK(test::equivalent(x.get_allocator(), al)); + BOOST_TEST(x.empty()); + BOOST_TEST(test::equivalent(x.hash_function(), hf)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + BOOST_TEST(test::equivalent(x.get_allocator(), al)); test::check_equivalent_keys(x); } } @@ -165,21 +165,21 @@ void constructor_tests2(T*, test::random_generator const& generator = test::defa std::cerr<<"Construct 1\n"; { T x(10000, hf1, eq1); - BOOST_CHECK(x.bucket_count() >= 10000); - BOOST_CHECK(test::equivalent(x.hash_function(), hf1)); - BOOST_CHECK(test::equivalent(x.key_eq(), eq1)); - BOOST_CHECK(test::equivalent(x.get_allocator(), al)); + BOOST_TEST(x.bucket_count() >= 10000); + BOOST_TEST(test::equivalent(x.hash_function(), hf1)); + BOOST_TEST(test::equivalent(x.key_eq(), eq1)); + BOOST_TEST(test::equivalent(x.get_allocator(), al)); test::check_equivalent_keys(x); } std::cerr<<"Construct 2\n"; { T x(100, hf1); - BOOST_CHECK(x.empty()); - BOOST_CHECK(x.bucket_count() >= 100); - BOOST_CHECK(test::equivalent(x.hash_function(), hf1)); - BOOST_CHECK(test::equivalent(x.key_eq(), eq)); - BOOST_CHECK(test::equivalent(x.get_allocator(), al)); + BOOST_TEST(x.empty()); + BOOST_TEST(x.bucket_count() >= 100); + BOOST_TEST(test::equivalent(x.hash_function(), hf1)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + BOOST_TEST(test::equivalent(x.get_allocator(), al)); test::check_equivalent_keys(x); } @@ -187,9 +187,9 @@ void constructor_tests2(T*, test::random_generator const& generator = test::defa { test::random_values v(100, generator); T x(v.begin(), v.end(), 0, hf1, eq1); - BOOST_CHECK(test::equivalent(x.hash_function(), hf1)); - BOOST_CHECK(test::equivalent(x.key_eq(), eq1)); - BOOST_CHECK(test::equivalent(x.get_allocator(), al)); + BOOST_TEST(test::equivalent(x.hash_function(), hf1)); + BOOST_TEST(test::equivalent(x.key_eq(), eq1)); + BOOST_TEST(test::equivalent(x.get_allocator(), al)); test::check_container(x, v); test::check_equivalent_keys(x); } @@ -198,10 +198,10 @@ void constructor_tests2(T*, test::random_generator const& generator = test::defa { test::random_values v(5, generator); T x(v.begin(), v.end(), 1000, hf1); - BOOST_CHECK(x.bucket_count() >= 1000); - BOOST_CHECK(test::equivalent(x.hash_function(), hf1)); - BOOST_CHECK(test::equivalent(x.key_eq(), eq)); - BOOST_CHECK(test::equivalent(x.get_allocator(), al)); + BOOST_TEST(x.bucket_count() >= 1000); + BOOST_TEST(test::equivalent(x.hash_function(), hf1)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + BOOST_TEST(test::equivalent(x.get_allocator(), al)); test::check_container(x, v); test::check_equivalent_keys(x); } @@ -293,8 +293,8 @@ UNORDERED_TEST(map_constructor_test, UNORDERED_AUTO_TEST(test_initializer_list) { std::cerr<<"Initializer List Tests\n"; boost::unordered_set x1 = { 2, 10, 45, -5 }; - BOOST_CHECK(x1.find(10) != x1.end()); - BOOST_CHECK(x1.find(46) == x1.end()); + BOOST_TEST(x1.find(10) != x1.end()); + BOOST_TEST(x1.find(46) == x1.end()); } #endif diff --git a/test/unordered/copy_tests.cpp b/test/unordered/copy_tests.cpp index b30df849..dc143bb8 100644 --- a/test/unordered/copy_tests.cpp +++ b/test/unordered/copy_tests.cpp @@ -27,11 +27,11 @@ void copy_construct_tests1(T*, test::random_generator const& generator = test::d { T x; T y(x); - BOOST_CHECK(y.empty()); - BOOST_CHECK(test::equivalent(y.hash_function(), hf)); - BOOST_CHECK(test::equivalent(y.key_eq(), eq)); - BOOST_CHECK(test::equivalent(y.get_allocator(), al)); - BOOST_CHECK(x.max_load_factor() == y.max_load_factor()); + BOOST_TEST(y.empty()); + BOOST_TEST(test::equivalent(y.hash_function(), hf)); + BOOST_TEST(test::equivalent(y.key_eq(), eq)); + BOOST_TEST(test::equivalent(y.get_allocator(), al)); + BOOST_TEST(x.max_load_factor() == y.max_load_factor()); test::check_equivalent_keys(y); } @@ -57,7 +57,7 @@ void copy_construct_tests1(T*, test::random_generator const& generator = test::d test::unordered_equivalence_tester equivalent(x); equivalent(y); // This isn't guaranteed: - BOOST_CHECK(y.load_factor() < y.max_load_factor()); + BOOST_TEST(y.load_factor() < y.max_load_factor()); test::check_equivalent_keys(y); } } @@ -75,22 +75,22 @@ void copy_construct_tests2(T* ptr, test::random_generator const& generator = tes { T x(10000, hf, eq, al); T y(x); - BOOST_CHECK(y.empty()); - BOOST_CHECK(test::equivalent(y.hash_function(), hf)); - BOOST_CHECK(test::equivalent(y.key_eq(), eq)); - BOOST_CHECK(test::equivalent(y.get_allocator(), al)); - BOOST_CHECK(x.max_load_factor() == y.max_load_factor()); + BOOST_TEST(y.empty()); + BOOST_TEST(test::equivalent(y.hash_function(), hf)); + BOOST_TEST(test::equivalent(y.key_eq(), eq)); + BOOST_TEST(test::equivalent(y.get_allocator(), al)); + BOOST_TEST(x.max_load_factor() == y.max_load_factor()); test::check_equivalent_keys(y); } { T x(1000, hf, eq, al); T y(x, al2); - BOOST_CHECK(y.empty()); - BOOST_CHECK(test::equivalent(y.hash_function(), hf)); - BOOST_CHECK(test::equivalent(y.key_eq(), eq)); - BOOST_CHECK(test::equivalent(y.get_allocator(), al2)); - BOOST_CHECK(x.max_load_factor() == y.max_load_factor()); + BOOST_TEST(y.empty()); + BOOST_TEST(test::equivalent(y.hash_function(), hf)); + BOOST_TEST(test::equivalent(y.key_eq(), eq)); + BOOST_TEST(test::equivalent(y.get_allocator(), al2)); + BOOST_TEST(x.max_load_factor() == y.max_load_factor()); test::check_equivalent_keys(y); } @@ -102,7 +102,7 @@ void copy_construct_tests2(T* ptr, test::random_generator const& generator = tes test::unordered_equivalence_tester equivalent(x); equivalent(y); test::check_equivalent_keys(y); - BOOST_CHECK(test::equivalent(y.get_allocator(), al)); + BOOST_TEST(test::equivalent(y.get_allocator(), al)); } { @@ -113,7 +113,7 @@ void copy_construct_tests2(T* ptr, test::random_generator const& generator = tes test::unordered_equivalence_tester equivalent(x); equivalent(y); test::check_equivalent_keys(y); - BOOST_CHECK(test::equivalent(y.get_allocator(), al2)); + BOOST_TEST(test::equivalent(y.get_allocator(), al2)); } } diff --git a/test/unordered/equality_tests.cpp b/test/unordered/equality_tests.cpp index 1679cf86..bfc78f1b 100644 --- a/test/unordered/equality_tests.cpp +++ b/test/unordered/equality_tests.cpp @@ -33,7 +33,7 @@ namespace equality_tests boost::unordered_set set1, set2; \ BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \ BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \ - BOOST_CHECK(set1 op set2); \ + BOOST_TEST(set1 op set2); \ } while(false) #define UNORDERED_EQUALITY_MULTISET_TEST(seq1, op, seq2) \ @@ -41,7 +41,7 @@ namespace equality_tests boost::unordered_multiset set1, set2; \ BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \ BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \ - BOOST_CHECK(set1 op set2); \ + BOOST_TEST(set1 op set2); \ } while(false) #define UNORDERED_EQUALITY_MAP_TEST(seq1, op, seq2) \ @@ -49,7 +49,7 @@ namespace equality_tests boost::unordered_map map1, map2; \ BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \ BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \ - BOOST_CHECK(map1 op map2); \ + BOOST_TEST(map1 op map2); \ } while(false) #define UNORDERED_EQUALITY_MULTIMAP_TEST(seq1, op, seq2) \ @@ -57,7 +57,7 @@ namespace equality_tests boost::unordered_multimap map1, map2; \ BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \ BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \ - BOOST_CHECK(map1 op map2); \ + BOOST_TEST(map1 op map2); \ } while(false) #define UNORDERED_SET_INSERT(r, set, item) set.insert(item); @@ -67,24 +67,24 @@ namespace equality_tests UNORDERED_AUTO_TEST(equality_size_tests) { boost::unordered_set x1, x2; - BOOST_CHECK(x1 == x2); - BOOST_CHECK(!(x1 != x2)); + BOOST_TEST(x1 == x2); + BOOST_TEST(!(x1 != x2)); x1.insert(1); - BOOST_CHECK(x1 != x2); - BOOST_CHECK(!(x1 == x2)); - BOOST_CHECK(x2 != x1); - BOOST_CHECK(!(x2 == x1)); + BOOST_TEST(x1 != x2); + BOOST_TEST(!(x1 == x2)); + BOOST_TEST(x2 != x1); + BOOST_TEST(!(x2 == x1)); x2.insert(1); - BOOST_CHECK(x1 == x2); - BOOST_CHECK(!(x1 != x2)); + BOOST_TEST(x1 == x2); + BOOST_TEST(!(x1 != x2)); x2.insert(2); - BOOST_CHECK(x1 != x2); - BOOST_CHECK(!(x1 == x2)); - BOOST_CHECK(x2 != x1); - BOOST_CHECK(!(x2 == x1)); + BOOST_TEST(x1 != x2); + BOOST_TEST(!(x1 == x2)); + BOOST_TEST(x2 != x1); + BOOST_TEST(!(x2 == x1)); } UNORDERED_AUTO_TEST(equality_key_value_tests) @@ -150,15 +150,15 @@ namespace equality_tests typedef boost::unordered_set set; set set1(0, mod_compare(false), mod_compare(false)); set set2(0, mod_compare(true), mod_compare(true)); - BOOST_CHECK(set1 == set2); + BOOST_TEST(set1 == set2); set1.insert(1); set2.insert(2); - BOOST_CHECK(set1 != set2); + BOOST_TEST(set1 != set2); set1.insert(2); set2.insert(1); - BOOST_CHECK(set1 == set2); + BOOST_TEST(set1 == set2); set1.insert(10); set2.insert(20); - BOOST_CHECK(set1 != set2); + BOOST_TEST(set1 != set2); set1.insert(20); set2.insert(10); - BOOST_CHECK(set1 == set2); + BOOST_TEST(set1 == set2); } } diff --git a/test/unordered/erase_equiv_tests.cpp b/test/unordered/erase_equiv_tests.cpp index 0bf7ab53..fbd56c27 100644 --- a/test/unordered/erase_equiv_tests.cpp +++ b/test/unordered/erase_equiv_tests.cpp @@ -67,11 +67,11 @@ UNORDERED_AUTO_TEST(single_item_tests) collide_map x(init.begin(), init.end()); x.erase(x.begin(), x.begin()); - BOOST_CHECK(x.count(1) == 1 && x.size() == 1); + BOOST_TEST(x.count(1) == 1 && x.size() == 1); x.erase(x.end(), x.end()); - BOOST_CHECK(x.count(1) == 1 && x.size() == 1); + BOOST_TEST(x.count(1) == 1 && x.size() == 1); x.erase(x.begin(), x.end()); - BOOST_CHECK(x.count(1) == 0 && x.size() == 0); + BOOST_TEST(x.count(1) == 0 && x.size() == 0); } UNORDERED_AUTO_TEST(two_equivalent_item_tests) @@ -83,14 +83,14 @@ UNORDERED_AUTO_TEST(two_equivalent_item_tests) { collide_map x(init.begin(), init.end()); x.erase(x.begin(), x.end()); - BOOST_CHECK(x.count(1) == 0 && x.size() == 0); + BOOST_TEST(x.count(1) == 0 && x.size() == 0); } { collide_map x(init.begin(), init.end()); int value = boost::next(x.begin())->second; x.erase(x.begin(), boost::next(x.begin())); - BOOST_CHECK(x.count(1) == 1 && x.size() == 1 && + BOOST_TEST(x.count(1) == 1 && x.size() == 1 && x.begin()->first == 1 && x.begin()->second == value); } @@ -98,7 +98,7 @@ UNORDERED_AUTO_TEST(two_equivalent_item_tests) collide_map x(init.begin(), init.end()); int value = x.begin()->second; x.erase(boost::next(x.begin()), x.end()); - BOOST_CHECK(x.count(1) == 1 && x.size() == 1 && + BOOST_TEST(x.count(1) == 1 && x.size() == 1 && x.begin()->first == 1 && x.begin()->second == value); } } diff --git a/test/unordered/erase_tests.cpp b/test/unordered/erase_tests.cpp index 74da3cf8..74fc6d1f 100644 --- a/test/unordered/erase_tests.cpp +++ b/test/unordered/erase_tests.cpp @@ -32,10 +32,10 @@ void erase_tests1(Container*, test::random_generator generator = test::default_g { std::size_t count = x.count(test::get_key(*it)); std::size_t old_size = x.size(); - BOOST_CHECK(count == x.erase(test::get_key(*it))); - BOOST_CHECK(x.size() == old_size - count); - BOOST_CHECK(x.count(test::get_key(*it)) == 0); - BOOST_CHECK(x.find(test::get_key(*it)) == x.end()); + BOOST_TEST(count == x.erase(test::get_key(*it))); + BOOST_TEST(x.size() == old_size - count); + BOOST_TEST(x.count(test::get_key(*it)) == 0); + BOOST_TEST(x.find(test::get_key(*it)) == x.end()); } } @@ -50,11 +50,11 @@ void erase_tests1(Container*, test::random_generator generator = test::default_g std::size_t count = x.count(key); BOOST_DEDUCED_TYPENAME Container::iterator pos = x.erase(x.begin()); --size; - BOOST_CHECK(pos == x.begin()); - BOOST_CHECK(x.count(key) == count - 1); - BOOST_CHECK(x.size() == size); + BOOST_TEST(pos == x.begin()); + BOOST_TEST(x.count(key) == count - 1); + BOOST_TEST(x.size() == size); } - BOOST_CHECK(x.empty()); + BOOST_TEST(x.empty()); } std::cerr<<"erase(random position).\n"; @@ -77,15 +77,15 @@ void erase_tests1(Container*, test::random_generator generator = test::default_g next = boost::next(pos); BOOST_DEDUCED_TYPENAME Container::key_type key = test::get_key(*pos); std::size_t count = x.count(key); - BOOST_CHECK(next == x.erase(pos)); + BOOST_TEST(next == x.erase(pos)); --size; if(size > 0) - BOOST_CHECK(index == 0 ? next == x.begin() : + BOOST_TEST(index == 0 ? next == x.begin() : next == boost::next(prev)); - BOOST_CHECK(x.count(key) == count - 1); - BOOST_CHECK(x.size() == size); + BOOST_TEST(x.count(key) == count - 1); + BOOST_TEST(x.size() == size); } - BOOST_CHECK(x.empty()); + BOOST_TEST(x.empty()); } std::cerr<<"erase(ranges).\n"; @@ -99,15 +99,15 @@ void erase_tests1(Container*, test::random_generator generator = test::default_g // returns 'the iterator immediately following the erase elements' // and if nothing is erased, then there's nothing to follow. But I // think this is the only sensible option... - BOOST_CHECK(x.erase(x.end(), x.end()) == x.end()); - BOOST_CHECK(x.erase(x.begin(), x.begin()) == x.begin()); - BOOST_CHECK(x.size() == size); + BOOST_TEST(x.erase(x.end(), x.end()) == x.end()); + BOOST_TEST(x.erase(x.begin(), x.begin()) == x.begin()); + BOOST_TEST(x.size() == size); - BOOST_CHECK(x.erase(x.begin(), x.end()) == x.end()); - BOOST_CHECK(x.empty()); - BOOST_CHECK(x.begin() == x.end()); + BOOST_TEST(x.erase(x.begin(), x.end()) == x.end()); + BOOST_TEST(x.empty()); + BOOST_TEST(x.begin() == x.end()); - BOOST_CHECK(x.erase(x.begin(), x.end()) == x.begin()); + BOOST_TEST(x.erase(x.begin(), x.end()) == x.begin()); } std::cerr<<"clear().\n"; @@ -115,8 +115,8 @@ void erase_tests1(Container*, test::random_generator generator = test::default_g test::random_values v(500, generator); Container x(v.begin(), v.end()); x.clear(); - BOOST_CHECK(x.empty()); - BOOST_CHECK(x.begin() == x.end()); + BOOST_TEST(x.empty()); + BOOST_TEST(x.begin() == x.end()); } std::cerr<<"\n"; diff --git a/test/unordered/find_tests.cpp b/test/unordered/find_tests.cpp index 77f6caeb..ad170a44 100644 --- a/test/unordered/find_tests.cpp +++ b/test/unordered/find_tests.cpp @@ -34,12 +34,12 @@ void find_tests1(X*, test::random_generator generator = test::default_generator) BOOST_DEDUCED_TYPENAME X::key_type key = test::get_key(*it1); iterator pos = x.find(key); BOOST_DEDUCED_TYPENAME X::const_iterator const_pos = x_const.find(key); - BOOST_CHECK(pos != x.end() && + BOOST_TEST(pos != x.end() && x.key_eq()(key, test::get_key(*pos))); - BOOST_CHECK(const_pos != x_const.end() && + BOOST_TEST(const_pos != x_const.end() && x_const.key_eq()(key, test::get_key(*const_pos))); - BOOST_CHECK(x.count(key) == tracker.count(key)); + BOOST_TEST(x.count(key) == tracker.count(key)); test::compare_pairs(x.equal_range(key), tracker.equal_range(key), @@ -56,11 +56,11 @@ void find_tests1(X*, test::random_generator generator = test::default_generator) BOOST_DEDUCED_TYPENAME X::key_type key = test::get_key(*it2); if(tracker.find(test::get_key(key)) == tracker.end()) { - BOOST_CHECK(x.find(key) == x.end()); - BOOST_CHECK(x_const.find(key) == x_const.end()); - BOOST_CHECK(x.count(key) == 0); + BOOST_TEST(x.find(key) == x.end()); + BOOST_TEST(x_const.find(key) == x_const.end()); + BOOST_TEST(x.count(key) == 0); std::pair range = x.equal_range(key); - BOOST_CHECK(range.first == range.second); + BOOST_TEST(range.first == range.second); } } } @@ -73,10 +73,10 @@ void find_tests1(X*, test::random_generator generator = test::default_generator) v2.begin(); it3 != v2.end(); ++it3) { BOOST_DEDUCED_TYPENAME X::key_type key = test::get_key(*it3); - BOOST_CHECK(x.find(key) == x.end()); - BOOST_CHECK(x.count(key) == 0); + BOOST_TEST(x.find(key) == x.end()); + BOOST_TEST(x.count(key) == 0); std::pair range = x.equal_range(key); - BOOST_CHECK(range.first == range.second); + BOOST_TEST(range.first == range.second); } } } diff --git a/test/unordered/fwd_map_test.cpp b/test/unordered/fwd_map_test.cpp index e5e905c2..831e54d4 100644 --- a/test/unordered/fwd_map_test.cpp +++ b/test/unordered/fwd_map_test.cpp @@ -42,21 +42,21 @@ UNORDERED_AUTO_TEST(use_map_fwd_declared_function) { y[2] = 1; call_swap(x, y); - BOOST_CHECK(y.find(1) != y.end() && y.find(1)->second == 2); - BOOST_CHECK(y.find(2) == y.end()); + BOOST_TEST(y.find(1) != y.end() && y.find(1)->second == 2); + BOOST_TEST(y.find(2) == y.end()); - BOOST_CHECK(x.find(1) == x.end()); - BOOST_CHECK(x.find(2) != x.end() && x.find(2)->second == 1); + BOOST_TEST(x.find(1) == x.end()); + BOOST_TEST(x.find(2) != x.end() && x.find(2)->second == 1); - BOOST_CHECK(!call_equals(x, y)); - BOOST_CHECK(call_not_equals(x, y)); + BOOST_TEST(!call_equals(x, y)); + BOOST_TEST(call_not_equals(x, y)); } UNORDERED_AUTO_TEST(use_multimap_fwd_declared_function) { int_multimap x, y; call_swap(x, y); - BOOST_CHECK(call_equals(x, y)); - BOOST_CHECK(!call_not_equals(x, y)); + BOOST_TEST(call_equals(x, y)); + BOOST_TEST(!call_not_equals(x, y)); } RUN_TESTS() diff --git a/test/unordered/fwd_set_test.cpp b/test/unordered/fwd_set_test.cpp index 9ea0c478..3db151a7 100644 --- a/test/unordered/fwd_set_test.cpp +++ b/test/unordered/fwd_set_test.cpp @@ -45,17 +45,17 @@ bool call_not_equals(int_multiset& x, int_multiset& y) { #include "../helpers/test.hpp" UNORDERED_AUTO_TEST(use_fwd_declared_trait_without_definition) { - BOOST_CHECK(sizeof(is_unordered_set_impl((int_set*) 0)) == sizeof(true_type)); + BOOST_TEST(sizeof(is_unordered_set_impl((int_set*) 0)) == sizeof(true_type)); } #include UNORDERED_AUTO_TEST(use_fwd_declared_trait) { boost::unordered_set x; - BOOST_CHECK(sizeof(is_unordered_set_impl(&x)) == sizeof(true_type)); + BOOST_TEST(sizeof(is_unordered_set_impl(&x)) == sizeof(true_type)); int dummy; - BOOST_CHECK(sizeof(is_unordered_set_impl(&dummy)) == sizeof(false_type)); + BOOST_TEST(sizeof(is_unordered_set_impl(&dummy)) == sizeof(false_type)); } UNORDERED_AUTO_TEST(use_set_fwd_declared_function) { @@ -64,21 +64,21 @@ UNORDERED_AUTO_TEST(use_set_fwd_declared_function) { y.insert(2); call_swap(x, y); - BOOST_CHECK(y.find(1) != y.end()); - BOOST_CHECK(y.find(2) == y.end()); + BOOST_TEST(y.find(1) != y.end()); + BOOST_TEST(y.find(2) == y.end()); - BOOST_CHECK(x.find(1) == x.end()); - BOOST_CHECK(x.find(2) != x.end()); + BOOST_TEST(x.find(1) == x.end()); + BOOST_TEST(x.find(2) != x.end()); - BOOST_CHECK(!call_equals(x, y)); - BOOST_CHECK(call_not_equals(x, y)); + BOOST_TEST(!call_equals(x, y)); + BOOST_TEST(call_not_equals(x, y)); } UNORDERED_AUTO_TEST(use_multiset_fwd_declared_function) { int_multiset x, y; call_swap(x, y); - BOOST_CHECK(call_equals(x, y)); - BOOST_CHECK(!call_not_equals(x, y)); + BOOST_TEST(call_equals(x, y)); + BOOST_TEST(!call_not_equals(x, y)); } RUN_TESTS() diff --git a/test/unordered/insert_stable_tests.cpp b/test/unordered/insert_stable_tests.cpp index 01ec3969..df38743e 100644 --- a/test/unordered/insert_stable_tests.cpp +++ b/test/unordered/insert_stable_tests.cpp @@ -47,13 +47,13 @@ UNORDERED_AUTO_TEST(stable_insert_test1) { x.insert(insert_stable::member(1,3)); boost::unordered_multiset::const_iterator it = x.begin(), end = x.end(); - BOOST_CHECK(it != end); - if(it != end) { BOOST_CHECK(it->tag2_ == 1); ++it; } - BOOST_CHECK(it != end); - if(it != end) { BOOST_CHECK(it->tag2_ == 2); ++it; } - BOOST_CHECK(it != end); - if(it != end) { BOOST_CHECK(it->tag2_ == 3); ++it; } - BOOST_CHECK(it == end); + BOOST_TEST(it != end); + if(it != end) { BOOST_TEST(it->tag2_ == 1); ++it; } + BOOST_TEST(it != end); + if(it != end) { BOOST_TEST(it->tag2_ == 2); ++it; } + BOOST_TEST(it != end); + if(it != end) { BOOST_TEST(it->tag2_ == 3); ++it; } + BOOST_TEST(it == end); } UNORDERED_AUTO_TEST(stable_insert_test2) { @@ -66,13 +66,13 @@ UNORDERED_AUTO_TEST(stable_insert_test2) { it = x.begin(); iterator end = x.end(); - BOOST_CHECK(it != end); - if(it != end) { BOOST_CHECK(it->first.tag2_ == 1 && it->second == 1); ++it; } - BOOST_CHECK(it != end); - if(it != end) { BOOST_CHECK(it->first.tag2_ == 2 && it->second == 2); ++it; } - BOOST_CHECK(it != end); - if(it != end) { BOOST_CHECK(it->first.tag2_ == 3 && it->second == 3); ++it; } - BOOST_CHECK(it == end); + BOOST_TEST(it != end); + if(it != end) { BOOST_TEST(it->first.tag2_ == 1 && it->second == 1); ++it; } + BOOST_TEST(it != end); + if(it != end) { BOOST_TEST(it->first.tag2_ == 2 && it->second == 2); ++it; } + BOOST_TEST(it != end); + if(it != end) { BOOST_TEST(it->first.tag2_ == 3 && it->second == 3); ++it; } + BOOST_TEST(it == end); } RUN_TESTS() diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 9434cba0..6a4f4d86 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -43,13 +43,13 @@ void unique_insert_tests1(X*, test::random_generator generator = test::default_g std::pair r1 = x.insert(*it); std::pair r2 = tracker.insert(*it); - BOOST_CHECK(r1.second == r2.second); - BOOST_CHECK(*r1.first == *r2.first); + BOOST_TEST(r1.second == r2.second); + BOOST_TEST(*r1.first == *r2.first); tracker.compare_key(x, *it); if(x.size() < b * old_bucket_count) - BOOST_CHECK(x.bucket_count() == old_bucket_count); + BOOST_TEST(x.bucket_count() == old_bucket_count); } test::check_equivalent_keys(x); @@ -73,12 +73,12 @@ void equivalent_insert_tests1(X*, test::random_generator generator = test::defau BOOST_DEDUCED_TYPENAME X::iterator r1 = x.insert(*it); BOOST_DEDUCED_TYPENAME test::ordered::iterator r2 = tracker.insert(*it); - BOOST_CHECK(*r1 == *r2); + BOOST_TEST(*r1 == *r2); tracker.compare_key(x, *it); if(x.size() < b * old_bucket_count) - BOOST_CHECK(x.bucket_count() == old_bucket_count); + BOOST_TEST(x.bucket_count() == old_bucket_count); } test::check_equivalent_keys(x); @@ -107,11 +107,11 @@ void insert_tests2(X*, test::random_generator generator = test::default_generato iterator r1 = x.insert(x.begin(), *it); tracker_iterator r2 = tracker.insert(tracker.begin(), *it); - BOOST_CHECK(*r1 == *r2); + BOOST_TEST(*r1 == *r2); tracker.compare_key(x, *it); if(x.size() < b * old_bucket_count) - BOOST_CHECK(x.bucket_count() == old_bucket_count); + BOOST_TEST(x.bucket_count() == old_bucket_count); } test::check_equivalent_keys(x); @@ -133,11 +133,11 @@ void insert_tests2(X*, test::random_generator generator = test::default_generato const_iterator r1 = x.insert(x_const.end(), *it); tracker_iterator r2 = tracker.insert(tracker.end(), *it); - BOOST_CHECK(*r1 == *r2); + BOOST_TEST(*r1 == *r2); tracker.compare_key(x, *it); if(x.size() < b * old_bucket_count) - BOOST_CHECK(x.bucket_count() == old_bucket_count); + BOOST_TEST(x.bucket_count() == old_bucket_count); } test::check_equivalent_keys(x); @@ -159,11 +159,11 @@ void insert_tests2(X*, test::random_generator generator = test::default_generato pos = x.insert(pos, *it); tracker_iterator r2 = tracker.insert(tracker.begin(), *it); - BOOST_CHECK(*pos == *r2); + BOOST_TEST(*pos == *r2); tracker.compare_key(x, *it); if(x.size() < b * old_bucket_count) - BOOST_CHECK(x.bucket_count() == old_bucket_count); + BOOST_TEST(x.bucket_count() == old_bucket_count); } test::check_equivalent_keys(x); @@ -187,7 +187,7 @@ void insert_tests2(X*, test::random_generator generator = test::default_generato tracker.compare_key(x, *it); if(x.size() < b * old_bucket_count) - BOOST_CHECK(x.bucket_count() == old_bucket_count); + BOOST_TEST(x.bucket_count() == old_bucket_count); } test::check_equivalent_keys(x); @@ -243,13 +243,13 @@ void unique_emplace_tests1(X*, test::random_generator generator = test::default_ std::pair r1 = x.emplace(*it); std::pair r2 = tracker.insert(*it); - BOOST_CHECK(r1.second == r2.second); - BOOST_CHECK(*r1.first == *r2.first); + BOOST_TEST(r1.second == r2.second); + BOOST_TEST(*r1.first == *r2.first); tracker.compare_key(x, *it); if(x.size() < b * old_bucket_count) - BOOST_CHECK(x.bucket_count() == old_bucket_count); + BOOST_TEST(x.bucket_count() == old_bucket_count); } test::check_equivalent_keys(x); @@ -273,12 +273,12 @@ void equivalent_emplace_tests1(X*, test::random_generator generator = test::defa BOOST_DEDUCED_TYPENAME X::iterator r1 = x.emplace(*it); BOOST_DEDUCED_TYPENAME test::ordered::iterator r2 = tracker.insert(*it); - BOOST_CHECK(*r1 == *r2); + BOOST_TEST(*r1 == *r2); tracker.compare_key(x, *it); if(x.size() < b * old_bucket_count) - BOOST_CHECK(x.bucket_count() == old_bucket_count); + BOOST_TEST(x.bucket_count() == old_bucket_count); } test::check_equivalent_keys(x); @@ -307,7 +307,7 @@ void map_tests(X*, test::random_generator generator = test::default_generator) tracker.compare_key(x, *it); if(x.size() < b * old_bucket_count) - BOOST_CHECK(x.bucket_count() == old_bucket_count); + BOOST_TEST(x.bucket_count() == old_bucket_count); } test::check_equivalent_keys(x); diff --git a/test/unordered/load_factor_tests.cpp b/test/unordered/load_factor_tests.cpp index b54f1d7a..8a2297c7 100644 --- a/test/unordered/load_factor_tests.cpp +++ b/test/unordered/load_factor_tests.cpp @@ -24,13 +24,13 @@ void set_load_factor_tests(X* = 0) { X x; - BOOST_CHECK(x.max_load_factor() == 1.0); - BOOST_CHECK(x.load_factor() == 0); + BOOST_TEST(x.max_load_factor() == 1.0); + BOOST_TEST(x.load_factor() == 0); // A valid implementation could fail these tests, but I think they're // reasonable. - x.max_load_factor(2.0); BOOST_CHECK(x.max_load_factor() == 2.0); - x.max_load_factor(0.5); BOOST_CHECK(x.max_load_factor() == 0.5); + x.max_load_factor(2.0); BOOST_TEST(x.max_load_factor() == 2.0); + x.max_load_factor(0.5); BOOST_TEST(x.max_load_factor() == 0.5); } template @@ -49,7 +49,7 @@ void insert_test(X*, float mlf, test::random_generator generator = test::default old_bucket_count = x.bucket_count(); x.insert(*it); if(old_size + 1 < b * old_bucket_count) - BOOST_CHECK(x.bucket_count() == old_bucket_count); + BOOST_TEST(x.bucket_count() == old_bucket_count); } } diff --git a/test/unordered/move_tests.cpp b/test/unordered/move_tests.cpp index c6e8c3c5..a78e6f8b 100644 --- a/test/unordered/move_tests.cpp +++ b/test/unordered/move_tests.cpp @@ -52,11 +52,11 @@ namespace move_tests { T y(empty(ptr)); - BOOST_CHECK(y.empty()); - BOOST_CHECK(test::equivalent(y.hash_function(), hf)); - BOOST_CHECK(test::equivalent(y.key_eq(), eq)); - BOOST_CHECK(test::equivalent(y.get_allocator(), al)); - BOOST_CHECK(y.max_load_factor() == 1.0); + BOOST_TEST(y.empty()); + BOOST_TEST(test::equivalent(y.hash_function(), hf)); + BOOST_TEST(test::equivalent(y.key_eq(), eq)); + BOOST_TEST(test::equivalent(y.get_allocator(), al)); + BOOST_TEST(y.max_load_factor() == 1.0); test::check_equivalent_keys(y); } @@ -64,7 +64,7 @@ namespace move_tests test::random_values v(1000, generator); test::object_count count; T y(create(v, count)); - BOOST_CHECK(count == test::global_object_count); + BOOST_TEST(count == test::global_object_count); test::check_container(y, v); test::check_equivalent_keys(y); } @@ -78,7 +78,7 @@ namespace move_tests test::object_count count; T y; y = create(v, count); - BOOST_CHECK(count == test::global_object_count); + BOOST_TEST(count == test::global_object_count); test::check_container(y, v); test::check_equivalent_keys(y); } @@ -98,12 +98,12 @@ namespace move_tests { test::random_values v(500, generator); T y(create(v, count, hf, eq, al, 0.5)); - BOOST_CHECK(count == test::global_object_count); + BOOST_TEST(count == test::global_object_count); test::check_container(y, v); - BOOST_CHECK(test::equivalent(y.hash_function(), hf)); - BOOST_CHECK(test::equivalent(y.key_eq(), eq)); - BOOST_CHECK(test::equivalent(y.get_allocator(), al)); - BOOST_CHECK(y.max_load_factor() == 0.5); // Not necessarily required. + BOOST_TEST(test::equivalent(y.hash_function(), hf)); + BOOST_TEST(test::equivalent(y.key_eq(), eq)); + BOOST_TEST(test::equivalent(y.get_allocator(), al)); + BOOST_TEST(y.max_load_factor() == 0.5); // Not necessarily required. test::check_equivalent_keys(y); } @@ -111,12 +111,12 @@ namespace move_tests // TODO: To do this correctly requires the fancy new allocator stuff. test::random_values v(500, generator); T y(create(v, count, hf, eq, al, 2.0), al2); - BOOST_CHECK(count != test::global_object_count); + BOOST_TEST(count != test::global_object_count); test::check_container(y, v); - BOOST_CHECK(test::equivalent(y.hash_function(), hf)); - BOOST_CHECK(test::equivalent(y.key_eq(), eq)); - BOOST_CHECK(test::equivalent(y.get_allocator(), al2)); - BOOST_CHECK(y.max_load_factor() == 2.0); // Not necessarily required. + BOOST_TEST(test::equivalent(y.hash_function(), hf)); + BOOST_TEST(test::equivalent(y.key_eq(), eq)); + BOOST_TEST(test::equivalent(y.get_allocator(), al2)); + BOOST_TEST(y.max_load_factor() == 2.0); // Not necessarily required. test::check_equivalent_keys(y); } @@ -124,17 +124,17 @@ namespace move_tests test::random_values v(25, generator); T y(create(v, count, hf, eq, al, 1.0), al); #if defined(BOOST_HAS_RVALUE_REFS) - BOOST_CHECK(count == test::global_object_count); + BOOST_TEST(count == test::global_object_count); #else - BOOST_CHECK(test::global_object_count.constructions - count.constructions <= + BOOST_TEST(test::global_object_count.constructions - count.constructions <= (test::is_map::value ? 50 : 25)); - BOOST_CHECK(count.instances == test::global_object_count.instances); + BOOST_TEST(count.instances == test::global_object_count.instances); #endif test::check_container(y, v); - BOOST_CHECK(test::equivalent(y.hash_function(), hf)); - BOOST_CHECK(test::equivalent(y.key_eq(), eq)); - BOOST_CHECK(test::equivalent(y.get_allocator(), al)); - BOOST_CHECK(y.max_load_factor() == 1.0); // Not necessarily required. + BOOST_TEST(test::equivalent(y.hash_function(), hf)); + BOOST_TEST(test::equivalent(y.key_eq(), eq)); + BOOST_TEST(test::equivalent(y.get_allocator(), al)); + BOOST_TEST(y.max_load_factor() == 1.0); // Not necessarily required. test::check_equivalent_keys(y); } } diff --git a/test/unordered/rehash_tests.cpp b/test/unordered/rehash_tests.cpp index e346a567..64608cb9 100644 --- a/test/unordered/rehash_tests.cpp +++ b/test/unordered/rehash_tests.cpp @@ -26,10 +26,10 @@ void rehash_empty_test1(X* = 0) X x; x.rehash(10000); - BOOST_CHECK(postcondition(x, 10000)); + BOOST_TEST(postcondition(x, 10000)); x.rehash(0); - BOOST_CHECK(postcondition(x, 0)); + BOOST_TEST(postcondition(x, 0)); } template @@ -40,18 +40,18 @@ void rehash_test1(X* = 0, test::random_generator generator = test::default_gener tracker.insert_range(v.begin(), v.end()); X x(v.begin(), v.end()); - x.rehash(0); BOOST_CHECK(postcondition(x, 0)); + x.rehash(0); BOOST_TEST(postcondition(x, 0)); tracker.compare(x); x.max_load_factor(0.25); - x.rehash(0); BOOST_CHECK(postcondition(x, 0)); + x.rehash(0); BOOST_TEST(postcondition(x, 0)); tracker.compare(x); x.max_load_factor(50.0); - x.rehash(0); BOOST_CHECK(postcondition(x, 0)); + x.rehash(0); BOOST_TEST(postcondition(x, 0)); tracker.compare(x); - x.rehash(1000); BOOST_CHECK(postcondition(x, 1000)); + x.rehash(1000); BOOST_TEST(postcondition(x, 1000)); tracker.compare(x); } diff --git a/test/unordered/simple_tests.cpp b/test/unordered/simple_tests.cpp index 09e48bfc..fab91746 100644 --- a/test/unordered/simple_tests.cpp +++ b/test/unordered/simple_tests.cpp @@ -19,67 +19,67 @@ void simple_test(X const& a) { X u; - BOOST_CHECK(u.size() == 0); - BOOST_CHECK(X().size() == 0); + BOOST_TEST(u.size() == 0); + BOOST_TEST(X().size() == 0); } { - BOOST_CHECK(equivalent(X(a))); + BOOST_TEST(equivalent(X(a))); } { X u(a); - BOOST_CHECK(equivalent(u)); + BOOST_TEST(equivalent(u)); } { X u = a; - BOOST_CHECK(equivalent(u)); + BOOST_TEST(equivalent(u)); } { X b(a); - BOOST_CHECK(b.begin() == const_cast(b).cbegin()); - BOOST_CHECK(b.end() == const_cast(b).cend()); + BOOST_TEST(b.begin() == const_cast(b).cbegin()); + BOOST_TEST(b.end() == const_cast(b).cend()); } { X b(a); X c; - BOOST_CHECK(equivalent(b)); - BOOST_CHECK(c.empty()); + BOOST_TEST(equivalent(b)); + BOOST_TEST(c.empty()); b.swap(c); - BOOST_CHECK(b.empty()); - BOOST_CHECK(equivalent(c)); + BOOST_TEST(b.empty()); + BOOST_TEST(equivalent(c)); b.swap(c); - BOOST_CHECK(c.empty()); - BOOST_CHECK(equivalent(b)); + BOOST_TEST(c.empty()); + BOOST_TEST(equivalent(b)); } { X u; X& r = u; - BOOST_CHECK(&(r = r) == &r); - BOOST_CHECK(r.empty()); - BOOST_CHECK(&(r = a) == &r); - BOOST_CHECK(equivalent(r)); - BOOST_CHECK(&(r = r) == &r); - BOOST_CHECK(equivalent(r)); + BOOST_TEST(&(r = r) == &r); + BOOST_TEST(r.empty()); + BOOST_TEST(&(r = a) == &r); + BOOST_TEST(equivalent(r)); + BOOST_TEST(&(r = r) == &r); + BOOST_TEST(equivalent(r)); } { - BOOST_CHECK(a.size() == + BOOST_TEST(a.size() == (BOOST_DEDUCED_TYPENAME X::size_type) std::distance(a.begin(), a.end())); } { - BOOST_CHECK(a.empty() == (a.size() == 0)); + BOOST_TEST(a.empty() == (a.size() == 0)); } { - BOOST_CHECK(a.empty() == (a.begin() == a.end())); + BOOST_TEST(a.empty() == (a.begin() == a.end())); X u; - BOOST_CHECK(u.begin() == u.end()); + BOOST_TEST(u.begin() == u.end()); } } From 9c435336552edd2ceefec6f61c209f575a071c0f Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 30 May 2009 17:41:05 +0000 Subject: [PATCH 030/100] A couple more minor unordered changes. Merged revisions 53312,53367 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r53312 | danieljames | 2009-05-27 18:43:22 +0100 (Wed, 27 May 2009) | 1 line Remove obsolete comment. ........ r53367 | danieljames | 2009-05-28 23:06:42 +0100 (Thu, 28 May 2009) | 1 line Remove a couple of old uses of BOOST_NO_INITIALIZER_LISTS. ........ [SVN r53466] --- test/helpers/memory.hpp | 5 ----- test/unordered/assign_tests.cpp | 2 +- test/unordered/constructor_tests.cpp | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/test/helpers/memory.hpp b/test/helpers/memory.hpp index a37eccba..6dbec85f 100644 --- a/test/helpers/memory.hpp +++ b/test/helpers/memory.hpp @@ -18,11 +18,6 @@ namespace test { namespace detail { - // This annoymous namespace won't cause ODR violations as I won't - // be linking multiple translation units together. I'll probably - // move this into a cpp file before a full release, but for now it's - // the most convenient way. - struct memory_area { void const* start; void const* end; diff --git a/test/unordered/assign_tests.cpp b/test/unordered/assign_tests.cpp index 09d64408..efe1c157 100644 --- a/test/unordered/assign_tests.cpp +++ b/test/unordered/assign_tests.cpp @@ -103,7 +103,7 @@ UNORDERED_TEST(assign_tests2, ((default_generator)(generate_collisions)) ) -#if !defined(BOOST_NO_INITIALIZER_LISTS) +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) UNORDERED_AUTO_TEST(assign_initializer_list) { diff --git a/test/unordered/constructor_tests.cpp b/test/unordered/constructor_tests.cpp index a2005cdc..1a73289f 100644 --- a/test/unordered/constructor_tests.cpp +++ b/test/unordered/constructor_tests.cpp @@ -288,7 +288,7 @@ UNORDERED_TEST(map_constructor_test, ((test_map)(test_multimap)) ) -#if !defined(BOOST_NO_INITIALIZER_LISTS) +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) UNORDERED_AUTO_TEST(test_initializer_list) { std::cerr<<"Initializer List Tests\n"; From 241316e0d96ab25f70f80dcfdfaa3ea9b14ac5ab Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 6 Jun 2009 14:05:54 +0000 Subject: [PATCH 031/100] Misc. unordered changes. Fixes #3082, #3119. Merged revisions 53505-53506,53525,53550,53552,53614 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r53505 | danieljames | 2009-05-31 16:50:56 +0100 (Sun, 31 May 2009) | 1 line Disable incorrect Visual C++ 64-bit warnings. Ref #3082. ........ r53506 | danieljames | 2009-05-31 16:53:09 +0100 (Sun, 31 May 2009) | 1 line Remove misplaced visual C++ warning pragma. ........ r53525 | danieljames | 2009-06-01 07:50:37 +0100 (Mon, 01 Jun 2009) | 1 line Fix tests for when the library has support for initializer lists but the compiler doesn't. ........ r53550 | danieljames | 2009-06-01 20:17:49 +0100 (Mon, 01 Jun 2009) | 1 line Get the type of the initializer_list right. ........ r53552 | danieljames | 2009-06-01 20:22:27 +0100 (Mon, 01 Jun 2009) | 1 line Fix the unordered_map declaration in the tutorial. Fixes #3119. ........ r53614 | danieljames | 2009-06-03 23:48:49 +0100 (Wed, 03 Jun 2009) | 1 line The move tests pass on 64 bit visual c++. ........ [SVN r53687] --- doc/hash_equality.qbk | 2 +- include/boost/unordered/detail/hash_table.hpp | 12 ++++++++++++ test/unordered/assign_tests.cpp | 15 +++++++++++++++ test/unordered/constructor_tests.cpp | 11 +++++++++++ 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/doc/hash_equality.qbk b/doc/hash_equality.qbk index 8fc08fb3..db1b0616 100644 --- a/doc/hash_equality.qbk +++ b/doc/hash_equality.qbk @@ -13,7 +13,7 @@ is declared as: class Key, class Mapped, class Hash = ``[classref boost::hash]``, class Pred = std::equal_to, - class Alloc = std::allocator > + class Alloc = std::allocator > > class ``[classref boost::unordered_map unordered_map]``; The hash function comes first as you might want to change the hash function diff --git a/include/boost/unordered/detail/hash_table.hpp b/include/boost/unordered/detail/hash_table.hpp index 8a458f7f..1609e955 100644 --- a/include/boost/unordered/detail/hash_table.hpp +++ b/include/boost/unordered/detail/hash_table.hpp @@ -61,6 +61,14 @@ #endif +#if defined(BOOST_MSVC) +#pragma warning(push) +#if BOOST_MSVC >= 1400 +#pragma warning(disable:4267) // conversion from 'size_t' to 'unsigned int', + // possible loss of data. +#endif +#endif + #if BOOST_WORKAROUND(__BORLANDC__, <= 0x0582) #define BOOST_UNORDERED_BORLAND_BOOL(x) (bool)(x) #else @@ -332,4 +340,8 @@ namespace boost { #undef BOOST_UNORDERED_BORLAND_BOOL #undef BOOST_UNORDERED_MSVC_RESET_PTR +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + #endif // BOOST_UNORDERED_DETAIL_HASH_TABLE_HPP_INCLUDED diff --git a/test/unordered/assign_tests.cpp b/test/unordered/assign_tests.cpp index efe1c157..56df1b20 100644 --- a/test/unordered/assign_tests.cpp +++ b/test/unordered/assign_tests.cpp @@ -105,6 +105,21 @@ UNORDERED_TEST(assign_tests2, #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) +UNORDERED_AUTO_TEST(assign_default_initializer_list) { + std::cerr<<"Initializer List Tests\n"; + std::initializer_list > init; + boost::unordered_map x1; + x1[25] = 3; + x1[16] = 10; + BOOST_TEST(!x1.empty()); + x1 = init; + BOOST_TEST(x1.empty()); +} + +#endif + +#if !defined(BOOST_NO_INITIALIZER_LISTS) + UNORDERED_AUTO_TEST(assign_initializer_list) { std::cerr<<"Initializer List Tests\n"; diff --git a/test/unordered/constructor_tests.cpp b/test/unordered/constructor_tests.cpp index 1a73289f..d5475b1f 100644 --- a/test/unordered/constructor_tests.cpp +++ b/test/unordered/constructor_tests.cpp @@ -290,6 +290,17 @@ UNORDERED_TEST(map_constructor_test, #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) +UNORDERED_AUTO_TEST(test_default_initializer_list) { + std::cerr<<"Initializer List Tests\n"; + std::initializer_list init; + boost::unordered_set x1 = init; + BOOST_TEST(x1.empty()); +} + +#endif + +#if !defined(BOOST_NO_INITIALIZER_LISTS) + UNORDERED_AUTO_TEST(test_initializer_list) { std::cerr<<"Initializer List Tests\n"; boost::unordered_set x1 = { 2, 10, 45, -5 }; From 60ecf12779c8c196e0ee7aa8a29a737b040ee24f Mon Sep 17 00:00:00 2001 From: "Troy D. Straszheim" Date: Wed, 22 Jul 2009 21:51:01 +0000 Subject: [PATCH 032/100] Add basic copyright/license to keep cmake out of the inspection report [SVN r55095] --- CMakeLists.txt | 6 ++++++ test/CMakeLists.txt | 6 ++++++ test/exception/CMakeLists.txt | 6 ++++++ test/unordered/CMakeLists.txt | 6 ++++++ 4 files changed, 24 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 59196994..b7dd577c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,9 @@ +# +# Copyright Troy D. Straszheim +# +# Distributed under the Boost Software License, Version 1.0. +# See http://www.boost.org/LICENSE_1_0.txt +# #---------------------------------------------------------------------------- # This file was automatically generated from the original CMakeLists.txt file # Add a variable to hold the headers for the library diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 51973cb0..a941b96f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,3 +1,9 @@ +# +# Copyright Troy D. Straszheim +# +# Distributed under the Boost Software License, Version 1.0. +# See http://www.boost.org/LICENSE_1_0.txt +# boost_additional_test_dependencies(unordered BOOST_DEPENDS test) # GCC Compilers diff --git a/test/exception/CMakeLists.txt b/test/exception/CMakeLists.txt index ec36ff62..aacdf3d9 100644 --- a/test/exception/CMakeLists.txt +++ b/test/exception/CMakeLists.txt @@ -1,3 +1,9 @@ +# +# Copyright Troy D. Straszheim +# +# Distributed under the Boost Software License, Version 1.0. +# See http://www.boost.org/LICENSE_1_0.txt +# foreach(test constructor_exception_tests diff --git a/test/unordered/CMakeLists.txt b/test/unordered/CMakeLists.txt index f3c58ad1..68d92be8 100644 --- a/test/unordered/CMakeLists.txt +++ b/test/unordered/CMakeLists.txt @@ -1,3 +1,9 @@ +# +# Copyright Troy D. Straszheim +# +# Distributed under the Boost Software License, Version 1.0. +# See http://www.boost.org/LICENSE_1_0.txt +# #------------------------------------------------------------------------------- # Unordered Tests foreach(test From 1bc3ae3d9dba1912de9f5120cbbac3fd4f8ee906 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 26 Jul 2009 20:22:48 +0000 Subject: [PATCH 033/100] Merge unordered changes, including fixes for Boost.TR1. Merged revisions 55099-55100,55132,55138,55184-55185 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r55099 | danieljames | 2009-07-22 23:37:52 +0100 (Wed, 22 Jul 2009) | 1 line Fix the insert tests when there is a small number of buckets. ........ r55100 | danieljames | 2009-07-22 23:38:08 +0100 (Wed, 22 Jul 2009) | 1 line Adjust the unordered defaults so that emplace takes more parameters and less buckets are created by default. ........ r55132 | danieljames | 2009-07-23 18:53:59 +0100 (Thu, 23 Jul 2009) | 1 line Remove the emulation of single argument C++0x std::pair constructor. ........ r55138 | danieljames | 2009-07-23 23:17:20 +0100 (Thu, 23 Jul 2009) | 1 line Try to work around an odd Visual C++ 8 bug. ........ r55184 | danieljames | 2009-07-26 19:59:33 +0100 (Sun, 26 Jul 2009) | 1 line Some extra changelog notes. ........ r55185 | danieljames | 2009-07-26 20:00:40 +0100 (Sun, 26 Jul 2009) | 1 line Update the reference documentation to mention that emplace is now emulated. ........ [SVN r55189] --- doc/changes.qbk | 9 ++- doc/ref.xml | 32 +++++++--- include/boost/unordered/detail/hash_table.hpp | 4 +- .../unordered/detail/hash_table_impl.hpp | 64 +++---------------- include/boost/unordered/unordered_map.hpp | 26 ++++++-- include/boost/unordered/unordered_set.hpp | 24 +++++-- test/exception/insert_exception_tests.cpp | 2 +- test/helpers/input_iterator.hpp | 19 +++++- 8 files changed, 101 insertions(+), 79 deletions(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index 956e0eae..418f1d90 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -79,8 +79,13 @@ First official release. 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. +* [@https://svn.boost.org/trac/boost/ticket/2908 Ticket 2908], + [@https://svn.boost.org/trac/boost/ticket/3096 Ticket 3096]: + Some workarounds for old versions of borland, including adding explicit + destructors to all containers. +* [@https://svn.boost.org/trac/boost/ticket/3082 Ticket 3082]: + Disable incorrect Visual C++ warnings. * Better configuration for C++0x features when the headers aren't available. -* [@https://svn.boost.org/trac/boost/ticket/2908 Ticket 2908]: - Add explicit destructors to all containers. +* Create less buckets by default. [endsect] diff --git a/doc/ref.xml b/doc/ref.xml index b1933659..2a3602dc 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -284,7 +284,9 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. Pointers and references to elements are never invalidated. - Only available on compilers with support for variadic template arguments and rvalue references. + If the compiler doesn't support variadic template arguments or rvalue + references, this is emulated for up to 10 arguments, with no support + for rvalue references or move semantics. @@ -313,7 +315,9 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 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. Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. Pointers and references to elements are never invalidated. - Only available on compilers with support for variadic template arguments and rvalue references. + If the compiler doesn't support variadic template arguments or rvalue + references, this is emulated for up to 10 arguments, with no support + for rvalue references or move semantics. @@ -1017,7 +1021,9 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. Pointers and references to elements are never invalidated. - Only available on compilers with support for variadic template arguments and rvalue references. + If the compiler doesn't support variadic template arguments or rvalue + references, this is emulated for up to 10 arguments, with no support + for rvalue references or move semantics. @@ -1046,7 +1052,9 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 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. Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. Pointers and references to elements are never invalidated. - Only available on compilers with support for variadic template arguments and rvalue references. + If the compiler doesn't support variadic template arguments or rvalue + references, this is emulated for up to 10 arguments, with no support + for rvalue references or move semantics. @@ -1762,7 +1770,9 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. Pointers and references to elements are never invalidated. - Only available on compilers with support for variadic template arguments and rvalue references. + If the compiler doesn't support variadic template arguments or rvalue + references, this is emulated for up to 10 arguments, with no support + for rvalue references or move semantics. @@ -1791,7 +1801,9 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 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. Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. Pointers and references to elements are never invalidated. - Only available on compilers with support for variadic template arguments and rvalue references. + If the compiler doesn't support variadic template arguments or rvalue + references, this is emulated for up to 10 arguments, with no support + for rvalue references or move semantics. @@ -2544,7 +2556,9 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. Pointers and references to elements are never invalidated. - Only available on compilers with support for variadic template arguments and rvalue references. + If the compiler doesn't support variadic template arguments or rvalue + references, this is emulated for up to 10 arguments, with no support + for rvalue references or move semantics. @@ -2573,7 +2587,9 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 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. Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. Pointers and references to elements are never invalidated. - Only available on compilers with support for variadic template arguments and rvalue references. + If the compiler doesn't support variadic template arguments or rvalue + references, this is emulated for up to 10 arguments, with no support + for rvalue references or move semantics. diff --git a/include/boost/unordered/detail/hash_table.hpp b/include/boost/unordered/detail/hash_table.hpp index 1609e955..2418b2a6 100644 --- a/include/boost/unordered/detail/hash_table.hpp +++ b/include/boost/unordered/detail/hash_table.hpp @@ -15,7 +15,7 @@ #include #if !defined(BOOST_UNORDERED_EMPLACE_LIMIT) -#define BOOST_UNORDERED_EMPLACE_LIMIT 5 +#define BOOST_UNORDERED_EMPLACE_LIMIT 10 #endif #include @@ -85,7 +85,7 @@ namespace boost { namespace unordered_detail { template struct type_wrapper {}; - static const std::size_t default_initial_bucket_count = 50; + static const std::size_t default_initial_bucket_count = 11; static const float minimum_max_load_factor = 1e-3f; inline std::size_t double_to_size_t(double f) diff --git a/include/boost/unordered/detail/hash_table_impl.hpp b/include/boost/unordered/detail/hash_table_impl.hpp index cee3e051..6bfe6580 100644 --- a/include/boost/unordered/detail/hash_table_impl.hpp +++ b/include/boost/unordered/detail/hash_table_impl.hpp @@ -206,55 +206,6 @@ namespace boost { 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 #define BOOST_UNORDERED_CONSTRUCT_IMPL(z, n, _) \ @@ -316,15 +267,16 @@ namespace boost { 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*) + { + construct_preamble(); + new(node_->address()) value_type(k, M()); + value_constructed_ = true; + } node_ptr get() const { @@ -1922,7 +1874,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. diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index d2793c56..b0658bad 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -105,8 +105,17 @@ namespace boost unordered_map(InputIterator f, InputIterator l, size_type n, const hasher &hf = hasher(), - const key_equal &eql = key_equal(), - const allocator_type &a = allocator_type()) + const key_equal &eql = key_equal()) + : base(f, l, n, hf, eql, allocator_type()) + { + } + + template + unordered_map(InputIterator f, InputIterator l, + size_type n, + const hasher &hf, + const key_equal &eql, + const allocator_type &a) : base(f, l, n, hf, eql, a) { } @@ -560,8 +569,17 @@ namespace boost unordered_multimap(InputIterator f, InputIterator l, size_type n, const hasher &hf = hasher(), - const key_equal &eql = key_equal(), - const allocator_type &a = allocator_type()) + const key_equal &eql = key_equal()) + : base(f, l, n, hf, eql, allocator_type()) + { + } + + template + unordered_multimap(InputIterator f, InputIterator l, + size_type n, + const hasher &hf, + const key_equal &eql, + const allocator_type &a) : base(f, l, n, hf, eql, a) { } diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 07ed746b..aecb54b4 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -103,8 +103,16 @@ namespace boost template unordered_set(InputIterator f, InputIterator l, size_type n, const hasher &hf = hasher(), - const key_equal &eql = key_equal(), - const allocator_type &a = allocator_type()) + const key_equal &eql = key_equal()) + : base(f, l, n, hf, eql, allocator_type()) + { + } + + template + unordered_set(InputIterator f, InputIterator l, size_type n, + const hasher &hf, + const key_equal &eql, + const allocator_type &a) : base(f, l, n, hf, eql, a) { } @@ -530,8 +538,16 @@ namespace boost template unordered_multiset(InputIterator f, InputIterator l, size_type n, const hasher &hf = hasher(), - const key_equal &eql = key_equal(), - const allocator_type &a = allocator_type()) + const key_equal &eql = key_equal()) + : base(f, l, n, hf, eql, allocator_type()) + { + } + + template + unordered_multiset(InputIterator f, InputIterator l, size_type n, + const hasher &hf, + const key_equal &eql, + const allocator_type &a) : base(f, l, n, hf, eql, a) { } diff --git a/test/exception/insert_exception_tests.cpp b/test/exception/insert_exception_tests.cpp index c44d56ba..acb47b48 100644 --- a/test/exception/insert_exception_tests.cpp +++ b/test/exception/insert_exception_tests.cpp @@ -195,7 +195,7 @@ struct insert_test_rehash3 : public insert_test_base rehash_bucket_count = static_cast( ceil(original_bucket_count * (double) x.max_load_factor())) - 1; - size_type initial_elements = rehash_bucket_count - 5; + size_type initial_elements = rehash_bucket_count > 5 ? rehash_bucket_count - 5 : 1; BOOST_TEST(initial_elements < this->values.size()); x.insert(this->values.begin(), diff --git a/test/helpers/input_iterator.hpp b/test/helpers/input_iterator.hpp index ec864b7e..d81d9fec 100644 --- a/test/helpers/input_iterator.hpp +++ b/test/helpers/input_iterator.hpp @@ -6,19 +6,34 @@ #if !defined(BOOST_UNORDERED_TEST_HELPERS_INPUT_ITERATOR_HEADER) #define BOOST_UNORDERED_TEST_HELPERS_INPUT_ITERATOR_HEADER +#include #include namespace test { + template + struct proxy + { + typedef BOOST_DEDUCED_TYPENAME Iterator::value_type value_type; + + proxy(value_type const& v) : v_(v) {} + proxy(proxy const& x) : v_(x.v_) {} + operator value_type const&() const { return v_; } + + value_type v_; + }; + template struct input_iterator_adaptor : boost::iterator_adaptor< input_iterator_adaptor, Iterator, - boost::use_default, std::input_iterator_tag> + boost::use_default, std::input_iterator_tag, + proxy > { typedef boost::iterator_adaptor< input_iterator_adaptor, Iterator, - boost::use_default, std::input_iterator_tag> base; + boost::use_default, std::input_iterator_tag, + proxy > base; explicit input_iterator_adaptor(Iterator it = Iterator()) : base(it) {} From df1dad5cb66ecec06bc4b81c6f3e7f655eeb6c14 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 27 Jul 2009 20:46:40 +0000 Subject: [PATCH 034/100] Merge an unordered documentation change that I missed before. Merged revisions 54914 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r54914 | danieljames | 2009-07-12 19:03:35 +0100 (Sun, 12 Jul 2009) | 1 line Add constructors to the methods for controlling bucket size in unordered containers. ........ [SVN r55211] --- doc/buckets.qbk | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/buckets.qbk b/doc/buckets.qbk index 92695ad0..1303708f 100644 --- a/doc/buckets.qbk +++ b/doc/buckets.qbk @@ -115,6 +115,15 @@ or close to the hint - unless your hint is unreasonably small or large. [table Methods for Controlling Bucket Size [[Method] [Description]] + [ + [`X(size_type n)`] + [Construct an empty container with at least `n` buckets (`X` is the container type).] + ] + [ + [`X(InputIterator i, InputIterator j, size_type n)`] + [Construct an empty container with at least `n` buckets and insert elements + from the range \[`i`, `j`) (`X` is the container type).] + ] [ [`float load_factor() const`] [The average number of elements per bucket.] From 1e7fe6a2d06dd735abe5da3b6f21e58cc90a81fa Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 24 Sep 2009 21:12:46 +0000 Subject: [PATCH 035/100] New version of Boost.Unordered Merged revisions 55470,55877-55878,55901-55902,55921-55922,55990-55992,56009-56010,56329,56346-56349,56362-56363,56374 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r55470 | danieljames | 2009-08-08 19:50:00 +0100 (Sat, 08 Aug 2009) | 1 line Remove empty svn:mergeinfo properties. This should reduce the amount of differences between trunk and release. ........ r55877 | danieljames | 2009-08-30 17:33:42 +0100 (Sun, 30 Aug 2009) | 1 line Remove allocator_constructor since it's never used. ........ r55878 | danieljames | 2009-08-30 17:42:28 +0100 (Sun, 30 Aug 2009) | 6 lines Initial checkin of new version of Boost.Unordered. - More template use, less preprocessor use. - Removed some of the Visual C++ 6 workarounds. - Reduced memory use of the main object. - Split into smaller headers. ........ r55901 | danieljames | 2009-08-31 11:39:25 +0100 (Mon, 31 Aug 2009) | 1 line Detab. ........ r55902 | danieljames | 2009-08-31 11:39:40 +0100 (Mon, 31 Aug 2009) | 1 line Remove unnecessary BOOST_DEDUCED_TYPENAMEs ........ r55921 | danieljames | 2009-08-31 16:33:28 +0100 (Mon, 31 Aug 2009) | 1 line Remove a few unused parameters. ........ r55922 | danieljames | 2009-08-31 16:33:49 +0100 (Mon, 31 Aug 2009) | 1 line Remove 'static' from next_node and node_count. Will hopefully make vacpp happy. ........ r55990 | danieljames | 2009-09-03 08:36:21 +0100 (Thu, 03 Sep 2009) | 1 line Combine hash_structure and hash_table_manager. ........ r55991 | danieljames | 2009-09-03 08:37:14 +0100 (Thu, 03 Sep 2009) | 1 line Remove some old Visual C++ workarounds. ........ r55992 | danieljames | 2009-09-03 08:37:30 +0100 (Thu, 03 Sep 2009) | 1 line Add a small test to see if the tested compilers support out of line template methods. ........ r56009 | danieljames | 2009-09-04 08:02:28 +0100 (Fri, 04 Sep 2009) | 1 line Fix link to n2691. ........ r56010 | danieljames | 2009-09-04 08:03:04 +0100 (Fri, 04 Sep 2009) | 1 line Move size_ and cached_begin_bucket_ into table, rename hash_table_manager hash_buckets. ........ r56329 | danieljames | 2009-09-20 22:55:15 +0100 (Sun, 20 Sep 2009) | 2 lines Since all the compilers support out of line template members use them and lots of other things. ........ r56346 | danieljames | 2009-09-21 22:17:19 +0100 (Mon, 21 Sep 2009) | 1 line Slightly more consistent variable names. In detail 'n' is now always a node pointer. ........ r56347 | danieljames | 2009-09-21 22:17:40 +0100 (Mon, 21 Sep 2009) | 1 line Fix bug where container was reducing the number of buckets. ........ r56348 | danieljames | 2009-09-21 22:18:01 +0100 (Mon, 21 Sep 2009) | 1 line Fix a bug that was causing unnecessary rehahes. ........ r56349 | danieljames | 2009-09-21 22:18:21 +0100 (Mon, 21 Sep 2009) | 1 line Use std::max. ........ r56362 | danieljames | 2009-09-22 23:39:00 +0100 (Tue, 22 Sep 2009) | 1 line Another std::max. ........ r56363 | danieljames | 2009-09-22 23:39:17 +0100 (Tue, 22 Sep 2009) | 1 line Remove the emplace_hint implementation for unique containers as it isn't really used and seems to be causing sun 5.7 problems. ........ r56374 | danieljames | 2009-09-24 21:42:19 +0100 (Thu, 24 Sep 2009) | 1 line Remove temporary test. ........ [SVN r56375] --- doc/ref.xml | 8 +- .../unordered/detail/allocator_helpers.hpp | 256 +- include/boost/unordered/detail/buckets.hpp | 177 ++ include/boost/unordered/detail/config.hpp | 30 - include/boost/unordered/detail/equivalent.hpp | 271 ++ .../boost/unordered/detail/extract_key.hpp | 171 ++ include/boost/unordered/detail/fwd.hpp | 987 +++++++ include/boost/unordered/detail/hash_table.hpp | 347 --- .../unordered/detail/hash_table_impl.hpp | 2527 ----------------- include/boost/unordered/detail/move.hpp | 19 +- include/boost/unordered/detail/node.hpp | 226 ++ include/boost/unordered/detail/table.hpp | 740 +++++ include/boost/unordered/detail/unique.hpp | 389 +++ include/boost/unordered/detail/util.hpp | 320 +++ include/boost/unordered/unordered_map.hpp | 904 +++--- include/boost/unordered/unordered_set.hpp | 865 +++--- test/Jamfile.v2 | 2 + test/helpers/list.hpp | 13 +- test/unordered/Jamfile.v2 | 1 + test/unordered/constructor_tests.cpp | 13 + test/unordered/copy_tests.cpp | 8 +- test/unordered/erase_equiv_tests.cpp | 2 +- test/unordered/move_tests.cpp | 4 +- test/unordered/simple_tests.cpp | 3 +- 24 files changed, 4341 insertions(+), 3942 deletions(-) create mode 100644 include/boost/unordered/detail/buckets.hpp delete mode 100644 include/boost/unordered/detail/config.hpp create mode 100644 include/boost/unordered/detail/equivalent.hpp create mode 100644 include/boost/unordered/detail/extract_key.hpp create mode 100644 include/boost/unordered/detail/fwd.hpp delete mode 100644 include/boost/unordered/detail/hash_table.hpp delete mode 100644 include/boost/unordered/detail/hash_table_impl.hpp create mode 100644 include/boost/unordered/detail/node.hpp create mode 100644 include/boost/unordered/detail/table.hpp create mode 100644 include/boost/unordered/detail/unique.hpp create mode 100644 include/boost/unordered/detail/util.hpp diff --git a/doc/ref.xml b/doc/ref.xml index 2a3602dc..67a2179b 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -24,7 +24,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) For the normative reference see chapter 23 of - the working draft of the C++ standard [n2691]. + the working draft of the C++ standard [n2691]. Template Parameters @@ -762,7 +762,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) For the normative reference see chapter 23 of - the working draft of the C++ standard [n2691]. + the working draft of the C++ standard [n2691]. Template Parameters @@ -1504,7 +1504,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) For the normative reference see chapter 23 of - the working draft of the C++ standard [n2691]. + the working draft of the C++ standard [n2691]. Template Parameters @@ -2291,7 +2291,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) For the normative reference see chapter 23 of - the working draft of the C++ standard [n2691]. + the working draft of the C++ standard [n2691]. Template Parameters diff --git a/include/boost/unordered/detail/allocator_helpers.hpp b/include/boost/unordered/detail/allocator_helpers.hpp index 0c0bd3a5..2c642231 100644 --- a/include/boost/unordered/detail/allocator_helpers.hpp +++ b/include/boost/unordered/detail/allocator_helpers.hpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// A couple of templates to make using allocators easier. + #ifndef BOOST_UNORDERED_DETAIL_ALLOCATOR_UTILITIES_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_ALLOCATOR_UTILITIES_HPP_INCLUDED @@ -21,214 +23,86 @@ # include #endif -#include +namespace boost { namespace unordered_detail { -namespace boost { - namespace unordered_detail { + // rebind_wrap + // + // Rebind allocators. For some problematic libraries, use rebind_to + // from . #if defined(BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES) - template - struct rebind_wrap : ::boost::detail::allocator::rebind_to {}; + template + struct rebind_wrap : ::boost::detail::allocator::rebind_to {}; #else - template - struct rebind_wrap - { - typedef BOOST_DEDUCED_TYPENAME - Alloc::BOOST_NESTED_TEMPLATE rebind::other - type; - }; + template + struct rebind_wrap + { + typedef BOOST_DEDUCED_TYPENAME + Alloc::BOOST_NESTED_TEMPLATE rebind::other + type; + }; #endif -#if !BOOST_WORKAROUND(BOOST_MSVC, < 1300) - template - inline void reset(T& x) { x = T(); } + // allocator_array_constructor + // + // Allocate and construct an array in an exception safe manner, and + // clean up if an exception is thrown before the container takes charge + // of it. - template - inline Ptr null_ptr() { return Ptr(); } -#else - template - inline void reset_impl(T& x, ...) { x = T(); } - template - inline void reset_impl(T*& x, int) { x = 0; } - template - inline void reset(T& x) { reset_impl(x); } + template + struct allocator_array_constructor + { + typedef BOOST_DEDUCED_TYPENAME Allocator::pointer pointer; - template - inline Ptr null_ptr() { Ptr x; reset(x); return x; } -#endif + Allocator& alloc_; + pointer ptr_; + pointer constructed_; + std::size_t length_; - // Work around for Microsoft's ETI bug. - - template struct allocator_value_type + allocator_array_constructor(Allocator& a) + : alloc_(a), ptr_(), constructed_(), length_(0) { - typedef BOOST_DEDUCED_TYPENAME Allocator::value_type type; - }; + constructed_ = pointer(); + ptr_ = pointer(); + } - template struct allocator_pointer - { - typedef BOOST_DEDUCED_TYPENAME Allocator::pointer type; - }; - - template struct allocator_const_pointer - { - typedef BOOST_DEDUCED_TYPENAME Allocator::const_pointer type; - }; - - template struct allocator_reference - { - typedef BOOST_DEDUCED_TYPENAME Allocator::reference type; - }; - - template struct allocator_const_reference - { - typedef BOOST_DEDUCED_TYPENAME Allocator::const_reference type; - }; - -#if defined(BOOST_MPL_CFG_MSVC_ETI_BUG) + ~allocator_array_constructor() { + if (ptr_) { + for(pointer p = ptr_; p != constructed_; ++p) + alloc_.destroy(p); - template <> - struct allocator_value_type - { - typedef int type; - }; - - template <> - struct allocator_pointer - { - typedef int type; - }; - - template <> - struct allocator_const_pointer - { - typedef int type; - }; - - template <> - struct allocator_reference - { - typedef int type; - }; - - template <> - struct allocator_const_reference - { - typedef int type; - }; - -#endif - - template - struct allocator_constructor - { - typedef BOOST_DEDUCED_TYPENAME allocator_value_type::type value_type; - typedef BOOST_DEDUCED_TYPENAME allocator_pointer::type pointer; - - Allocator& alloc_; - pointer ptr_; - bool constructed_; - - allocator_constructor(Allocator& a) - : alloc_(a), ptr_(), constructed_(false) - { -#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) - unordered_detail::reset(ptr_); -#endif + alloc_.deallocate(ptr_, length_); } + } - ~allocator_constructor() { - if(ptr_) { - if(constructed_) alloc_.destroy(ptr_); - alloc_.deallocate(ptr_, 1); - } - } - - template - void construct(V const& v) { - BOOST_ASSERT(!ptr_ && !constructed_); - ptr_ = alloc_.allocate(1); - alloc_.construct(ptr_, value_type(v)); - constructed_ = true; - } - - void construct(value_type const& v) { - BOOST_ASSERT(!ptr_ && !constructed_); - ptr_ = alloc_.allocate(1); - alloc_.construct(ptr_, v); - constructed_ = true; - } - - pointer get() const - { - return ptr_; - } - - // no throw - pointer release() - { - pointer p = ptr_; - constructed_ = false; - unordered_detail::reset(ptr_); - return p; - } - }; - - template - struct allocator_array_constructor + template + void construct(V const& v, std::size_t l) { - typedef BOOST_DEDUCED_TYPENAME allocator_pointer::type pointer; + BOOST_ASSERT(!ptr_); + length_ = l; + ptr_ = alloc_.allocate(length_); + pointer end = ptr_ + static_cast(length_); + for(constructed_ = ptr_; constructed_ != end; ++constructed_) + alloc_.construct(constructed_, v); + } - Allocator& alloc_; - pointer ptr_; - pointer constructed_; - std::size_t length_; + pointer get() const + { + return ptr_; + } - allocator_array_constructor(Allocator& a) - : alloc_(a), ptr_(), constructed_(), length_(0) - { -#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) - unordered_detail::reset(constructed_); - unordered_detail::reset(ptr_); -#endif - } - - ~allocator_array_constructor() { - if (ptr_) { - for(pointer p = ptr_; p != constructed_; ++p) - alloc_.destroy(p); - - alloc_.deallocate(ptr_, length_); - } - } - - template - void construct(V const& v, std::size_t l) - { - BOOST_ASSERT(!ptr_); - length_ = l; - ptr_ = alloc_.allocate(length_); - pointer end = ptr_ + static_cast(length_); - for(constructed_ = ptr_; constructed_ != end; ++constructed_) - alloc_.construct(constructed_, v); - } - - pointer get() const - { - return ptr_; - } - - pointer release() - { - pointer p(ptr_); - unordered_detail::reset(ptr_); - return p; - } - private: - allocator_array_constructor(allocator_array_constructor const&); - allocator_array_constructor& operator=(allocator_array_constructor const&); - }; - } -} + pointer release() + { + pointer p(ptr_); + ptr_ = pointer(); + return p; + } + private: + allocator_array_constructor(allocator_array_constructor const&); + allocator_array_constructor& operator=( + allocator_array_constructor const&); + }; +}} #if defined(BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES) # undef BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp new file mode 100644 index 00000000..8a2163c6 --- /dev/null +++ b/include/boost/unordered/detail/buckets.hpp @@ -0,0 +1,177 @@ + +// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. +// Copyright (C) 2005-2009 Daniel James +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED +#define BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED + +#include +#include +#include + +namespace boost { namespace unordered_detail { + + //////////////////////////////////////////////////////////////////////////// + // Buckets + // TODO: Are these needed? + + template + inline BOOST_DEDUCED_TYPENAME hash_buckets::bucket_ptr + hash_buckets::get_bucket(std::size_t num) const + { + return buckets_ + static_cast(num); + } + + template + inline BOOST_DEDUCED_TYPENAME hash_buckets::bucket_ptr + hash_buckets::bucket_ptr_from_hash(std::size_t hashed) const + { + return get_bucket(hashed % bucket_count_); + } + + template + inline std::size_t hash_buckets::bucket_size(std::size_t index) const + { + if(!buckets_) return 0; + bucket_ptr ptr = get_bucket(index)->next_; + std::size_t count = 0; + while(ptr) { + ++count; + ptr = ptr->next_; + } + return count; + } + + template + inline BOOST_DEDUCED_TYPENAME hash_buckets::node_ptr + hash_buckets::bucket_begin(std::size_t num) const + { + return buckets_ ? get_bucket(num)->next_ : node_ptr(); + } + + //////////////////////////////////////////////////////////////////////////// + // Delete + + template + inline void hash_buckets::delete_node(node_ptr b) + { + node* raw_ptr = static_cast(&*b); + boost::unordered_detail::destroy(&raw_ptr->value()); + real_node_ptr n(node_alloc().address(*raw_ptr)); + node_alloc().destroy(n); + node_alloc().deallocate(n, 1); + } + + template + inline void hash_buckets::clear_bucket(bucket_ptr b) + { + node_ptr node_it = b->next_; + b->next_ = node_ptr(); + + while(node_it) { + node_ptr node_to_delete = node_it; + node_it = node_it->next_; + delete_node(node_to_delete); + } + } + + template + inline void hash_buckets::delete_buckets() + { + bucket_ptr end = this->get_bucket(this->bucket_count_); + + for(bucket_ptr begin = this->buckets_; begin != end; ++begin) { + clear_bucket(begin); + } + + // Destroy the buckets (including the sentinel bucket). + ++end; + for(bucket_ptr begin = this->buckets_; begin != end; ++begin) { + bucket_alloc().destroy(begin); + } + + bucket_alloc().deallocate(this->buckets_, this->bucket_count_ + 1); + + this->buckets_ = bucket_ptr(); + } + + template + inline std::size_t hash_buckets::delete_nodes( + node_ptr begin, node_ptr end) + { + std::size_t count = 0; + while(begin != end) { + node_ptr n = begin; + begin = begin->next_; + delete_node(n); + ++count; + } + return count; + } + + //////////////////////////////////////////////////////////////////////////// + // Constructors and Destructors + + template + inline hash_buckets::hash_buckets( + node_allocator const& a, std::size_t bucket_count) + : buckets_(), + bucket_count_(bucket_count), + allocators_(a,a) + { + } + + template + inline hash_buckets::~hash_buckets() + { + if(this->buckets_) { this->delete_buckets(); } + } + + template + inline void hash_buckets::create_buckets() + { + // The array constructor will clean up in the event of an + // exception. + allocator_array_constructor + constructor(bucket_alloc()); + + // Creates an extra bucket to act as a sentinel. + constructor.construct(bucket(), this->bucket_count_ + 1); + + // Set up the sentinel (node_ptr cast) + bucket_ptr sentinel = constructor.get() + + static_cast(this->bucket_count_); + sentinel->next_ = sentinel; + + // Only release the buckets once everything is successfully + // done. + this->buckets_ = constructor.release(); + } + + //////////////////////////////////////////////////////////////////////////// + // Constructors and Destructors + + // no throw + template + inline void hash_buckets::move(hash_buckets& other) + { + BOOST_ASSERT(node_alloc() == other.node_alloc()); + if(this->buckets_) { this->delete_buckets(); } + this->buckets_ = other.buckets_; + this->bucket_count_ = other.bucket_count_; + other.buckets_ = bucket_ptr(); + other.bucket_count_ = 0; + } + + template + inline void hash_buckets::swap(hash_buckets& other) + { + BOOST_ASSERT(node_alloc() == other.node_alloc()); + std::swap(buckets_, other.buckets_); + std::swap(bucket_count_, other.bucket_count_); + } +}} + +#endif diff --git a/include/boost/unordered/detail/config.hpp b/include/boost/unordered/detail/config.hpp deleted file mode 100644 index 68c9875a..00000000 --- a/include/boost/unordered/detail/config.hpp +++ /dev/null @@ -1,30 +0,0 @@ - -// Copyright 2008-2009 Daniel James. -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#if !defined(BOOST_UNORDERED_DETAIL_CONFIG_HEADER) -#define BOOST_UNORDERED_DETAIL_CONFIG_HEADER - -#include - -#if defined(BOOST_NO_SFINAE) -# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN -#elif defined(__GNUC__) && \ - (__GNUC__ < 3 || __GNUC__ == 3 && __GNUC_MINOR__ <= 3) -# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN -#elif BOOST_WORKAROUND(BOOST_INTEL, < 900) || \ - BOOST_WORKAROUND(__EDG_VERSION__, < 304) || \ - BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0593)) -# 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/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp new file mode 100644 index 00000000..fa05019d --- /dev/null +++ b/include/boost/unordered/detail/equivalent.hpp @@ -0,0 +1,271 @@ + +// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. +// Copyright (C) 2005-2009 Daniel James +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED +#define BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED + +#include +#include + +namespace boost { namespace unordered_detail { + + //////////////////////////////////////////////////////////////////////////// + // Equality + + template + bool hash_equivalent_table + ::equals(hash_equivalent_table const& other) const + { + if(this->size_ != other.size_) return false; + if(!this->size_) return true; + + bucket_ptr end = this->get_bucket(this->bucket_count_); + for(bucket_ptr i = this->cached_begin_bucket_; i != end; ++i) + { + node_ptr it1 = i->next_; + while(BOOST_UNORDERED_BORLAND_BOOL(it1)) + { + node_ptr it2 = other.find_iterator(get_key_from_ptr(it1)); + if(!BOOST_UNORDERED_BORLAND_BOOL(it2)) return false; + + node_ptr end1 = node::next_group(it1); + node_ptr end2 = node::next_group(it2); + + do { + if(!extractor::compare_mapped( + node::get_value(it1), node::get_value(it2))) + return false; + it1 = it1->next_; + it2 = it2->next_; + } while(it1 != end1 && it2 != end2); + if(it1 != end1 || it2 != end2) return false; + } + } + + return true; + } + + //////////////////////////////////////////////////////////////////////////// + // A convenience method for adding nodes. + + template + inline BOOST_DEDUCED_TYPENAME hash_equivalent_table::node_ptr + hash_equivalent_table + ::add_node(node_constructor& a, bucket_ptr bucket, node_ptr pos) + { + node_ptr n = a.release(); + if(BOOST_UNORDERED_BORLAND_BOOL(pos)) { + node::add_after_node(n, pos); + } + else { + node::add_to_bucket(n, *bucket); + if(bucket < this->cached_begin_bucket_) + this->cached_begin_bucket_ = bucket; + } + ++this->size_; + return n; + } + + //////////////////////////////////////////////////////////////////////////// + // Insert methods + + template + inline BOOST_DEDUCED_TYPENAME + hash_equivalent_table::iterator_base + hash_equivalent_table::emplace_impl(node_constructor& a) + { + key_type const& k = get_key(a.value()); + std::size_t hash_value = this->hash_function()(k); + + if(!this->size_) { + return this->emplace_empty_impl_with_node(a, 1); + } + else { + bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); + node_ptr position = find_iterator(bucket, k); + + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + if(this->reserve_for_insert(this->size_ + 1)) + bucket = this->bucket_ptr_from_hash(hash_value); + + return iterator_base(bucket, add_node(a, bucket, position)); + } + } + + template + inline BOOST_DEDUCED_TYPENAME + hash_equivalent_table::iterator_base + hash_equivalent_table + ::emplace_hint_impl(iterator_base const& it, node_constructor& a) + { + // equal can throw, but with no effects + if (!it.node_ || !equal(get_key(a.value()), *it)) { + // 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 added at the end of the group. + + node_ptr start = node::first_in_group(it.node_); + + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + bucket_ptr bucket = this->reserve_for_insert(this->size_ + 1) ? + get_bucket(this->bucket_index(get_key(a.value()))) : + it.bucket_; + + // Nothing after this point can throw + + return iterator_base(bucket, add_node(a, bucket, start)); + } + } + + template + inline void hash_equivalent_table + ::emplace_impl_no_rehash(node_constructor& a) + { + key_type const& k = get_key(a.value()); + bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); + add_node(a, bucket, find_iterator(bucket, k)); + } + +#if defined(BOOST_UNORDERED_STD_FORWARD) + + // Emplace (equivalent key containers) + // (I'm using an overloaded emplace for both 'insert' and 'emplace') + + // if hash function throws, basic exception safety + // strong otherwise + template + template + BOOST_DEDUCED_TYPENAME hash_equivalent_table::iterator_base + hash_equivalent_table + ::emplace(Args&&... args) + { + // Create the node before rehashing in case it throws an + // exception (need strong safety in such a case). + node_constructor a(*this); + a.construct(std::forward(args)...); + + return emplace_impl(a); + } + + // Emplace (equivalent key containers) + // (I'm using an overloaded emplace for both 'insert' and 'emplace') + + // if hash function throws, basic exception safety + // strong otherwise + template + template + BOOST_DEDUCED_TYPENAME hash_equivalent_table::iterator_base + hash_equivalent_table + ::emplace_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(*this); + a.construct(std::forward(args)...); + + return emplace_hint_impl(it, a); + } + +#else + +#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \ + template \ + template \ + BOOST_DEDUCED_TYPENAME hash_equivalent_table::iterator_base \ + hash_equivalent_table \ + ::emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ + { \ + node_constructor a(*this); \ + a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ + return emplace_impl(a); \ + } \ + \ + template \ + template \ + BOOST_DEDUCED_TYPENAME hash_equivalent_table::iterator_base \ + hash_equivalent_table \ + ::emplace_hint(iterator_base const& it, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ + { \ + node_constructor a(*this); \ + a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ + return emplace_hint_impl(it, a); \ + } + + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_INSERT_IMPL, _) + +#undef BOOST_UNORDERED_INSERT_IMPL +#endif + + //////////////////////////////////////////////////////////////////////////// + // Insert range methods + + // if hash function throws, or inserting > 1 element, basic exception safety + // strong otherwise + template + template + inline void hash_equivalent_table + ::insert_for_range(I i, I j, forward_traversal_tag) + { + if(i == j) return; + std::size_t distance = unordered_detail::distance(i, j); + if(distance == 1) { + emplace(*i); + } + else { + node_constructor a(*this); + + // Only require basic exception safety here + if(this->size_) { + this->reserve_for_insert(this->size_ + distance); + } + else { + a.construct(*i++); + this->emplace_empty_impl_with_node(a, distance); + } + + for (; i != j; ++i) { + a.construct(*i); + emplace_impl_no_rehash(a); + } + } + } + + // if hash function throws, or inserting > 1 element, basic exception safety + // strong otherwise + template + template + inline void hash_equivalent_table + ::insert_for_range(I i, I j, boost::incrementable_traversal_tag) + { + node_constructor a(*this); + for (; i != j; ++i) { + a.construct(*i); + emplace_impl(a); + } + } + + // if hash function throws, or inserting > 1 element, basic exception safety + // strong otherwise + // TODO: Should I special case an empty container? + template + template + void hash_equivalent_table::insert_range(I i, I j) + { + BOOST_DEDUCED_TYPENAME boost::iterator_traversal::type + iterator_traversal_tag; + insert_for_range(i, j, iterator_traversal_tag); + } +}} + +#endif diff --git a/include/boost/unordered/detail/extract_key.hpp b/include/boost/unordered/detail/extract_key.hpp new file mode 100644 index 00000000..cba889eb --- /dev/null +++ b/include/boost/unordered/detail/extract_key.hpp @@ -0,0 +1,171 @@ + +// Copyright (C) 2005-2009 Daniel James +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_UNORDERED_DETAIL_EXTRACT_KEY_HPP_INCLUDED +#define BOOST_UNORDERED_DETAIL_EXTRACT_KEY_HPP_INCLUDED + +#include +#include +#include + +namespace boost { +namespace unordered_detail { + + // 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. This could be done by overloading the emplace implementation + // for the different cases, but that's a bit tricky on compilers without + // variadic templates. + + struct no_key { + no_key() {} + template no_key(T const&) {} + }; + + struct set_extractor + { + template + struct apply + { + typedef ValueType value_type; + typedef ValueType key_type; + + static key_type const& extract(key_type const& v) + { + return v; + } + + static no_key extract() + { + return no_key(); + } + + #if defined(BOOST_UNORDERED_STD_FORWARD) + template + static no_key extract(Args const&...) + { + return no_key(); + } + + #else + template + static no_key extract(Arg const&) + { + return no_key(); + } + + template + static no_key extract(Arg const&, Arg const&) + { + return no_key(); + } + #endif + + static bool compare_mapped(value_type const&, value_type const&) + { + return true; + } + }; + }; + + struct map_extractor + { + template + struct apply + { + typedef ValueType value_type; + typedef BOOST_DEDUCED_TYPENAME + remove_const::type + key_type; + + static key_type const& extract(value_type const& v) + { + return v.first; + } + + static key_type const& extract(key_type const& v) + { + return v; + } + + template + static key_type const& extract(std::pair const& v) + { + return v.first; + } + + template + static key_type const& extract( + std::pair const& v) + { + return v.first; + } +/* + template + static key_type const& extract( + std::pair const& v) + { + return v.first; + } + + template + static key_type const& extract( + std::pair const& v) + { + return v.first; + } +*/ + +#if defined(BOOST_UNORDERED_STD_FORWARD) + template + static key_type const& extract(key_type const& k, + Arg1 const&, Args const&...) + { + return k; + } + + template + static no_key extract(Args const&...) + { + return no_key(); + } +#else + template + static key_type const& extract(key_type const& k, Arg1 const&) + { + return k; + } + + static no_key extract() + { + return no_key(); + } + + template + static no_key extract(Arg const&) + { + return no_key(); + } + + template + static no_key extract(Arg const&, Arg1 const&) + { + return no_key(); + } +#endif + + static bool compare_mapped(value_type const& x, value_type const& y) + { + return x.second == y.second; + } + }; + }; +}} + +#endif diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp new file mode 100644 index 00000000..39f85427 --- /dev/null +++ b/include/boost/unordered/detail/fwd.hpp @@ -0,0 +1,987 @@ + +// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. +// Copyright (C) 2005-2009 Daniel James +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// This contains the basic data structure, apart from the actual values. There's +// no construction or deconstruction here. So this only depends on the pointer +// type. + +#ifndef BOOST_UNORDERED_DETAIL_FWD_HPP_INCLUDED +#define BOOST_UNORDERED_DETAIL_FWD_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include + +// This header defines most of the classes used to implement the unordered +// containers. It doesn't include the insert methods as they require a lot +// of preprocessor metaprogramming - they are in insert.hpp + +// Template parameters: +// +// H = Hash Function +// P = Predicate +// A = Value Allocator +// G = Grouped/Ungrouped +// K = Key Extractor + +#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 + +#if !defined(BOOST_UNORDERED_EMPLACE_LIMIT) +#define BOOST_UNORDERED_EMPLACE_LIMIT 10 +#endif + +#if !defined(BOOST_UNORDERED_STD_FORWARD) + +#include +#include +#include + +#define BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \ + BOOST_PP_ENUM_PARAMS_Z(z, num_params, class Arg) +#define BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \ + BOOST_PP_ENUM_BINARY_PARAMS_Z(z, num_params, Arg, const& arg) +#define BOOST_UNORDERED_CALL_PARAMS(z, num_params) \ + BOOST_PP_ENUM_PARAMS_Z(z, num_params, arg) + +#endif + +namespace boost { namespace unordered_detail { + + static const float minimum_max_load_factor = 1e-3f; + static const std::size_t default_bucket_count = 11; + struct move_tag {}; + + template + class hash_node_constructor; + struct set_extractor; + struct map_extractor; + struct no_key; + + // Explicitly call a destructor + +#if defined(BOOST_MSVC) +#pragma warning(push) +#if BOOST_MSVC >= 1400 +#pragma warning(disable:4100) // unreferenced formal parameter +#endif +#endif + + template + inline void destroy(T* x) { + x->~T(); + } + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + + // hash_bucket + + template + class hash_bucket + { + hash_bucket& operator=(hash_bucket const&); + public: + typedef hash_bucket bucket; + typedef BOOST_DEDUCED_TYPENAME + boost::unordered_detail::rebind_wrap::type + bucket_allocator; + typedef BOOST_DEDUCED_TYPENAME bucket_allocator::pointer bucket_ptr; + typedef bucket_ptr node_ptr; + + node_ptr next_; + + hash_bucket() : next_() {} + + // Only copy construct when allocating. + hash_bucket(hash_bucket const& x) + : next_() + { + BOOST_ASSERT(!x.next_); + } + }; + + template + struct ungrouped_node_base : hash_bucket { + typedef hash_bucket bucket; + typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr; + typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr; + + ungrouped_node_base() : bucket() {} + static inline node_ptr& next_group(node_ptr ptr); + static inline std::size_t group_count(node_ptr ptr); + static inline void add_to_bucket(node_ptr n, bucket& b); + static inline void add_after_node(node_ptr n, node_ptr position); + static void unlink_node(bucket& b, node_ptr n); + static void unlink_nodes(bucket& b, node_ptr begin, node_ptr end); + static void unlink_nodes(bucket& b, node_ptr end); + }; + + template + struct grouped_node_base : hash_bucket + { + typedef hash_bucket bucket; + typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr; + typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr; + + node_ptr group_prev_; + + grouped_node_base() : bucket(), group_prev_() {} + static inline node_ptr& next_group(node_ptr ptr); + static inline node_ptr first_in_group(node_ptr n); + static inline std::size_t group_count(node_ptr ptr); + static inline void add_to_bucket(node_ptr n, bucket& b); + static inline void add_after_node(node_ptr n, node_ptr position); + static void unlink_node(bucket& b, node_ptr n); + static void unlink_nodes(bucket& b, node_ptr begin, node_ptr end); + static void unlink_nodes(bucket& b, node_ptr end); + + private: + static inline node_ptr split_group(node_ptr split); + static inline grouped_node_base& get(node_ptr ptr) { + return static_cast(*ptr); + } + }; + + struct ungrouped + { + template + struct base { + typedef ungrouped_node_base type; + }; + }; + + struct grouped + { + template + struct base { + typedef grouped_node_base type; + }; + }; + + template + struct value_base + { + typedef ValueType value_type; + BOOST_DEDUCED_TYPENAME boost::aligned_storage< + sizeof(value_type), + ::boost::alignment_of::value>::type data_; + + void* address() { + return this; + } + value_type& value() { + return *(ValueType*) this; + } + }; + + // Node + + template + class hash_node : + public G::BOOST_NESTED_TEMPLATE base::type, + public value_base + { + public: + typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; + typedef BOOST_DEDUCED_TYPENAME hash_bucket::node_ptr node_ptr; + + static value_type& get_value(node_ptr p) { + return static_cast(*p).value(); + } + }; + + // Iterator Base + + template + class hash_iterator_base + { + public: + typedef A value_allocator; + typedef hash_bucket bucket; + typedef hash_node node; + typedef BOOST_DEDUCED_TYPENAME node::value_type value_type; + typedef BOOST_DEDUCED_TYPENAME node::bucket_ptr bucket_ptr; + typedef BOOST_DEDUCED_TYPENAME node::node_ptr node_ptr; + + bucket_ptr bucket_; + node_ptr node_; + + hash_iterator_base() : bucket_(), node_() {} + explicit hash_iterator_base(bucket_ptr b) + : bucket_(b), + node_(b ? b->next_ : node_ptr()) {} + hash_iterator_base(bucket_ptr b, node_ptr n) + : bucket_(b), + node_(n) {} + + bool operator==(hash_iterator_base const& x) const { + return node_ == x.node_; } + bool operator!=(hash_iterator_base const& x) const { + return node_ != x.node_; } + value_type& operator*() const { + return node::get_value(node_); + } + + void increment_bucket(node_ptr n) { + while(!n) { + ++bucket_; + n = bucket_->next_; + } + node_ = bucket_ == n ? node_ptr() : n; + } + + void increment() { + increment_bucket(node_->next_); + } + }; + + // hash_buckets + // + // This is responsible for allocating and deallocating buckets and nodes. + // + // Notes: + // 1. For the sake exception safety the allocators themselves don't allocate + // anything. + // 2. It's the callers responsibility to allocate the buckets before calling + // any of the methods (other than getters and setters). + + template + class hash_buckets + { + hash_buckets(hash_buckets const&); + hash_buckets& operator=(hash_buckets const&); + public: + // Types + + typedef A value_allocator; + typedef hash_bucket bucket; + typedef hash_iterator_base iterator_base; + typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; + typedef BOOST_DEDUCED_TYPENAME iterator_base::node node; + + typedef BOOST_DEDUCED_TYPENAME node::bucket_allocator bucket_allocator; + typedef BOOST_DEDUCED_TYPENAME node::bucket_ptr bucket_ptr; + typedef BOOST_DEDUCED_TYPENAME node::node_ptr node_ptr; + + typedef BOOST_DEDUCED_TYPENAME rebind_wrap::type + node_allocator; + typedef BOOST_DEDUCED_TYPENAME node_allocator::pointer real_node_ptr; + + // Members + + bucket_ptr buckets_; + std::size_t bucket_count_; + boost::compressed_pair allocators_; + + // Data access + + bucket_allocator const& bucket_alloc() const { + return allocators_.first(); } + node_allocator const& node_alloc() const { + return allocators_.second(); } + bucket_allocator& bucket_alloc() { + return allocators_.first(); } + node_allocator& node_alloc() { + return allocators_.second(); } + std::size_t max_bucket_count() const { + // -1 to account for the sentinel. + return prev_prime(this->bucket_alloc().max_size() - 1); + } + + // Constructors + + hash_buckets(node_allocator const& a, std::size_t n); + void create_buckets(); + ~hash_buckets(); + + // no throw + void swap(hash_buckets& other); + void move(hash_buckets& other); + + // For the remaining functions, buckets_ must not be null. + + bucket_ptr get_bucket(std::size_t n) const; + bucket_ptr bucket_ptr_from_hash(std::size_t hashed) const; + std::size_t bucket_size(std::size_t index) const; + node_ptr bucket_begin(std::size_t n) const; + + // Alloc/Dealloc + + void delete_node(node_ptr); + + // + void delete_buckets(); + void clear_bucket(bucket_ptr); + std::size_t delete_nodes(node_ptr begin, node_ptr end); + std::size_t delete_to_bucket_end(node_ptr begin); + }; + + template class set_hash_functions; + + template + class hash_buffered_functions + { + friend class set_hash_functions; + hash_buffered_functions& operator=(hash_buffered_functions const&); + + typedef boost::compressed_pair function_pair; + typedef BOOST_DEDUCED_TYPENAME boost::aligned_storage< + sizeof(function_pair), + ::boost::alignment_of::value>::type aligned_function; + + bool current_; // The currently active functions. + aligned_function funcs_[2]; + + function_pair const& current() const { + return *static_cast( + static_cast(&funcs_[current_])); + } + + void construct(bool which, H const& hf, P const& eq) + { + new((void*) &funcs_[which]) function_pair(hf, eq); + } + + void construct(bool which, function_pair const& f) + { + new((void*) &funcs_[which]) function_pair(f); + } + + void destroy(bool which) + { + boost::unordered_detail::destroy((function_pair*)(&funcs_[which])); + } + + public: + + hash_buffered_functions(H const& hf, P const& eq) + : current_(false) + { + construct(current_, hf, eq); + } + + hash_buffered_functions(hash_buffered_functions const& bf) + : current_(false) + { + construct(current_, bf.current()); + } + + ~hash_buffered_functions() { + destroy(current_); + } + + H const& hash_function() const { + return current().first(); + } + + P const& key_eq() const { + return current().second(); + } + }; + + template + class set_hash_functions + { + set_hash_functions(set_hash_functions const&); + set_hash_functions& operator=(set_hash_functions const&); + + typedef hash_buffered_functions buffered_functions; + buffered_functions& buffered_functions_; + bool tmp_functions_; + + public: + + set_hash_functions(buffered_functions& f, H const& h, P const& p) + : buffered_functions_(f), + tmp_functions_(!f.current_) + { + f.construct(tmp_functions_, h, p); + } + + set_hash_functions(buffered_functions& f, + buffered_functions const& other) + : buffered_functions_(f), + tmp_functions_(!f.current_) + { + f.construct(tmp_functions_, other.current()); + } + + ~set_hash_functions() + { + buffered_functions_.destroy(tmp_functions_); + } + + void commit() + { + buffered_functions_.current_ = tmp_functions_; + tmp_functions_ = !tmp_functions_; + } + }; + + template + class hash_table : + public hash_buckets, + public hash_buffered_functions + { + hash_table(hash_table const&); + public: + typedef H hasher; + typedef P key_equal; + typedef A value_allocator; + typedef G grouped; + typedef K key_extractor; + typedef hash_buffered_functions base; + typedef hash_buckets buckets; + + typedef BOOST_DEDUCED_TYPENAME value_allocator::value_type value_type; + typedef BOOST_DEDUCED_TYPENAME key_extractor::BOOST_NESTED_TEMPLATE + apply extractor; + typedef BOOST_DEDUCED_TYPENAME extractor::key_type key_type; + + typedef BOOST_DEDUCED_TYPENAME buckets::node node; + typedef BOOST_DEDUCED_TYPENAME buckets::bucket bucket; + typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr; + typedef BOOST_DEDUCED_TYPENAME buckets::bucket_ptr bucket_ptr; + typedef BOOST_DEDUCED_TYPENAME buckets::iterator_base iterator_base; + typedef BOOST_DEDUCED_TYPENAME buckets::node_allocator node_allocator; + typedef hash_node_constructor node_constructor; + typedef std::pair iterator_pair; + + // Members + + std::size_t size_; + float mlf_; + // Cached data - invalid if !this->buckets_ + bucket_ptr cached_begin_bucket_; + std::size_t max_load_; + + // Helper methods + + key_type const& get_key(value_type const& v) const { + return extractor::extract(v); + } + key_type const& get_key_from_ptr(node_ptr n) const { + return extractor::extract(node::get_value(n)); + } + bool equal(key_type const& k, value_type const& v) const; + node_ptr find_iterator(bucket_ptr bucket, key_type const& k) const; + node_ptr find_iterator(key_type const& k) const; + node_ptr* find_for_erase(bucket_ptr bucket, key_type const& k) const; + + // Load methods + + std::size_t max_size() const; + std::size_t bucket_index(key_type const& k) const; + void max_load_factor(float z); + std::size_t min_buckets_for_size(std::size_t n) const; + std::size_t calculate_max_load(); + + // Constructors + + hash_table(std::size_t n, hasher const& hf, key_equal const& eq, + node_allocator const& a); + hash_table(hash_table const& x, node_allocator const& a); + hash_table(hash_table& x, move_tag m); + hash_table(hash_table& x, node_allocator const& a, move_tag m); + ~hash_table() {} + hash_table& operator=(hash_table const&); + + // Iterators + + iterator_base begin() const { + return this->size_ ? + iterator_base(this->cached_begin_bucket_) : + iterator_base(); + } + iterator_base end() const { + return iterator_base(); + } + + // Swap & Move + + void swap(hash_table& x); + void fast_swap(hash_table& other); + void slow_swap(hash_table& other); + void partial_swap(hash_table& other); + void move(hash_table& x); + + // Reserve and rehash + + void create_for_insert(std::size_t n); + bool reserve_for_insert(std::size_t n); + void rehash(std::size_t n); + void rehash_impl(std::size_t n); + + // Move/copy buckets + + void move_buckets_to(buckets& dst); + void copy_buckets_to(buckets& dst) const; + + // Misc. key methods + + std::size_t count(key_type const& k) const; + iterator_base find(key_type const& k) const; + value_type& at(key_type const& k) const; + iterator_pair equal_range(key_type const& k) const; + + // Erase + // + // no throw + + void clear(); + std::size_t erase_key(key_type const& k); + iterator_base erase(iterator_base r); + std::size_t erase_group(node_ptr* it, bucket_ptr bucket); + iterator_base erase_range(iterator_base r1, iterator_base r2); + + // recompute_begin_bucket + + void init_buckets(); + + // After an erase cached_begin_bucket_ might be left pointing to + // an empty bucket, so this is called to update it + // + // no throw + + void recompute_begin_bucket(bucket_ptr b); + + // This is called when a range has been erased + // + // no throw + + void recompute_begin_bucket(bucket_ptr b1, bucket_ptr b2); + + // no throw + float load_factor() const; + + iterator_base emplace_empty_impl_with_node( + node_constructor&, std::size_t); + }; + + template + class hash_unique_table : + public hash_table + + { + public: + typedef H hasher; + typedef P key_equal; + typedef A value_allocator; + typedef K key_extractor; + + typedef hash_table table; + typedef hash_node_constructor node_constructor; + + typedef BOOST_DEDUCED_TYPENAME table::key_type key_type; + typedef BOOST_DEDUCED_TYPENAME table::value_type value_type; + typedef BOOST_DEDUCED_TYPENAME table::node node; + typedef BOOST_DEDUCED_TYPENAME table::node_ptr node_ptr; + typedef BOOST_DEDUCED_TYPENAME table::bucket_ptr bucket_ptr; + typedef BOOST_DEDUCED_TYPENAME table::iterator_base iterator_base; + typedef BOOST_DEDUCED_TYPENAME table::extractor extractor; + + typedef std::pair emplace_return; + + // Constructors + + hash_unique_table(std::size_t n, hasher const& hf, key_equal const& eq, + value_allocator const& a) + : table(n, hf, eq, a) {} + hash_unique_table(hash_unique_table const& x) + : table(x, x.node_alloc()) {} + hash_unique_table(hash_unique_table const& x, value_allocator const& a) + : table(x, a) {} + hash_unique_table(hash_unique_table& x, move_tag m) + : table(x, m) {} + hash_unique_table(hash_unique_table& x, value_allocator const& a, + move_tag m) + : table(x, a, m) {} + ~hash_unique_table() {} + + // Insert methods + + emplace_return emplace_impl_with_node(node_constructor& a); + value_type& operator[](key_type const& k); + + // equals + + bool equals(hash_unique_table const&) const; + + node_ptr add_node(node_constructor& a, bucket_ptr bucket); + +#if defined(BOOST_UNORDERED_STD_FORWARD) + + template + emplace_return emplace(Args&&... args); + template + emplace_return emplace_impl(key_type const& k, Args&&... args); + template + emplace_return emplace_impl(no_key, Args&&... args); + template + emplace_return emplace_empty_impl(Args&&... args); +#else + +#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ + template \ + emplace_return emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \ + template \ + emplace_return emplace_impl(key_type const& k, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \ + template \ + emplace_return emplace_impl(no_key, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \ + template \ + emplace_return emplace_empty_impl( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); + + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_INSERT_IMPL, _) + +#undef BOOST_UNORDERED_INSERT_IMPL + +#endif + + // if hash function throws, or inserting > 1 element, basic exception + // safety strong otherwise + template + void insert_range(InputIt i, InputIt j); + template + void insert_range_impl(key_type const&, InputIt i, InputIt j); + template + void insert_range_impl(no_key, InputIt i, InputIt j); + }; + + template + class hash_equivalent_table : + public hash_table + + { + public: + typedef H hasher; + typedef P key_equal; + typedef A value_allocator; + typedef K key_extractor; + + typedef hash_table table; + typedef hash_node_constructor + node_constructor; + typedef hash_iterator_base iterator_base; + + typedef BOOST_DEDUCED_TYPENAME table::key_type key_type; + typedef BOOST_DEDUCED_TYPENAME table::value_type value_type; + typedef BOOST_DEDUCED_TYPENAME table::node node; + typedef BOOST_DEDUCED_TYPENAME table::node_ptr node_ptr; + typedef BOOST_DEDUCED_TYPENAME table::bucket_ptr bucket_ptr; + typedef BOOST_DEDUCED_TYPENAME table::extractor extractor; + + // Constructors + + hash_equivalent_table(std::size_t n, + hasher const& hf, key_equal const& eq, value_allocator const& a) + : table(n, hf, eq, a) {} + hash_equivalent_table(hash_equivalent_table const& x) + : table(x, x.node_alloc()) {} + hash_equivalent_table(hash_equivalent_table const& x, + value_allocator const& a) + : table(x, a) {} + hash_equivalent_table(hash_equivalent_table& x, move_tag m) + : table(x, m) {} + hash_equivalent_table(hash_equivalent_table& x, + value_allocator const& a, move_tag m) + : table(x, a, m) {} + ~hash_equivalent_table() {} + + // Insert methods + + iterator_base emplace_impl(node_constructor& a); + iterator_base emplace_hint_impl(iterator_base const& it, + node_constructor& a); + void emplace_impl_no_rehash(node_constructor& a); + + // equals + + bool equals(hash_equivalent_table const&) const; + + inline node_ptr add_node(node_constructor& a, + bucket_ptr bucket, node_ptr pos); + +#if defined(BOOST_UNORDERED_STD_FORWARD) + + template + iterator_base emplace(Args&&... args); + template + iterator_base emplace_hint(iterator_base const& it, Args&&... args); + +#else + +#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ + template \ + iterator_base emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \ + \ + template \ + iterator_base emplace_hint(iterator_base const& it, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); + + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_INSERT_IMPL, _) + +#undef BOOST_UNORDERED_INSERT_IMPL +#endif + + template + void insert_for_range(I i, I j, forward_traversal_tag); + template + void insert_for_range(I i, I j, boost::incrementable_traversal_tag); + template + void insert_range(I i, I j); + }; + + // Iterator Access + + class iterator_access + { + public: + template + static BOOST_DEDUCED_TYPENAME Iterator::base const& + get(Iterator const& it) + { + return it.base_; + } + }; + + // Iterators + + template class hash_iterator; + template class hash_const_iterator; + template class hash_local_iterator; + template class hash_const_local_iterator; + + // Local Iterators + // + // all no throw + + template + class hash_local_iterator + : public boost::iterator < + std::forward_iterator_tag, + BOOST_DEDUCED_TYPENAME A::value_type, + std::ptrdiff_t, + BOOST_DEDUCED_TYPENAME A::pointer, + BOOST_DEDUCED_TYPENAME A::reference> + { + public: + typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; + + private: + typedef hash_buckets buckets; + typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr; + typedef BOOST_DEDUCED_TYPENAME buckets::node node; + typedef hash_const_local_iterator const_local_iterator; + + friend class hash_const_local_iterator; + node_ptr ptr_; + + public: + hash_local_iterator() : ptr_() {} + explicit hash_local_iterator(node_ptr x) : ptr_(x) {} + BOOST_DEDUCED_TYPENAME A::reference operator*() const { + return node::get_value(ptr_); + } + value_type* operator->() const { + return &node::get_value(ptr_); + } + hash_local_iterator& operator++() { + ptr_ = ptr_->next_; return *this; + } + hash_local_iterator operator++(int) { + hash_local_iterator tmp(ptr_); ptr_ = ptr_->next_; return tmp; } + bool operator==(hash_local_iterator x) const { + return ptr_ == x.ptr_; + } + bool operator==(const_local_iterator x) const { + return ptr_ == x.ptr_; + } + bool operator!=(hash_local_iterator x) const { + return ptr_ != x.ptr_; + } + bool operator!=(const_local_iterator x) const { + return ptr_ != x.ptr_; + } + }; + + template + class hash_const_local_iterator + : public boost::iterator < + std::forward_iterator_tag, + BOOST_DEDUCED_TYPENAME A::value_type, + std::ptrdiff_t, + BOOST_DEDUCED_TYPENAME A::const_pointer, + BOOST_DEDUCED_TYPENAME A::const_reference > + { + public: + typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; + + private: + typedef hash_buckets buckets; + typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr ptr; + typedef BOOST_DEDUCED_TYPENAME buckets::node node; + typedef hash_local_iterator local_iterator; + friend class hash_local_iterator; + ptr ptr_; + + public: + hash_const_local_iterator() : ptr_() {} + explicit hash_const_local_iterator(ptr x) : ptr_(x) {} + hash_const_local_iterator(local_iterator x) : ptr_(x.ptr_) {} + BOOST_DEDUCED_TYPENAME A::const_reference + operator*() const { + return node::get_value(ptr_); + } + value_type const* operator->() const { + return &node::get_value(ptr_); + } + hash_const_local_iterator& operator++() { + ptr_ = ptr_->next_; return *this; + } + hash_const_local_iterator operator++(int) { + hash_const_local_iterator tmp(ptr_); ptr_ = ptr_->next_; return tmp; + } + bool operator==(local_iterator x) const { + return ptr_ == x.ptr_; + } + bool operator==(hash_const_local_iterator x) const { + return ptr_ == x.ptr_; + } + bool operator!=(local_iterator x) const { + return ptr_ != x.ptr_; + } + bool operator!=(hash_const_local_iterator x) const { + return ptr_ != x.ptr_; + } + }; + + // iterators + // + // all no throw + + + template + class hash_iterator + : public boost::iterator < + std::forward_iterator_tag, + BOOST_DEDUCED_TYPENAME A::value_type, + std::ptrdiff_t, + BOOST_DEDUCED_TYPENAME A::pointer, + BOOST_DEDUCED_TYPENAME A::reference > + { + public: + typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; + + private: + typedef hash_buckets buckets; + typedef BOOST_DEDUCED_TYPENAME buckets::node node; + typedef BOOST_DEDUCED_TYPENAME buckets::iterator_base base; + typedef hash_const_iterator const_iterator; + friend class hash_const_iterator; + base base_; + + public: + + hash_iterator() : base_() {} + explicit hash_iterator(base const& x) : base_(x) {} + BOOST_DEDUCED_TYPENAME A::reference operator*() const { + return *base_; + } + value_type* operator->() const { + return &*base_; + } + hash_iterator& operator++() { + base_.increment(); return *this; + } + hash_iterator operator++(int) { + hash_iterator tmp(base_); base_.increment(); return tmp; + } + bool operator==(hash_iterator const& x) const { + return base_ == x.base_; + } + bool operator==(const_iterator const& x) const { + return base_ == x.base_; + } + bool operator!=(hash_iterator const& x) const { + return base_ != x.base_; + } + bool operator!=(const_iterator const& x) const { + return base_ != x.base_; + } + }; + + template + class hash_const_iterator + : public boost::iterator < + std::forward_iterator_tag, + BOOST_DEDUCED_TYPENAME A::value_type, + std::ptrdiff_t, + BOOST_DEDUCED_TYPENAME A::const_pointer, + BOOST_DEDUCED_TYPENAME A::const_reference > + { + public: + typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; + + private: + typedef hash_buckets buckets; + typedef BOOST_DEDUCED_TYPENAME buckets::node node; + typedef BOOST_DEDUCED_TYPENAME buckets::iterator_base base; + typedef hash_iterator iterator; + friend class hash_iterator; + friend class iterator_access; + base base_; + + public: + + hash_const_iterator() : base_() {} + explicit hash_const_iterator(base const& x) : base_(x) {} + hash_const_iterator(iterator const& x) : base_(x.base_) {} + BOOST_DEDUCED_TYPENAME A::const_reference operator*() const { + return *base_; + } + value_type const* operator->() const { + return &*base_; + } + hash_const_iterator& operator++() { + base_.increment(); return *this; + } + hash_const_iterator operator++(int) { + hash_const_iterator tmp(base_); base_.increment(); return tmp; + } + bool operator==(iterator const& x) const { + return base_ == x.base_; + } + bool operator==(hash_const_iterator const& x) const { + return base_ == x.base_; + } + bool operator!=(iterator const& x) const { + return base_ != x.base_; + } + bool operator!=(hash_const_iterator const& x) const { + return base_ != x.base_; + } + }; +}} + +#endif diff --git a/include/boost/unordered/detail/hash_table.hpp b/include/boost/unordered/detail/hash_table.hpp deleted file mode 100644 index 2418b2a6..00000000 --- a/include/boost/unordered/detail/hash_table.hpp +++ /dev/null @@ -1,347 +0,0 @@ - -// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. -// Copyright (C) 2005-2009 Daniel James -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_UNORDERED_DETAIL_HASH_TABLE_HPP_INCLUDED -#define BOOST_UNORDERED_DETAIL_HASH_TABLE_HPP_INCLUDED - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include -#include - -#if !defined(BOOST_UNORDERED_EMPLACE_LIMIT) -#define BOOST_UNORDERED_EMPLACE_LIMIT 10 -#endif - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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) - -#endif - -#if defined(BOOST_MSVC) -#pragma warning(push) -#if BOOST_MSVC >= 1400 -#pragma warning(disable:4267) // conversion from 'size_t' to 'unsigned int', - // possible loss of data. -#endif -#endif - -#if BOOST_WORKAROUND(__BORLANDC__, <= 0x0582) -#define BOOST_UNORDERED_BORLAND_BOOL(x) (bool)(x) -#else -#define BOOST_UNORDERED_BORLAND_BOOL(x) x -#endif - -#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) -#define BOOST_UNORDERED_MSVC_RESET_PTR(x) unordered_detail::reset(x) -#else -#define BOOST_UNORDERED_MSVC_RESET_PTR(x) -#endif - -namespace boost { - namespace unordered_detail { - template struct type_wrapper {}; - - static const std::size_t default_initial_bucket_count = 11; - static const float minimum_max_load_factor = 1e-3f; - - inline std::size_t double_to_size_t(double f) - { - return f >= static_cast((std::numeric_limits::max)()) ? - (std::numeric_limits::max)() : - static_cast(f); - } - - // prime number list, accessor - - template struct prime_list_template - { - static std::size_t const value[]; - static std::ptrdiff_t const length; - }; - -#define BOOST_UNORDERED_PRIMES \ - (5ul)(11ul)(17ul)(29ul)(37ul)(53ul)(67ul)(79ul) \ - (97ul)(131ul)(193ul)(257ul)(389ul)(521ul)(769ul) \ - (1031ul)(1543ul)(2053ul)(3079ul)(6151ul)(12289ul)(24593ul) \ - (49157ul)(98317ul)(196613ul)(393241ul)(786433ul) \ - (1572869ul)(3145739ul)(6291469ul)(12582917ul)(25165843ul) \ - (50331653ul)(100663319ul)(201326611ul)(402653189ul)(805306457ul) \ - (1610612741ul)(3221225473ul)(4294967291ul) - - template - std::size_t const prime_list_template::value[] = { - BOOST_PP_SEQ_ENUM(BOOST_UNORDERED_PRIMES) - }; - - template - std::ptrdiff_t const prime_list_template::length - = BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES); - -#undef BOOST_UNORDERED_PRIMES - - typedef prime_list_template prime_list; - - // no throw - inline std::size_t next_prime(std::size_t n) { - std::size_t const* const prime_list_begin = prime_list::value; - std::size_t const* const prime_list_end = prime_list_begin + - prime_list::length; - std::size_t const* bound = - std::lower_bound(prime_list_begin, prime_list_end, n); - if(bound == prime_list_end) - bound--; - return *bound; - } - - // no throw - inline std::size_t prev_prime(std::size_t n) { - std::size_t const* const prime_list_begin = prime_list::value; - std::size_t const* const prime_list_end = prime_list_begin + - prime_list::length; - std::size_t const* bound = - std::upper_bound(prime_list_begin,prime_list_end, n); - if(bound != prime_list_begin) - bound--; - return *bound; - } - - // Controls how many buckets are allocated and which buckets hash - // values map to. Does not contain the buckets themselves, or ever - // deal with them directly. - - struct bucket_manager { - std::size_t bucket_count_; - - bucket_manager() - : bucket_count_(0) {} - - explicit bucket_manager(std::size_t n) - : bucket_count_(next_prime(n)) {} - - std::size_t bucket_count() const { - return bucket_count_; - } - - std::size_t bucket_from_hash(std::size_t hashed) const { - return hashed % bucket_count_; - } - - std::size_t max_bucket_count(std::size_t max_size) const { - return prev_prime(max_size); - } - }; - - // pair_cast - used to convert between pair types. - - template - inline std::pair pair_cast(std::pair const& x) - { - return std::pair(Dst1(x.first), Dst2(x.second)); - } - -#if !defined(BOOST_NO_STD_DISTANCE) - using ::std::distance; -#else - template - inline std::size_t distance(ForwardIterator i, ForwardIterator j) { - std::size_t x; - std::distance(i, j, x); - return x; - } -#endif - - struct move_tag {}; - - // Both hasher and key_equal's copy/assign can throw so double - // buffering is used to copy them. - - template - struct buffered_functions - { - typedef Hash hasher; - typedef Pred key_equal; - - class functions - { - std::pair functions_; - - public: - - functions(hasher const& h, key_equal const& k) - : functions_(h, k) {} - - hasher const& hash_function() const - { - return functions_.first; - } - - key_equal const& key_eq() const - { - return functions_.second; - } - }; - - typedef functions buffered_functions::*functions_ptr; - - buffered_functions(hasher const& h, key_equal const& k) - : func1_(h, k), func2_(h, k), func_(&buffered_functions::func1_) {} - - // This copies the given function objects into the currently unused - // function objects and returns a pointer, that func_ can later be - // set to, to commit the change. - // - // Strong exception safety (since only usued function objects are - // changed). - functions_ptr buffer(buffered_functions const& x) { - functions_ptr ptr = func_ == &buffered_functions::func1_ - ? &buffered_functions::func2_ : &buffered_functions::func1_; - this->*ptr = x.current(); - return ptr; - } - - void set(functions_ptr ptr) { - BOOST_ASSERT(ptr != func_); - func_ = ptr; - } - - functions const& current() const { - return this->*func_; - } - - private: - functions func1_; - functions func2_; - functions_ptr func_; // The currently active functions. - }; - -#if defined(BOOST_MSVC) -# define BOOST_UNORDERED_DESTRUCT(x, type) (x)->~type(); -#else -# define BOOST_UNORDERED_DESTRUCT(x, type) boost::unordered_detail::destroy(x) - template - void destroy(T* x) { - x->~T(); - } -#endif - } -} - -#define BOOST_UNORDERED_EQUIVALENT_KEYS 1 -#include -#undef BOOST_UNORDERED_EQUIVALENT_KEYS - -#define BOOST_UNORDERED_EQUIVALENT_KEYS 0 -#include -#undef BOOST_UNORDERED_EQUIVALENT_KEYS - -namespace boost { - namespace unordered_detail { - class iterator_access - { - public: - template - static BOOST_DEDUCED_TYPENAME Iterator::base const& get(Iterator const& it) { - return it.base_; - } - }; - - template - class hash_types_unique_keys - { - public: - typedef BOOST_DEDUCED_TYPENAME - boost::unordered_detail::rebind_wrap::type - value_allocator; - - typedef hash_table_unique_keys hash_table; - typedef hash_table_data_unique_keys data; - typedef BOOST_DEDUCED_TYPENAME data::iterator_base iterator_base; - - typedef hash_const_local_iterator_unique_keys const_local_iterator; - typedef hash_local_iterator_unique_keys local_iterator; - typedef hash_const_iterator_unique_keys const_iterator; - typedef hash_iterator_unique_keys iterator; - - typedef BOOST_DEDUCED_TYPENAME data::size_type size_type; - typedef std::ptrdiff_t difference_type; - }; - - template - class hash_types_equivalent_keys - { - public: - typedef BOOST_DEDUCED_TYPENAME - boost::unordered_detail::rebind_wrap::type - value_allocator; - - typedef hash_table_equivalent_keys hash_table; - typedef hash_table_data_equivalent_keys data; - typedef BOOST_DEDUCED_TYPENAME data::iterator_base iterator_base; - - typedef hash_const_local_iterator_equivalent_keys const_local_iterator; - typedef hash_local_iterator_equivalent_keys local_iterator; - typedef hash_const_iterator_equivalent_keys const_iterator; - typedef hash_iterator_equivalent_keys iterator; - - typedef BOOST_DEDUCED_TYPENAME data::size_type size_type; - typedef std::ptrdiff_t difference_type; - }; - } // namespace boost::unordered_detail -} // namespace boost - -#undef BOOST_UNORDERED_BORLAND_BOOL -#undef BOOST_UNORDERED_MSVC_RESET_PTR - -#if defined(BOOST_MSVC) -#pragma warning(pop) -#endif - -#endif // BOOST_UNORDERED_DETAIL_HASH_TABLE_HPP_INCLUDED diff --git a/include/boost/unordered/detail/hash_table_impl.hpp b/include/boost/unordered/detail/hash_table_impl.hpp deleted file mode 100644 index 6bfe6580..00000000 --- a/include/boost/unordered/detail/hash_table_impl.hpp +++ /dev/null @@ -1,2527 +0,0 @@ - -// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. -// Copyright (C) 2005-2009 Daniel James -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#if BOOST_UNORDERED_EQUIVALENT_KEYS -#define BOOST_UNORDERED_TABLE hash_table_equivalent_keys -#define BOOST_UNORDERED_TABLE_DATA hash_table_data_equivalent_keys -#define BOOST_UNORDERED_ITERATOR hash_iterator_equivalent_keys -#define BOOST_UNORDERED_CONST_ITERATOR hash_const_iterator_equivalent_keys -#define BOOST_UNORDERED_LOCAL_ITERATOR hash_local_iterator_equivalent_keys -#define BOOST_UNORDERED_CONST_LOCAL_ITERATOR hash_const_local_iterator_equivalent_keys -#else -#define BOOST_UNORDERED_TABLE hash_table_unique_keys -#define BOOST_UNORDERED_TABLE_DATA hash_table_data_unique_keys -#define BOOST_UNORDERED_ITERATOR hash_iterator_unique_keys -#define BOOST_UNORDERED_CONST_ITERATOR hash_const_iterator_unique_keys -#define BOOST_UNORDERED_LOCAL_ITERATOR hash_local_iterator_unique_keys -#define BOOST_UNORDERED_CONST_LOCAL_ITERATOR hash_const_local_iterator_unique_keys -#endif - -namespace boost { - namespace unordered_detail { - - // - // Hash Table Data - // - // Responsible for managing the hash buckets. - - template - class BOOST_UNORDERED_TABLE_DATA - { - public: - typedef BOOST_UNORDERED_TABLE_DATA data; - - struct node; - struct bucket; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; - - typedef Alloc value_allocator; - - typedef BOOST_DEDUCED_TYPENAME - boost::unordered_detail::rebind_wrap::type - node_allocator; - typedef BOOST_DEDUCED_TYPENAME - boost::unordered_detail::rebind_wrap::type - bucket_allocator; - - typedef BOOST_DEDUCED_TYPENAME allocator_value_type::type value_type; - typedef BOOST_DEDUCED_TYPENAME allocator_pointer::type node_ptr; - typedef BOOST_DEDUCED_TYPENAME allocator_pointer::type bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME allocator_reference::type reference; - typedef BOOST_DEDUCED_TYPENAME allocator_reference::type bucket_reference; - - typedef bucket_ptr link_ptr; - - // Hash Bucket - // - // all no throw - - struct bucket - { - private: - bucket& operator=(bucket const&); - public: - link_ptr next_; - - bucket() : next_() - { - BOOST_UNORDERED_MSVC_RESET_PTR(next_); - } - - bucket(bucket const& x) : next_(x.next_) - { - // Only copy construct when allocating. - BOOST_ASSERT(!x.next_); - } - - bool empty() const - { - return !this->next_; - } - }; - - // Value Base - - struct value_base { - typename boost::aligned_storage< - sizeof(value_type), - ::boost::alignment_of::value>::type data_; - - void* address() { return this; } - }; - - // Hash Node - // - // all no throw - - struct node : value_base, bucket { -#if BOOST_UNORDERED_EQUIVALENT_KEYS - public: - node() : group_prev_() - { - BOOST_UNORDERED_MSVC_RESET_PTR(group_prev_); - } - - link_ptr group_prev_; -#endif - - value_type& value() { - return *static_cast(this->address()); - } - }; - - // allocators - // - // Stores all the allocators that we're going to need. - - struct allocators - { - node_allocator node_alloc_; - bucket_allocator bucket_alloc_; - - allocators(value_allocator const& a) - : node_alloc_(a), bucket_alloc_(a) - {} - - void destroy(link_ptr ptr) - { - node* raw_ptr = static_cast(&*ptr); - BOOST_UNORDERED_DESTRUCT(&raw_ptr->value(), value_type); - node_ptr n(node_alloc_.address(*raw_ptr)); - node_alloc_.destroy(n); - node_alloc_.deallocate(n, 1); - } - - void swap(allocators& x) - { - boost::swap(node_alloc_, x.node_alloc_); - boost::swap(bucket_alloc_, x.bucket_alloc_); - } - - bool operator==(allocators const& x) - { - return node_alloc_ == x.node_alloc_; - } - }; - - // node_constructor - // - // Used to construct nodes in an exception safe manner. - - class node_constructor - { - allocators& allocators_; - - node_ptr node_; - bool node_constructed_; - bool value_constructed_; - - public: - - node_constructor(allocators& a) - : allocators_(a), - node_(), node_constructed_(false), value_constructed_(false) - { - } - - ~node_constructor() - { - if (node_) { - if (value_constructed_) { - BOOST_UNORDERED_DESTRUCT(&node_->value(), value_type); - } - - if (node_constructed_) - allocators_.node_alloc_.destroy(node_); - allocators_.node_alloc_.deallocate(node_, 1); - } - } - - 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 - void construct(Args&&... args) - { - construct_preamble(); - new(node_->address()) value_type(std::forward(args)...); - value_constructed_ = true; - } -#else - -#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); - } - -#undef BOOST_UNORDERED_CONSTRUCT_IMPL - -#endif - template - void construct_pair(K const& k, M*) - { - construct_preamble(); - new(node_->address()) value_type(k, M()); - value_constructed_ = true; - } - - node_ptr get() const - { - BOOST_ASSERT(node_); - return node_; - } - - // no throw - link_ptr release() - { - node_ptr p = node_; - unordered_detail::reset(node_); - return link_ptr(allocators_.bucket_alloc_.address(*p)); - } - - private: - node_constructor(node_constructor const&); - node_constructor& operator=(node_constructor const&); - }; - - // Methods for navigating groups of elements with equal keys. - -#if BOOST_UNORDERED_EQUIVALENT_KEYS - static inline link_ptr& prev_in_group(link_ptr n) { - return static_cast(&*n)->group_prev_; - } - - // pre: Must be pointing to the first node in a group. - static inline link_ptr& next_group(link_ptr n) { - BOOST_ASSERT(BOOST_UNORDERED_BORLAND_BOOL(n) && n != prev_in_group(n)->next_); - return prev_in_group(n)->next_; - } -#else - static inline link_ptr& next_group(link_ptr n) { - BOOST_ASSERT(n); - return n->next_; - } -#endif - - // pre: Must be pointing to a node - static inline node& get_node(link_ptr p) { - BOOST_ASSERT(p); - return *static_cast(&*p); - } - - // pre: Must be pointing to a node - static inline reference get_value(link_ptr p) { - return get_node(p).value(); - } - - class iterator_base - { - typedef BOOST_UNORDERED_TABLE_DATA data; - public: - bucket_ptr bucket_; - link_ptr node_; - - iterator_base() - : bucket_(), node_() - { - BOOST_UNORDERED_MSVC_RESET_PTR(bucket_); - BOOST_UNORDERED_MSVC_RESET_PTR(node_); - } - - explicit iterator_base(bucket_ptr b) - : bucket_(b), node_(b->next_) {} - - iterator_base(bucket_ptr b, link_ptr n) - : bucket_(b), node_(n) {} - - bool operator==(iterator_base const& x) const - { - return node_ == x.node_; - } - - bool operator!=(iterator_base const& x) const - { - return node_ != x.node_; - } - - reference operator*() const - { - return get_value(node_); - } - - void increment() - { - BOOST_ASSERT(bucket_); - node_ = node_->next_; - - while (!node_) { - ++bucket_; - node_ = bucket_->next_; - } - } - - void increment_group() - { - node_ = data::next_group(node_); - - while (!node_) { - ++bucket_; - node_ = bucket_->next_; - } - } - }; - - // Member Variables - - allocators allocators_; - bucket_ptr buckets_; - bucket_manager bucket_manager_; - bucket_ptr cached_begin_bucket_; - size_type size_; - - // Constructors/Deconstructor - - BOOST_UNORDERED_TABLE_DATA(size_type n, value_allocator const& a) - : allocators_(a), - buckets_(), bucket_manager_(n), - cached_begin_bucket_(), size_(0) - { - BOOST_UNORDERED_MSVC_RESET_PTR(buckets_); - create_buckets(); - } - - BOOST_UNORDERED_TABLE_DATA(BOOST_UNORDERED_TABLE_DATA const& x, size_type n) - : allocators_(x.allocators_), - buckets_(), bucket_manager_(n), - cached_begin_bucket_(), size_(0) - { - BOOST_UNORDERED_MSVC_RESET_PTR(buckets_); - create_buckets(); - } - - BOOST_UNORDERED_TABLE_DATA(BOOST_UNORDERED_TABLE_DATA& x, move_tag) - : allocators_(x.allocators_), - buckets_(x.buckets_), bucket_manager_(x.bucket_manager_), - cached_begin_bucket_(x.cached_begin_bucket_), size_(x.size_) - { - unordered_detail::reset(x.buckets_); - } - - BOOST_UNORDERED_TABLE_DATA(BOOST_UNORDERED_TABLE_DATA& x, - value_allocator const& a, size_type n, move_tag) - : allocators_(a), buckets_(), bucket_manager_(), - cached_begin_bucket_(), size_(0) - { - if(allocators_ == x.allocators_) { - buckets_ = x.buckets_; - bucket_manager_ = x.bucket_manager_; - cached_begin_bucket_ = x.cached_begin_bucket_; - size_ = x.size_; - unordered_detail::reset(x.buckets_); - } - else { - BOOST_UNORDERED_MSVC_RESET_PTR(buckets_); - bucket_manager_ = bucket_manager(n); - create_buckets(); - } - } - - // no throw - ~BOOST_UNORDERED_TABLE_DATA() - { - delete_buckets(); - } - - void create_buckets() { - size_type bucket_count = bucket_manager_.bucket_count(); - - // The array constructor will clean up in the event of an - // exception. - allocator_array_constructor - constructor(allocators_.bucket_alloc_); - - // Creates an extra bucket to act as a sentinel. - constructor.construct(bucket(), bucket_count + 1); - - cached_begin_bucket_ = constructor.get() + static_cast(bucket_count); - - // Set up the sentinel. - cached_begin_bucket_->next_ = link_ptr(cached_begin_bucket_); - - // Only release the buckets once everything is successfully - // done. - buckets_ = constructor.release(); - } - - // no throw - void delete_buckets() - { - if(buckets_) { - bucket_ptr begin = cached_begin_bucket_; - bucket_ptr end = buckets_end(); - while(begin != end) { - clear_bucket(begin); - ++begin; - } - - // Destroy an extra bucket for the sentinels. - ++end; - for(begin = buckets_; begin != end; ++begin) - allocators_.bucket_alloc_.destroy(begin); - - allocators_.bucket_alloc_.deallocate(buckets_, - bucket_manager_.bucket_count() + 1); - } - } - - private: - - BOOST_UNORDERED_TABLE_DATA(BOOST_UNORDERED_TABLE_DATA const&); - BOOST_UNORDERED_TABLE_DATA& operator=(BOOST_UNORDERED_TABLE_DATA const&); - - public: - - // no throw - void swap(BOOST_UNORDERED_TABLE_DATA& other) - { - std::swap(buckets_, other.buckets_); - std::swap(bucket_manager_, other.bucket_manager_); - std::swap(cached_begin_bucket_, other.cached_begin_bucket_); - std::swap(size_, other.size_); - } - - // no throw - void move(BOOST_UNORDERED_TABLE_DATA& other) - { - delete_buckets(); - buckets_ = other.buckets_; - unordered_detail::reset(other.buckets_); - bucket_manager_ = other.bucket_manager_; - cached_begin_bucket_ = other.cached_begin_bucket_; - size_ = other.size_; - } - - // Return the bucket number for a hashed value. - // - // no throw - size_type bucket_from_hash(size_type hashed) const - { - return bucket_manager_.bucket_from_hash(hashed); - } - - // Return the bucket for a hashed value. - // - // no throw - bucket_ptr bucket_ptr_from_hash(size_type hashed) const - { - return buckets_ + static_cast( - bucket_manager_.bucket_from_hash(hashed)); - } - - // Begin & End - // - // no throw - - bucket_ptr buckets_end() const - { - return buckets_ + static_cast(bucket_manager_.bucket_count()); - } - - iterator_base begin() const - { - return size_ - ? iterator_base(cached_begin_bucket_) - : end(); - } - - iterator_base end() const - { - return iterator_base(buckets_end()); - } - - link_ptr begin(size_type n) const - { - return (buckets_ + static_cast(n))->next_; - } - - link_ptr end(size_type) const - { - return unordered_detail::null_ptr(); - } - - link_ptr begin(bucket_ptr b) const - { - return b->next_; - } - - // Bucket Size - - // no throw - static inline size_type node_count(link_ptr it) - { - size_type count = 0; - while(BOOST_UNORDERED_BORLAND_BOOL(it)) { - ++count; - it = it->next_; - } - return count; - } - - static inline size_type node_count(link_ptr it1, link_ptr it2) - { - size_type count = 0; - while(it1 != it2) { - ++count; - it1 = it1->next_; - } - return count; - } - - size_type bucket_size(size_type n) const - { - return node_count(begin(n)); - } - -#if BOOST_UNORDERED_EQUIVALENT_KEYS - static inline size_type group_count(link_ptr it) - { - return node_count(it, next_group(it)); - } -#else - static inline size_type group_count(link_ptr) - { - return 1; - } -#endif - - // get_for_erase - // - // Find the pointer to a node, for use when erasing. - // - // no throw - -#if BOOST_UNORDERED_EQUIVALENT_KEYS - static link_ptr* get_for_erase(iterator_base r) - { - link_ptr n = r.node_; - - // If the element isn't the first in its group, then - // the link to it will be found in the previous element - // in the group. - link_ptr* it = &prev_in_group(n)->next_; - if(*it == n) return it; - - // The element is the first in its group, so iterate - // throught the groups, checking against the first element. - it = &r.bucket_->next_; - while(*it != n) it = &BOOST_UNORDERED_TABLE_DATA::next_group(*it); - return it; - } -#else - static link_ptr* get_for_erase(iterator_base r) - { - link_ptr n = r.node_; - link_ptr* it = &r.bucket_->next_; - while(*it != n) it = &(*it)->next_; - return it; - } -#endif - - // Link/Unlink/Move Node - // - // For adding nodes to buckets, removing them and moving them to a - // new bucket. - // - // no throw - -#if BOOST_UNORDERED_EQUIVALENT_KEYS - // If n points to the first node in a group, this adds it to the - // end of that group. - link_ptr link_node(node_constructor& a, link_ptr pos) - { - link_ptr n = a.release(); - node& node_ref = get_node(n); - node& pos_ref = get_node(pos); - node_ref.next_ = pos_ref.group_prev_->next_; - node_ref.group_prev_ = pos_ref.group_prev_; - pos_ref.group_prev_->next_ = n; - pos_ref.group_prev_ = n; - ++size_; - return n; - } - - link_ptr link_node_in_bucket(node_constructor& a, bucket_ptr base) - { - link_ptr n = a.release(); - node& node_ref = get_node(n); - node_ref.next_ = base->next_; - node_ref.group_prev_ = n; - base->next_ = n; - ++size_; - if(base < cached_begin_bucket_) cached_begin_bucket_ = base; - return n; - } - - void link_group(link_ptr n, bucket_ptr base, size_type count) - { - node& node_ref = get_node(n); - node& last_ref = get_node(node_ref.group_prev_); - last_ref.next_ = base->next_; - base->next_ = n; - size_ += count; - if(base < cached_begin_bucket_) cached_begin_bucket_ = base; - } -#else - void link_node(link_ptr n, bucket_ptr base) - { - n->next_ = base->next_; - base->next_ = n; - ++size_; - if(base < cached_begin_bucket_) cached_begin_bucket_ = base; - } - - link_ptr link_node_in_bucket(node_constructor& a, bucket_ptr base) - { - link_ptr n = a.release(); - link_node(n, base); - return n; - } - - void link_group(link_ptr n, bucket_ptr base, size_type) - { - link_node(n, base); - } -#endif - -#if BOOST_UNORDERED_EQUIVALENT_KEYS - void unlink_node(iterator_base it) - { - link_ptr* pos = get_for_erase(it); - node* n = &get_node(it.node_); - link_ptr next = n->next_; - - if(n->group_prev_ == *pos) { - // The deleted node is the sole node in the group, so - // no need to unlink it from a group. - } - else if(BOOST_UNORDERED_BORLAND_BOOL(next) && prev_in_group(next) == *pos) - { - // The deleted node is not at the end of the group, so - // change the link from the next node. - prev_in_group(next) = n->group_prev_; - } - else { - // The deleted node is at the end of the group, so the - // first node in the group is pointing to it. - // Find that to change its pointer. - link_ptr it = n->group_prev_; - while(prev_in_group(it) != *pos) { - it = prev_in_group(it); - } - prev_in_group(it) = n->group_prev_; - } - *pos = next; - --size_; - } - - size_type unlink_group(link_ptr* pos) - { - size_type count = group_count(*pos); - size_ -= count; - *pos = next_group(*pos); - return count; - } -#else - void unlink_node(iterator_base n) - { - link_ptr* pos = get_for_erase(n); - *pos = (*pos)->next_; - --size_; - } - - size_type unlink_group(link_ptr* pos) - { - *pos = (*pos)->next_; - --size_; - return 1; - } -#endif - - void unlink_nodes(iterator_base n) - { - link_ptr* it = get_for_erase(n); - split_group(*it); - unordered_detail::reset(*it); - size_ -= node_count(n.node_); - } - - void unlink_nodes(iterator_base begin, iterator_base end) - { - BOOST_ASSERT(begin.bucket_ == end.bucket_); - size_ -= node_count(begin.node_, end.node_); - link_ptr* it = get_for_erase(begin); - split_group(*it, end.node_); - *it = end.node_; - } - - void unlink_nodes(bucket_ptr base, iterator_base end) - { - BOOST_ASSERT(base == end.bucket_); - - split_group(end.node_); - - link_ptr ptr(base->next_); - base->next_ = end.node_; - - size_ -= node_count(ptr, end.node_); - } - -#if BOOST_UNORDERED_EQUIVALENT_KEYS - // Break a ciruclar list into two, with split as the beginning - // of the second group (if split is at the beginning then don't - // split). - static inline link_ptr split_group(link_ptr split) - { - // If split is at the beginning of the group then there's - // nothing to split. - if(prev_in_group(split)->next_ != split) - return unordered_detail::null_ptr(); - - // Find the start of the group. - link_ptr start = split; - do { - start = prev_in_group(start); - } while(prev_in_group(start)->next_ == start); - - link_ptr last = prev_in_group(start); - prev_in_group(start) = prev_in_group(split); - prev_in_group(split) = last; - - return start; - } - - static inline void split_group(link_ptr split1, link_ptr split2) - { - link_ptr begin1 = split_group(split1); - link_ptr begin2 = split_group(split2); - - if(BOOST_UNORDERED_BORLAND_BOOL(begin1) && split1 == begin2) { - link_ptr end1 = prev_in_group(begin1); - prev_in_group(begin1) = prev_in_group(begin2); - prev_in_group(begin2) = end1; - } - } -#else - static inline void split_group(link_ptr) - { - } - - static inline void split_group(link_ptr, link_ptr) - { - } -#endif - - // copy_group - // - // Basic exception safety. - // If it throws, it only copies some of the nodes in the group. - -#if BOOST_UNORDERED_EQUIVALENT_KEYS - void copy_group(link_ptr it, bucket_ptr dst) - { - node_constructor a(allocators_); - - link_ptr end = next_group(it); - - a.construct(get_value(it)); // throws - link_ptr n = link_node_in_bucket(a, dst); - - for(it = it->next_; it != end; it = it->next_) { - a.construct(get_value(it)); // throws - link_node(a, n); - } - } -#else - void copy_group(link_ptr it, bucket_ptr dst) - { - node_constructor a(allocators_); - - a.construct(get_value(it)); // throws - link_node_in_bucket(a, dst); - } -#endif - - // Delete Node - // - // Remove a node, or a range of nodes, from a bucket, and destroy - // them. - // - // no throw - - void delete_to_bucket_end(link_ptr begin) - { - while(begin) { - link_ptr node = begin; - begin = begin->next_; - allocators_.destroy(node); - } - } - - void delete_nodes(link_ptr begin, link_ptr end) - { - while(begin != end) { - link_ptr node = begin; - begin = begin->next_; - allocators_.destroy(node); - } - } - -#if BOOST_UNORDERED_EQUIVALENT_KEYS - void delete_group(link_ptr first_node) - { - delete_nodes(first_node, prev_in_group(first_node)->next_); - } -#else - void delete_group(link_ptr node) - { - allocators_.destroy(node); - } -#endif - - // Clear - // - // Remove all the nodes. - // - // no throw - - void clear_bucket(bucket_ptr b) - { - link_ptr first_node = b->next_; - unordered_detail::reset(b->next_); - delete_to_bucket_end(first_node); - } - - void clear() - { - bucket_ptr begin = cached_begin_bucket_; - bucket_ptr end = buckets_end(); - - size_ = 0; - cached_begin_bucket_ = end; - - while(begin != end) { - clear_bucket(begin); - ++begin; - } - } - - // Erase - // - // no throw - - iterator_base erase(iterator_base r) - { - BOOST_ASSERT(r != end()); - iterator_base next = r; - next.increment(); - unlink_node(r); - allocators_.destroy(r.node_); - // r has been invalidated but its bucket is still valid - recompute_begin_bucket(r.bucket_, next.bucket_); - return next; - } - - iterator_base erase_range(iterator_base r1, iterator_base r2) - { - if(r1 != r2) - { - BOOST_ASSERT(r1 != end()); - - if (r1.bucket_ == r2.bucket_) { - unlink_nodes(r1, r2); - delete_nodes(r1.node_, r2.node_); - - // No need to call recompute_begin_bucket because - // the nodes are only deleted from one bucket, which - // still contains r2 after the erase. - BOOST_ASSERT(!r1.bucket_->empty()); - } - else { - BOOST_ASSERT(r1.bucket_ < r2.bucket_); - - unlink_nodes(r1); - delete_to_bucket_end(r1.node_); - - bucket_ptr i = r1.bucket_; - for(++i; i != r2.bucket_; ++i) { - size_ -= node_count(i->next_); - clear_bucket(i); - } - - if(r2 != end()) { - link_ptr first = r2.bucket_->next_; - unlink_nodes(r2.bucket_, r2); - delete_nodes(first, r2.node_); - } - - // r1 has been invalidated but its bucket is still - // valid. - recompute_begin_bucket(r1.bucket_, r2.bucket_); - } - } - - return r2; - } - - // recompute_begin_bucket - // - // After an erase cached_begin_bucket_ might be left pointing to - // an empty bucket, so this is called to update it - // - // no throw - - void recompute_begin_bucket(bucket_ptr b) - { - BOOST_ASSERT(!(b < cached_begin_bucket_)); - - if(b == cached_begin_bucket_) - { - if (size_ != 0) { - while (cached_begin_bucket_->empty()) - ++cached_begin_bucket_; - } else { - cached_begin_bucket_ = buckets_end(); - } - } - } - - // This is called when a range has been erased - // - // no throw - - void recompute_begin_bucket(bucket_ptr b1, bucket_ptr b2) - { - BOOST_ASSERT(!(b1 < cached_begin_bucket_) && !(b2 < b1)); - BOOST_ASSERT(b2 == buckets_end() || !b2->empty()); - - if(b1 == cached_begin_bucket_ && b1->empty()) - cached_begin_bucket_ = b2; - } - - size_type erase_group(link_ptr* it, bucket_ptr bucket) - { - link_ptr pos = *it; - size_type count = unlink_group(it); - delete_group(pos); - - this->recompute_begin_bucket(bucket); - - return count; - } - }; - -#if defined(BOOST_MPL_CFG_MSVC_ETI_BUG) - template <> - class BOOST_UNORDERED_TABLE_DATA - { - public: - typedef int size_type; - typedef int iterator_base; - }; -#endif - - // - // Hash Table - // - - template - class BOOST_UNORDERED_TABLE - { - typedef BOOST_UNORDERED_TABLE_DATA data; - - typedef BOOST_DEDUCED_TYPENAME data::node_constructor node_constructor; - typedef BOOST_DEDUCED_TYPENAME data::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME data::link_ptr link_ptr; - - public: - - typedef BOOST_DEDUCED_TYPENAME data::value_allocator value_allocator; - typedef BOOST_DEDUCED_TYPENAME data::node_allocator node_allocator; - - // Type definitions - - typedef KeyType key_type; - typedef Hash hasher; - typedef Pred key_equal; - typedef ValueType value_type; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; - - // iterators - - typedef BOOST_DEDUCED_TYPENAME data::iterator_base iterator_base; - - private: - - - typedef boost::unordered_detail::buffered_functions - function_store; - typedef BOOST_DEDUCED_TYPENAME function_store::functions functions; - typedef BOOST_DEDUCED_TYPENAME function_store::functions_ptr - functions_ptr; - - function_store functions_; - float mlf_; - size_type max_load_; - - public: - - data data_; - - // Constructors - // - // In the constructors, if anything throws an exception, - // BOOST_UNORDERED_TABLE_DATA's destructor will clean up. - - BOOST_UNORDERED_TABLE(size_type n, - hasher const& hf, key_equal const& eq, - value_allocator const& a) - : functions_(hf, eq), // throws, cleans itself up - mlf_(1.0f), // no throw - data_(n, a) // throws, cleans itself up - { - calculate_max_load(); // no throw - } - - // Construct from iterators - - // initial_size - // - // A helper function for the copy constructor to calculate how many - // nodes will be created if the iterator's support it. Might get it - // totally wrong for containers with unique keys. - // - // no throw - - template - size_type initial_size(I i, I j, size_type n, - boost::forward_traversal_tag) - { - // max load factor isn't set yet, but when it is, it'll be 1.0. - return (std::max)(static_cast(unordered_detail::distance(i, j)) + 1, n); - } - - template - size_type initial_size(I, I, size_type n, - boost::incrementable_traversal_tag) - { - return n; - } - - template - size_type initial_size(I i, I j, size_type n) - { - BOOST_DEDUCED_TYPENAME boost::iterator_traversal::type - iterator_traversal_tag; - return initial_size(i, j, n, iterator_traversal_tag); - } - - template - BOOST_UNORDERED_TABLE(I i, I j, size_type n, - hasher const& hf, key_equal const& eq, - value_allocator const& a) - : functions_(hf, eq), // throws, cleans itself up - mlf_(1.0f), // no throw - data_(initial_size(i, j, n), a) // throws, cleans itself up - { - calculate_max_load(); // no throw - - // This can throw, but BOOST_UNORDERED_TABLE_DATA's destructor will clean up. - insert_range(i, j); - } - - // Copy Construct - - BOOST_UNORDERED_TABLE(BOOST_UNORDERED_TABLE const& x) - : functions_(x.functions_), // throws - mlf_(x.mlf_), // no throw - data_(x.data_, x.min_buckets_for_size(x.size())) // throws - { - calculate_max_load(); // no throw - - // This can throw, but BOOST_UNORDERED_TABLE_DATA's destructor will clean - // up. - x.copy_buckets_to(data_); - } - - // Copy Construct with allocator - - BOOST_UNORDERED_TABLE(BOOST_UNORDERED_TABLE const& x, - value_allocator const& a) - : functions_(x.functions_), // throws - mlf_(x.mlf_), // no throw - data_(x.min_buckets_for_size(x.size()), a) - { - calculate_max_load(); // no throw - - // This can throw, but BOOST_UNORDERED_TABLE_DATA's destructor will clean - // up. - x.copy_buckets_to(data_); - } - - // Move Construct - - BOOST_UNORDERED_TABLE(BOOST_UNORDERED_TABLE& x, move_tag m) - : functions_(x.functions_), // throws - mlf_(x.mlf_), // no throw - data_(x.data_, m) // throws - { - calculate_max_load(); // no throw - } - - BOOST_UNORDERED_TABLE(BOOST_UNORDERED_TABLE& x, - value_allocator const& a, move_tag m) - : functions_(x.functions_), // throws - mlf_(x.mlf_), // no throw - data_(x.data_, a, - x.min_buckets_for_size(x.size()), m) // throws - { - calculate_max_load(); // no throw - - if(x.data_.buckets_) { - // This can throw, but BOOST_UNORDERED_TABLE_DATA's destructor will clean - // up. - x.copy_buckets_to(data_); - } - } - - // Assign - // - // basic exception safety, if buffered_functions::buffer or reserver throws - // the container is left in a sane, empty state. If copy_buckets_to - // throws the container is left with whatever was successfully - // copied. - - BOOST_UNORDERED_TABLE& operator=(BOOST_UNORDERED_TABLE const& x) - { - if(this != &x) - { - data_.clear(); // no throw - functions_.set(functions_.buffer(x.functions_)); - // throws, strong - mlf_ = x.mlf_; // no throw - calculate_max_load(); // no throw - reserve(x.size()); // throws - x.copy_buckets_to(data_); // throws - } - - return *this; - } - - // Swap - // - // Swap's behaviour when allocators aren't equal is in dispute, for - // details see: - // - // http://unordered.nfshost.com/doc/html/unordered/rationale.html#swapping_containers_with_unequal_allocators - // - // ---------------------------------------------------------------- - // - // Strong exception safety (might change unused function objects) - // - // Can throw if hash or predicate object's copy constructor throws - // or if allocators are unequal. - - void swap(BOOST_UNORDERED_TABLE& x) - { - // The swap code can work when swapping a container with itself - // but it triggers an assertion in buffered_functions. - // At the moment, I'd rather leave that assertion in and add a - // check here, rather than remove the assertion. I might change - // this at a later date. - if(this == &x) return; - - // These can throw, but they only affect the function objects - // that aren't in use so it is strongly exception safe, via. - // double buffering. - functions_ptr new_func_this = functions_.buffer(x.functions_); - functions_ptr new_func_that = x.functions_.buffer(functions_); - - if(data_.allocators_ == x.data_.allocators_) { - data_.swap(x.data_); // no throw - } - else { - // Create new buckets in separate HASH_TABLE_DATA objects - // which will clean up if anything throws an exception. - // (all can throw, but with no effect as these are new objects). - data new_this(data_, x.min_buckets_for_size(x.data_.size_)); - x.copy_buckets_to(new_this); - - data new_that(x.data_, min_buckets_for_size(data_.size_)); - copy_buckets_to(new_that); - - // Start updating the data here, no throw from now on. - data_.swap(new_this); - x.data_.swap(new_that); - } - - // We've made it, the rest is no throw. - std::swap(mlf_, x.mlf_); - - functions_.set(new_func_this); - x.functions_.set(new_func_that); - - calculate_max_load(); - x.calculate_max_load(); - } - - // Move - // - // ---------------------------------------------------------------- - // - // Strong exception safety (might change unused function objects) - // - // Can throw if hash or predicate object's copy constructor throws - // or if allocators are unequal. - - void move(BOOST_UNORDERED_TABLE& x) - { - // This can throw, but it only affects the function objects - // that aren't in use so it is strongly exception safe, via. - // double buffering. - functions_ptr new_func_this = functions_.buffer(x.functions_); - - if(data_.allocators_ == x.data_.allocators_) { - data_.move(x.data_); // no throw - } - else { - // Create new buckets in separate HASH_TABLE_DATA objects - // which will clean up if anything throws an exception. - // (all can throw, but with no effect as these are new objects). - data new_this(data_, x.min_buckets_for_size(x.data_.size_)); - x.copy_buckets_to(new_this); - - // Start updating the data here, no throw from now on. - data_.move(new_this); - } - - // We've made it, the rest is no throw. - mlf_ = x.mlf_; - functions_.set(new_func_this); - calculate_max_load(); - } - - // accessors - - // no throw - node_allocator get_allocator() const - { - return data_.allocators_.node_alloc_; - } - - // no throw - hasher const& hash_function() const - { - return functions_.current().hash_function(); - } - - // no throw - key_equal const& key_eq() const - { - return functions_.current().key_eq(); - } - - // no throw - size_type size() const - { - return data_.size_; - } - - // no throw - bool empty() const - { - return data_.size_ == 0; - } - - // no throw - size_type max_size() const - { - using namespace std; - - // size < mlf_ * count - return double_to_size_t(ceil( - (double) mlf_ * max_bucket_count())) - 1; - } - - // strong safety - size_type bucket(key_type const& k) const - { - // hash_function can throw: - return data_.bucket_from_hash(hash_function()(k)); - } - - - // strong safety - bucket_ptr get_bucket(key_type const& k) const - { - return data_.buckets_ + static_cast(bucket(k)); - } - - // no throw - size_type bucket_count() const - { - return data_.bucket_manager_.bucket_count(); - } - - // no throw - size_type max_bucket_count() const - { - // -1 to account for the end marker. - return prev_prime(data_.allocators_.bucket_alloc_.max_size() - 1); - } - - private: - - // no throw - size_type min_buckets_for_size(size_type n) const - { - BOOST_ASSERT(mlf_ != 0); - - using namespace std; - - // From 6.3.1/13: - // size < mlf_ * count - // => count > size / mlf_ - // - // Or from rehash post-condition: - // count > size / mlf_ - return double_to_size_t(floor(n / (double) mlf_)) + 1; - } - - // no throw - void calculate_max_load() - { - using namespace std; - - // From 6.3.1/13: - // Only resize when size >= mlf_ * count - max_load_ = double_to_size_t(ceil( - (double) mlf_ * data_.bucket_manager_.bucket_count())); - } - - // basic exception safety - bool reserve(size_type n) - { - bool need_to_reserve = n >= max_load_; - // throws - basic: - if (need_to_reserve) rehash_impl(min_buckets_for_size(n)); - BOOST_ASSERT(n < max_load_ || n > max_size()); - return need_to_reserve; - } - - // basic exception safety - bool reserve_for_insert(size_type n) - { - bool need_to_reserve = n >= max_load_; - // throws - basic: - if (need_to_reserve) { - size_type s = size(); - s = s + (s >> 1); - s = s > n ? s : n; - rehash_impl(min_buckets_for_size(s)); - } - BOOST_ASSERT(n < max_load_ || n > max_size()); - return need_to_reserve; - } - - public: - - // no throw - float max_load_factor() const - { - return mlf_; - } - - // no throw - void max_load_factor(float z) - { - BOOST_ASSERT(z > 0); - mlf_ = (std::max)(z, minimum_max_load_factor); - calculate_max_load(); - } - - // no throw - float load_factor() const - { - BOOST_ASSERT(data_.bucket_manager_.bucket_count() != 0); - return static_cast(data_.size_) - / static_cast(data_.bucket_manager_.bucket_count()); - } - - // 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); - } - - static key_type const& extract(value_type const& v, - type_wrapper*) - { - return v; - } - - static key_type const& extract(value_type const& v, - void*) - { - 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) - { - 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) - { - 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&...) - { - return k; - } - -#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: - - // if hash function throws, basic exception safety - // strong otherwise. - void rehash(size_type n) - { - using namespace std; - - // no throw: - size_type min_size = min_buckets_for_size(size()); - // basic/strong: - rehash_impl(min_size > n ? min_size : n); - - BOOST_ASSERT((float) bucket_count() > (float) size() / max_load_factor() - && bucket_count() >= n); - } - - private: - - // if hash function throws, basic exception safety - // strong otherwise - void rehash_impl(size_type n) - { - n = next_prime(n); // no throw - - if (n == bucket_count()) // no throw - return; - - data new_buckets(data_, n); // throws, seperate - move_buckets_to(new_buckets); // basic/no throw - new_buckets.swap(data_); // no throw - calculate_max_load(); // no throw - } - - // move_buckets_to & copy_buckets_to - // - // if the hash function throws, basic excpetion safety - // no throw otherwise - - void move_buckets_to(data& dst) - { - BOOST_ASSERT(dst.size_ == 0); - //BOOST_ASSERT(src.allocators_.node_alloc_ == dst.allocators_.node_alloc_); - - data& src = this->data_; - hasher const& hf = this->hash_function(); - bucket_ptr end = src.buckets_end(); - - for(; src.cached_begin_bucket_ != end; - ++src.cached_begin_bucket_) { - bucket_ptr src_bucket = src.cached_begin_bucket_; - while(src_bucket->next_) { - // Move the first group of equivalent nodes in - // src_bucket to dst. - - // This next line throws iff the hash function throws. - bucket_ptr dst_bucket = dst.bucket_ptr_from_hash( - hf(extract_key(data::get_value(src_bucket->next_)))); - - link_ptr n = src_bucket->next_; - size_type count = src.unlink_group(&src_bucket->next_); - dst.link_group(n, dst_bucket, count); - } - } - } - - // basic excpetion safety. If an exception is thrown this will - // leave dst partially filled. - - void copy_buckets_to(data& dst) const - { - BOOST_ASSERT(dst.size_ == 0); - - // no throw: - data const& src = this->data_; - hasher const& hf = this->hash_function(); - bucket_ptr end = src.buckets_end(); - - // no throw: - for(bucket_ptr i = src.cached_begin_bucket_; i != end; ++i) { - // no throw: - for(link_ptr it = src.begin(i); - BOOST_UNORDERED_BORLAND_BOOL(it); it = data::next_group(it)) { - // hash function can throw. - bucket_ptr dst_bucket = dst.bucket_ptr_from_hash( - hf(extract_key(data::get_value(it)))); - // throws, strong - dst.copy_group(it, dst_bucket); - } - } - } - - public: - - // Insert functions - // - // basic exception safety, if hash function throws - // strong otherwise. - -#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 hash function throws, basic exception safety - // strong otherwise - template - iterator_base emplace(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 emplace_impl(a); - } - - // Emplace (equivalent key containers) - // (I'm using an overloaded emplace for both 'insert' and 'emplace') - - // if hash function throws, basic exception safety - // strong otherwise - template - iterator_base emplace_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 emplace_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); \ - } - - BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, - BOOST_UNORDERED_INSERT_IMPL, _) - -#undef BOOST_UNORDERED_INSERT_IMPL -#endif - - iterator_base emplace_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_ptr_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_for_insert(size() + 1)) - bucket = data_.bucket_ptr_from_hash(hash_value); - - // I'm relying on link_ptr not being invalidated by - // the rehash here. - return iterator_base(bucket, - (BOOST_UNORDERED_BORLAND_BOOL(position)) ? - data_.link_node(a, position) : - data_.link_node_in_bucket(a, bucket) - ); - } - - iterator_base emplace_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 - // to a matching key. - return emplace_impl(a); - } - else { - // Find the first node in the group - so that the node - // will be added at the end of the group. - - link_ptr start(it.node_); - while(data_.prev_in_group(start)->next_ == start) - start = data_.prev_in_group(start); - - // reserve has basic exception safety if the hash function - // throws, strong otherwise. - bucket_ptr base = reserve_for_insert(size() + 1) ? - get_bucket(extract_key(a.get()->value())) : it.bucket_; - - // Nothing after this point can throw - - return iterator_base(base, - data_.link_node(a, start)); - } - } - - // Insert from iterator range (equivalent key containers) - - private: - - // if hash function throws, or inserting > 1 element, basic exception safety - // strong otherwise - template - void insert_for_range(I i, I j, forward_traversal_tag) - { - size_type distance = unordered_detail::distance(i, j); - if(distance == 1) { - emplace(*i); - } - else { - // Only require basic exception safety here - reserve_for_insert(size() + distance); - node_constructor a(data_.allocators_); - - for (; i != j; ++i) { - a.construct(*i); - - key_type const& k = extract_key(a.get()->value()); - bucket_ptr bucket = get_bucket(k); - link_ptr position = find_iterator(bucket, k); - - if(BOOST_UNORDERED_BORLAND_BOOL(position)) - data_.link_node(a, position); - else - data_.link_node_in_bucket(a, bucket); - } - } - } - - // if hash function throws, or inserting > 1 element, basic exception safety - // strong otherwise - template - void insert_for_range(I i, I j, - boost::incrementable_traversal_tag) - { - // If only inserting 1 element, get the required - // safety since insert is only called once. - for (; i != j; ++i) emplace(*i); - } - - public: - - // if hash function throws, or inserting > 1 element, basic exception safety - // strong otherwise - template - void insert_range(I i, I j) - { - BOOST_DEDUCED_TYPENAME boost::iterator_traversal::type - iterator_traversal_tag; - insert_for_range(i, j, iterator_traversal_tag); - } -#else - // if hash function throws, basic exception safety - // strong otherwise - value_type& operator[](key_type const& k) - { - BOOST_STATIC_ASSERT(( - !boost::is_same::value)); - typedef BOOST_DEDUCED_TYPENAME value_type::second_type mapped_type; - - 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 data::get_value(pos); - else - { - // 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_pair(k, (mapped_type*) 0); - - // 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. - - return data::get_value(data_.link_node_in_bucket(a, bucket)); - } - } - -#if defined(BOOST_UNORDERED_STD_FORWARD) - - // Emplace (unique keys) - // (I'm using an overloaded emplace for both 'insert' and 'emplace') - - // if hash function throws, basic exception safety - // strong otherwise - template - std::pair emplace(Args&&... args) - { - return emplace_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) - { - // No side effects in this initial code - 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(std::forward(args)...); - - // 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. - - return std::pair(iterator_base(bucket, - data_.link_node_in_bucket(a, bucket)), true); - } - } - - template - std::pair emplace_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); - 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 { - // 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. - - return std::pair(iterator_base(bucket, - data_.link_node_in_bucket(a, bucket)), true); - } - } - - // Insert from iterators (unique keys) - - template - size_type insert_size(I i, I j, boost::forward_traversal_tag) - { - return unordered_detail::distance(i, j); - } - - template - size_type insert_size(I, I, boost::incrementable_traversal_tag) - { - return 1; - } - - template - size_type insert_size(I i, I j) - { - BOOST_DEDUCED_TYPENAME boost::iterator_traversal::type - iterator_traversal_tag; - return insert_size(i, j, iterator_traversal_tag); - } - - // if hash function throws, or inserting > 1 element, basic exception safety - // 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_); - - for (; i != j; ++i) { - // No side effects in this initial code - size_type hash_value = hash_function()(extract_key(*i)); - bucket_ptr bucket = data_.bucket_ptr_from_hash(hash_value); - link_ptr pos = find_iterator(bucket, extract_key(*i)); - - if (!BOOST_UNORDERED_BORLAND_BOOL(pos)) { - // 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). - a.construct(*i); - - // 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); - } - } - } - - 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: - - // erase_key - - // strong exception safety - size_type erase_key(key_type const& k) - { - // No side effects in initial section - bucket_ptr bucket = get_bucket(k); - link_ptr* it = find_for_erase(bucket, k); - - // No throw. - return *it ? data_.erase_group(it, bucket) : 0; - } - - // count - // - // strong exception safety, no side effects - size_type count(key_type const& k) const - { - link_ptr it = find_iterator(k); // throws, strong - return BOOST_UNORDERED_BORLAND_BOOL(it) ? data::group_count(it) : 0; - } - - // find - // - // strong exception safety, no side effects - iterator_base find(key_type const& k) const - { - bucket_ptr bucket = get_bucket(k); - link_ptr it = find_iterator(bucket, k); - - if (BOOST_UNORDERED_BORLAND_BOOL(it)) - return iterator_base(bucket, it); - else - return data_.end(); - } - - value_type& at(key_type const& k) const - { - bucket_ptr bucket = get_bucket(k); - link_ptr it = find_iterator(bucket, k); - - if (BOOST_UNORDERED_BORLAND_BOOL(it)) - return data::get_value(it); - else - throw std::out_of_range("Unable to find key in unordered_map."); - } - - // equal_range - // - // strong exception safety, no side effects - std::pair equal_range(key_type const& k) const - { - bucket_ptr bucket = get_bucket(k); - link_ptr it = find_iterator(bucket, k); - if (BOOST_UNORDERED_BORLAND_BOOL(it)) { - iterator_base first(iterator_base(bucket, it)); - iterator_base second(first); - second.increment_group(); - return std::pair(first, second); - } - else { - return std::pair( - data_.end(), data_.end()); - } - } - - // strong exception safety, no side effects - bool equal(key_type const& k, value_type const& v) const - { - return key_eq()(k, extract_key(v)); - } - - // strong exception safety, no side effects - link_ptr find_iterator(key_type const& k) const - { - return find_iterator(get_bucket(k), k); - } - - // strong exception safety, no side effects - link_ptr find_iterator(bucket_ptr bucket, - key_type const& k) const - { - link_ptr it = data_.begin(bucket); - while (BOOST_UNORDERED_BORLAND_BOOL(it) && !equal(k, data::get_value(it))) { - it = data::next_group(it); - } - - return it; - } - - // strong exception safety, no side effects - link_ptr* find_for_erase(bucket_ptr bucket, key_type const& k) const - { - link_ptr* it = &bucket->next_; - while(BOOST_UNORDERED_BORLAND_BOOL(*it) && !equal(k, data::get_value(*it))) - it = &data::next_group(*it); - - return it; - } - }; - - // - // Equals - unordered container equality comparison. - // - -#if BOOST_UNORDERED_EQUIVALENT_KEYS - template - inline bool group_equals( - BOOST_UNORDERED_TABLE_DATA*, - typename BOOST_UNORDERED_TABLE_DATA::link_ptr it1, - typename BOOST_UNORDERED_TABLE_DATA::link_ptr it2, - KeyType*, - type_wrapper*) - { - typedef BOOST_UNORDERED_TABLE_DATA data; - return data::group_count(it1) == data::group_count(it2); - } - - template - inline bool group_equals( - BOOST_UNORDERED_TABLE_DATA*, - typename BOOST_UNORDERED_TABLE_DATA::link_ptr it1, - typename BOOST_UNORDERED_TABLE_DATA::link_ptr it2, - KeyType*, - void*) - { - typedef BOOST_UNORDERED_TABLE_DATA data; - typename BOOST_UNORDERED_TABLE_DATA::link_ptr end1 = data::next_group(it1); - typename BOOST_UNORDERED_TABLE_DATA::link_ptr end2 = data::next_group(it2); - - do { - if(data::get_value(it1).second != data::get_value(it2).second) return false; - it1 = it1->next_; - it2 = it2->next_; - } while(it1 != end1 && it2 != end2); - return it1 == end1 && it2 == end2; - } -#else - template - inline bool group_equals( - BOOST_UNORDERED_TABLE_DATA*, - typename BOOST_UNORDERED_TABLE_DATA::link_ptr, - typename BOOST_UNORDERED_TABLE_DATA::link_ptr, - KeyType*, - type_wrapper*) - { - return true; - } - - template - inline bool group_equals( - BOOST_UNORDERED_TABLE_DATA*, - typename BOOST_UNORDERED_TABLE_DATA::link_ptr it1, - typename BOOST_UNORDERED_TABLE_DATA::link_ptr it2, - KeyType*, - void*) - { - typedef BOOST_UNORDERED_TABLE_DATA data; - return data::get_value(it1).second == data::get_value(it2).second; - } -#endif - - template - bool equals(BOOST_UNORDERED_TABLE const& t1, - BOOST_UNORDERED_TABLE const& t2) - { - typedef BOOST_UNORDERED_TABLE_DATA data; - typedef typename data::bucket_ptr bucket_ptr; - typedef typename data::link_ptr link_ptr; - - if(t1.size() != t2.size()) return false; - - for(bucket_ptr i = t1.data_.cached_begin_bucket_, - j = t1.data_.buckets_end(); i != j; ++i) - { - for(link_ptr it(i->next_); BOOST_UNORDERED_BORLAND_BOOL(it); it = data::next_group(it)) - { - link_ptr other_pos = t2.find_iterator(t2.extract_key(data::get_value(it))); - if(!BOOST_UNORDERED_BORLAND_BOOL(other_pos) || - !group_equals((data*)0, it, other_pos, (K*)0, (type_wrapper*)0)) - return false; - } - } - - return true; - } - - // Iterators - - template class BOOST_UNORDERED_ITERATOR; - template class BOOST_UNORDERED_CONST_ITERATOR; - template class BOOST_UNORDERED_LOCAL_ITERATOR; - template class BOOST_UNORDERED_CONST_LOCAL_ITERATOR; - class iterator_access; - - // Local Iterators - // - // all no throw - - template - class BOOST_UNORDERED_LOCAL_ITERATOR - : public boost::iterator < - std::forward_iterator_tag, - BOOST_DEDUCED_TYPENAME allocator_value_type::type, - std::ptrdiff_t, - BOOST_DEDUCED_TYPENAME allocator_pointer::type, - BOOST_DEDUCED_TYPENAME allocator_reference::type > - { - public: - typedef BOOST_DEDUCED_TYPENAME allocator_value_type::type value_type; - - private: - typedef BOOST_UNORDERED_TABLE_DATA data; - typedef BOOST_DEDUCED_TYPENAME data::link_ptr ptr; - typedef BOOST_UNORDERED_CONST_LOCAL_ITERATOR const_local_iterator; - - friend class BOOST_UNORDERED_CONST_LOCAL_ITERATOR; - ptr ptr_; - - public: - BOOST_UNORDERED_LOCAL_ITERATOR() : ptr_() { - BOOST_UNORDERED_MSVC_RESET_PTR(ptr_); - } - explicit BOOST_UNORDERED_LOCAL_ITERATOR(ptr x) : ptr_(x) {} - BOOST_DEDUCED_TYPENAME allocator_reference::type operator*() const - { return data::get_value(ptr_); } - value_type* operator->() const { return &data::get_value(ptr_); } - BOOST_UNORDERED_LOCAL_ITERATOR& operator++() { ptr_ = ptr_->next_; return *this; } - BOOST_UNORDERED_LOCAL_ITERATOR operator++(int) { BOOST_UNORDERED_LOCAL_ITERATOR tmp(ptr_); ptr_ = ptr_->next_; return tmp; } - bool operator==(BOOST_UNORDERED_LOCAL_ITERATOR x) const { return ptr_ == x.ptr_; } - bool operator==(const_local_iterator x) const { return ptr_ == x.ptr_; } - bool operator!=(BOOST_UNORDERED_LOCAL_ITERATOR x) const { return ptr_ != x.ptr_; } - bool operator!=(const_local_iterator x) const { return ptr_ != x.ptr_; } - }; - - template - class BOOST_UNORDERED_CONST_LOCAL_ITERATOR - : public boost::iterator < - std::forward_iterator_tag, - BOOST_DEDUCED_TYPENAME allocator_value_type::type, - std::ptrdiff_t, - BOOST_DEDUCED_TYPENAME allocator_const_pointer::type, - BOOST_DEDUCED_TYPENAME allocator_const_reference::type > - { - public: - typedef BOOST_DEDUCED_TYPENAME allocator_value_type::type value_type; - - private: - typedef BOOST_UNORDERED_TABLE_DATA data; - typedef BOOST_DEDUCED_TYPENAME data::link_ptr ptr; - typedef BOOST_UNORDERED_LOCAL_ITERATOR local_iterator; - friend class BOOST_UNORDERED_LOCAL_ITERATOR; - ptr ptr_; - - public: - BOOST_UNORDERED_CONST_LOCAL_ITERATOR() : ptr_() { - BOOST_UNORDERED_MSVC_RESET_PTR(ptr_); - } - explicit BOOST_UNORDERED_CONST_LOCAL_ITERATOR(ptr x) : ptr_(x) {} - BOOST_UNORDERED_CONST_LOCAL_ITERATOR(local_iterator x) : ptr_(x.ptr_) {} - BOOST_DEDUCED_TYPENAME allocator_const_reference::type - operator*() const { return data::get_value(ptr_); } - value_type const* operator->() const { return &data::get_value(ptr_); } - BOOST_UNORDERED_CONST_LOCAL_ITERATOR& operator++() { ptr_ = ptr_->next_; return *this; } - BOOST_UNORDERED_CONST_LOCAL_ITERATOR operator++(int) { BOOST_UNORDERED_CONST_LOCAL_ITERATOR tmp(ptr_); ptr_ = ptr_->next_; return tmp; } - bool operator==(local_iterator x) const { return ptr_ == x.ptr_; } - bool operator==(BOOST_UNORDERED_CONST_LOCAL_ITERATOR x) const { return ptr_ == x.ptr_; } - bool operator!=(local_iterator x) const { return ptr_ != x.ptr_; } - bool operator!=(BOOST_UNORDERED_CONST_LOCAL_ITERATOR x) const { return ptr_ != x.ptr_; } - }; - - // iterators - // - // all no throw - - - template - class BOOST_UNORDERED_ITERATOR - : public boost::iterator < - std::forward_iterator_tag, - BOOST_DEDUCED_TYPENAME allocator_value_type::type, - std::ptrdiff_t, - BOOST_DEDUCED_TYPENAME allocator_pointer::type, - BOOST_DEDUCED_TYPENAME allocator_reference::type > - { - public: - typedef BOOST_DEDUCED_TYPENAME allocator_value_type::type value_type; - - private: - typedef BOOST_DEDUCED_TYPENAME BOOST_UNORDERED_TABLE_DATA::iterator_base base; - typedef BOOST_UNORDERED_CONST_ITERATOR const_iterator; - friend class BOOST_UNORDERED_CONST_ITERATOR; - base base_; - - public: - - BOOST_UNORDERED_ITERATOR() : base_() {} - explicit BOOST_UNORDERED_ITERATOR(base const& x) : base_(x) {} - BOOST_DEDUCED_TYPENAME allocator_reference::type - operator*() const { return *base_; } - value_type* operator->() const { return &*base_; } - BOOST_UNORDERED_ITERATOR& operator++() { base_.increment(); return *this; } - BOOST_UNORDERED_ITERATOR operator++(int) { BOOST_UNORDERED_ITERATOR tmp(base_); base_.increment(); return tmp; } - bool operator==(BOOST_UNORDERED_ITERATOR const& x) const { return base_ == x.base_; } - bool operator==(const_iterator const& x) const { return base_ == x.base_; } - bool operator!=(BOOST_UNORDERED_ITERATOR const& x) const { return base_ != x.base_; } - bool operator!=(const_iterator const& x) const { return base_ != x.base_; } - }; - - template - class BOOST_UNORDERED_CONST_ITERATOR - : public boost::iterator < - std::forward_iterator_tag, - BOOST_DEDUCED_TYPENAME allocator_value_type::type, - std::ptrdiff_t, - BOOST_DEDUCED_TYPENAME allocator_const_pointer::type, - BOOST_DEDUCED_TYPENAME allocator_const_reference::type > - { - public: - typedef BOOST_DEDUCED_TYPENAME allocator_value_type::type value_type; - - private: - typedef BOOST_DEDUCED_TYPENAME BOOST_UNORDERED_TABLE_DATA::iterator_base base; - typedef BOOST_UNORDERED_ITERATOR iterator; - friend class BOOST_UNORDERED_ITERATOR; - friend class iterator_access; - base base_; - - public: - - BOOST_UNORDERED_CONST_ITERATOR() : base_() {} - explicit BOOST_UNORDERED_CONST_ITERATOR(base const& x) : base_(x) {} - BOOST_UNORDERED_CONST_ITERATOR(iterator const& x) : base_(x.base_) {} - BOOST_DEDUCED_TYPENAME allocator_const_reference::type - operator*() const { return *base_; } - value_type const* operator->() const { return &*base_; } - BOOST_UNORDERED_CONST_ITERATOR& operator++() { base_.increment(); return *this; } - BOOST_UNORDERED_CONST_ITERATOR operator++(int) { BOOST_UNORDERED_CONST_ITERATOR tmp(base_); base_.increment(); return tmp; } - bool operator==(iterator const& x) const { return base_ == x.base_; } - bool operator==(BOOST_UNORDERED_CONST_ITERATOR const& x) const { return base_ == x.base_; } - bool operator!=(iterator const& x) const { return base_ != x.base_; } - bool operator!=(BOOST_UNORDERED_CONST_ITERATOR const& x) const { return base_ != x.base_; } - }; - } -} - -#undef BOOST_UNORDERED_TABLE -#undef BOOST_UNORDERED_TABLE_DATA -#undef BOOST_UNORDERED_ITERATOR -#undef BOOST_UNORDERED_CONST_ITERATOR -#undef BOOST_UNORDERED_LOCAL_ITERATOR -#undef BOOST_UNORDERED_CONST_LOCAL_ITERATOR diff --git a/include/boost/unordered/detail/move.hpp b/include/boost/unordered/detail/move.hpp index 1376f35b..16fd9212 100644 --- a/include/boost/unordered/detail/move.hpp +++ b/include/boost/unordered/detail/move.hpp @@ -11,7 +11,7 @@ #ifndef BOOST_UNORDERED_DETAIL_MOVE_HEADER #define BOOST_UNORDERED_DETAIL_MOVE_HEADER - +#include #include #include #include @@ -20,7 +20,20 @@ #include #include #include -#include +#include + +/*************************************************************************************************/ + +#if defined(BOOST_NO_SFINAE) +# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN +#elif defined(__GNUC__) && \ + (__GNUC__ < 3 || __GNUC__ == 3 && __GNUC_MINOR__ <= 3) +# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN +#elif BOOST_WORKAROUND(BOOST_INTEL, < 900) || \ + BOOST_WORKAROUND(__EDG_VERSION__, < 304) || \ + BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0593)) +# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN +#endif /*************************************************************************************************/ @@ -96,6 +109,8 @@ struct move_from { explicit move_from(T& x) : source(x) { } T& source; +private: + move_from& operator=(move_from const&); }; /*************************************************************************************************/ diff --git a/include/boost/unordered/detail/node.hpp b/include/boost/unordered/detail/node.hpp new file mode 100644 index 00000000..85a31410 --- /dev/null +++ b/include/boost/unordered/detail/node.hpp @@ -0,0 +1,226 @@ + +// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. +// Copyright (C) 2005-2009 Daniel James +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// This contains the basic data structure, apart from the actual values. There's +// no construction or deconstruction here. So this only depends on the pointer +// type. + +#ifndef BOOST_UNORDERED_DETAIL_NODE_HPP_INCLUDED +#define BOOST_UNORDERED_DETAIL_NODE_HPP_INCLUDED + +#include +#include +#include +#include + +#if BOOST_WORKAROUND(__BORLANDC__, <= 0X0582) +#define BOOST_UNORDERED_BORLAND_BOOL(x) (bool)(x) +#else +#define BOOST_UNORDERED_BORLAND_BOOL(x) x +#endif + +namespace boost { namespace unordered_detail { + + //////////////////////////////////////////////////////////////////////////// + // ungrouped node implementation + + template + inline BOOST_DEDUCED_TYPENAME ungrouped_node_base::node_ptr& + ungrouped_node_base::next_group(node_ptr ptr) + { + return ptr->next_; + } + + template + inline std::size_t ungrouped_node_base::group_count(node_ptr) + { + return 1; + } + + template + inline void ungrouped_node_base::add_to_bucket(node_ptr n, bucket& b) + { + n->next_ = b.next_; + b.next_ = n; + } + + template + inline void ungrouped_node_base::add_after_node(node_ptr n, + node_ptr position) + { + n->next_ = position->next_; + position->next_ = position; + } + + template + inline void ungrouped_node_base::unlink_nodes(bucket& b, + node_ptr begin, node_ptr end) + { + node_ptr* pos = &b.next_; + while(*pos != begin) pos = &(*pos)->next_; + *pos = end; + } + + template + inline void ungrouped_node_base::unlink_nodes(bucket& b, node_ptr end) + { + b.next_ = end; + } + + template + inline void ungrouped_node_base::unlink_node(bucket& b, node_ptr n) + { + unlink_nodes(b, n, n->next_); + } + + //////////////////////////////////////////////////////////////////////////// + // grouped node implementation + + // If ptr is the first element in a group, return pointer to next group. + // Otherwise returns a pointer to ptr. + template + inline BOOST_DEDUCED_TYPENAME grouped_node_base::node_ptr& + grouped_node_base::next_group(node_ptr ptr) + { + return get(ptr).group_prev_->next_; + } + + template + inline BOOST_DEDUCED_TYPENAME grouped_node_base::node_ptr + grouped_node_base::first_in_group(node_ptr ptr) + { + while(next_group(ptr) == ptr) + ptr = get(ptr).group_prev_; + return ptr; + } + + template + inline std::size_t grouped_node_base::group_count(node_ptr ptr) + { + node_ptr start = ptr; + std::size_t size = 0; + do { + ++size; + ptr = get(ptr).group_prev_; + } while(ptr != start); + return size; + } + + template + inline void grouped_node_base::add_to_bucket(node_ptr n, bucket& b) + { + n->next_ = b.next_; + get(n).group_prev_ = n; + b.next_ = n; + } + + template + inline void grouped_node_base::add_after_node(node_ptr n, node_ptr pos) + { + n->next_ = next_group(pos); + get(n).group_prev_ = get(pos).group_prev_; + next_group(pos) = n; + get(pos).group_prev_ = n; + } + + // Break a ciruclar list into two, with split as the beginning + // of the second group (if split is at the beginning then don't + // split). + template + inline BOOST_DEDUCED_TYPENAME grouped_node_base::node_ptr + grouped_node_base::split_group(node_ptr split) + { + node_ptr first = first_in_group(split); + if(first == split) return split; + + node_ptr last = get(first).group_prev_; + get(first).group_prev_ = get(split).group_prev_; + get(split).group_prev_ = last; + + return first; + } + + template + void grouped_node_base::unlink_node(bucket& b, node_ptr n) + { + node_ptr next = n->next_; + node_ptr* pos = &next_group(n); + + if(*pos != n) { + // The node is at the beginning of a group. + + // Find the previous node pointer: + pos = &b.next_; + while(*pos != n) pos = &next_group(*pos); + + // Remove from group + if(BOOST_UNORDERED_BORLAND_BOOL(next) && + get(next).group_prev_ == n) + { + get(next).group_prev_ = get(n).group_prev_; + } + } + else if(BOOST_UNORDERED_BORLAND_BOOL(next) && + get(next).group_prev_ == n) + { + // The deleted node is not at the end of the group, so + // change the link from the next node. + get(next).group_prev_ = get(n).group_prev_; + } + else { + // The deleted node is at the end of the group, so the + // first node in the group is pointing to it. + // Find that to change its pointer. + node_ptr x = get(n).group_prev_; + while(get(x).group_prev_ != n) { + x = get(x).group_prev_; + } + get(x).group_prev_ = get(n).group_prev_; + } + *pos = next; + } + + template + void grouped_node_base::unlink_nodes(bucket& b, + node_ptr begin, node_ptr end) + { + node_ptr* pos = &next_group(begin); + + if(*pos != begin) { + // The node is at the beginning of a group. + + // Find the previous node pointer: + pos = &b.next_; + while(*pos != begin) pos = &next_group(*pos); + + // Remove from group + if(BOOST_UNORDERED_BORLAND_BOOL(end)) split_group(end); + } + else { + node_ptr group1 = split_group(begin); + if(BOOST_UNORDERED_BORLAND_BOOL(end)) { + node_ptr group2 = split_group(end); + + if(begin == group2) { + node_ptr end1 = get(group1).group_prev_; + node_ptr end2 = get(group2).group_prev_; + get(group1).group_prev_ = end2; + get(group2).group_prev_ = end1; + } + } + } + *pos = end; + } + + template + void grouped_node_base::unlink_nodes(bucket& b, node_ptr end) + { + split_group(end); + b.next_ = end; + } +}} + +#endif diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp new file mode 100644 index 00000000..4e7a5811 --- /dev/null +++ b/include/boost/unordered/detail/table.hpp @@ -0,0 +1,740 @@ + +// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. +// Copyright (C) 2005-2009 Daniel James +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED +#define BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED + +#include +#include +#include +#include +#include + +#include +#include + +namespace boost { namespace unordered_detail { + + //////////////////////////////////////////////////////////////////////////// + // Helper methods + + // strong exception safety, no side effects + template + inline bool hash_table::equal( + key_type const& k, value_type const& v) const + { + return this->key_eq()(k, get_key(v)); + } + + // strong exception safety, no side effects + template + inline BOOST_DEDUCED_TYPENAME hash_table::node_ptr + hash_table::find_iterator( + bucket_ptr bucket, key_type const& k) const + { + node_ptr it = bucket->next_; + while (BOOST_UNORDERED_BORLAND_BOOL(it) && + !equal(k, node::get_value(it))) + { + it = node::next_group(it); + } + + return it; + } + + // strong exception safety, no side effects + // pre: this->buckets_ + template + inline BOOST_DEDUCED_TYPENAME hash_table::node_ptr + hash_table::find_iterator(key_type const& k) const + { + return find_iterator(this->get_bucket(this->bucket_index(k)), k); + } + + // strong exception safety, no side effects + template + inline BOOST_DEDUCED_TYPENAME hash_table::node_ptr* + hash_table::find_for_erase( + bucket_ptr bucket, key_type const& k) const + { + node_ptr* it = &bucket->next_; + while(BOOST_UNORDERED_BORLAND_BOOL(*it) && + !equal(k, node::get_value(*it))) + { + it = &node::next_group(*it); + } + + return it; + } + + //////////////////////////////////////////////////////////////////////////// + // Load methods + + // no throw + template + std::size_t hash_table::max_size() const + { + using namespace std; + + // size < mlf_ * count + return double_to_size_t(ceil( + (double) this->mlf_ * this->max_bucket_count())) - 1; + } + + // strong safety + template + inline std::size_t hash_table::bucket_index( + key_type const& k) const + { + // hash_function can throw: + return this->hash_function()(k) % this->bucket_count_; + } + + + // no throw + template + inline std::size_t hash_table::calculate_max_load() + { + using namespace std; + + // From 6.3.1/13: + // Only resize when size >= mlf_ * count + return double_to_size_t(ceil((double) mlf_ * this->bucket_count_)); + } + + template + void hash_table::max_load_factor(float z) + { + BOOST_ASSERT(z > 0); + mlf_ = (std::max)(z, minimum_max_load_factor); + this->max_load_ = this->calculate_max_load(); + } + + // no throw + template + inline std::size_t hash_table::min_buckets_for_size( + std::size_t size) const + { + BOOST_ASSERT(this->mlf_ != 0); + + using namespace std; + + // From 6.3.1/13: + // size < mlf_ * count + // => count > size / mlf_ + // + // Or from rehash post-condition: + // count > size / mlf_ + return next_prime(double_to_size_t(floor(size / (double) mlf_)) + 1); + } + + //////////////////////////////////////////////////////////////////////////// + // recompute_begin_bucket + + // init_buckets + + template + inline void hash_table::init_buckets() + { + if (this->size_) { + this->cached_begin_bucket_ = this->buckets_; + while (!this->cached_begin_bucket_->next_) + ++this->cached_begin_bucket_; + } else { + this->cached_begin_bucket_ = this->get_bucket(this->bucket_count_); + } + this->max_load_ = calculate_max_load(); + } + + // After an erase cached_begin_bucket_ might be left pointing to + // an empty bucket, so this is called to update it + // + // no throw + + template + inline void hash_table::recompute_begin_bucket(bucket_ptr b) + { + BOOST_ASSERT(!(b < this->cached_begin_bucket_)); + + if(b == this->cached_begin_bucket_) + { + if (this->size_ != 0) { + while (!this->cached_begin_bucket_->next_) + ++this->cached_begin_bucket_; + } else { + this->cached_begin_bucket_ = + this->get_bucket(this->bucket_count_); + } + } + } + + // This is called when a range has been erased + // + // no throw + + template + inline void hash_table::recompute_begin_bucket( + bucket_ptr b1, bucket_ptr b2) + { + BOOST_ASSERT(!(b1 < this->cached_begin_bucket_) && !(b2 < b1)); + BOOST_ASSERT(BOOST_UNORDERED_BORLAND_BOOL(b2->next_)); + + if(b1 == this->cached_begin_bucket_ && !b1->next_) + this->cached_begin_bucket_ = b2; + } + + // no throw + template + inline float hash_table::load_factor() const + { + BOOST_ASSERT(this->bucket_count_ != 0); + return static_cast(this->size_) + / static_cast(this->bucket_count_); + } + + //////////////////////////////////////////////////////////////////////////// + // Constructors + + template + hash_table::hash_table(std::size_t num_buckets, + hasher const& hf, key_equal const& eq, node_allocator const& a) + : buckets(a, next_prime(num_buckets)), + base(hf, eq), + size_(), + mlf_(1.0f), + cached_begin_bucket_(), + max_load_(0) + { + } + + // Copy Construct with allocator + + template + hash_table::hash_table(hash_table const& x, + node_allocator const& a) + : buckets(a, x.min_buckets_for_size(x.size_)), + base(x), + size_(x.size_), + mlf_(x.mlf_), + cached_begin_bucket_(), + max_load_(0) + { + if(x.size_) { + x.copy_buckets_to(*this); + this->init_buckets(); + } + } + + // Move Construct + + template + hash_table::hash_table(hash_table& x, move_tag) + : buckets(x.node_alloc(), x.bucket_count_), + base(x), + size_(0), + mlf_(1.0f), + cached_begin_bucket_(), + max_load_(0) + { + this->partial_swap(x); + } + + template + hash_table::hash_table(hash_table& x, + node_allocator const& a, move_tag) + : buckets(a, x.bucket_count_), + base(x), + size_(0), + mlf_(x.mlf_), + cached_begin_bucket_(), + max_load_(0) + { + if(a == x.node_alloc()) { + this->partial_swap(x); + } + else if(x.size_) { + x.copy_buckets_to(*this); + this->size_ = x.size_; + this->init_buckets(); + } + } + + template + hash_table& hash_table::operator=( + hash_table const& x) + { + hash_table tmp(x, this->node_alloc()); + this->fast_swap(tmp); + return *this; + } + + //////////////////////////////////////////////////////////////////////////// + // Swap & Move + + // Swap + // + // Strong exception safety + // + // Can throw if hash or predicate object's copy constructor throws + // or if allocators are unequal. + + template + inline void hash_table::partial_swap(hash_table& x) + { + this->buckets::swap(x); // No throw + std::swap(this->size_, x.size_); + std::swap(this->mlf_, x.mlf_); + std::swap(this->cached_begin_bucket_, x.cached_begin_bucket_); + std::swap(this->max_load_, x.max_load_); + } + + template + inline void hash_table::fast_swap(hash_table& x) + { + // These can throw, but they only affect the function objects + // that aren't in use so it is strongly exception safe, via. + // double buffering. + { + set_hash_functions op1(*this, x); + set_hash_functions op2(x, *this); + op1.commit(); + op2.commit(); + } + this->buckets::swap(x); // No throw + std::swap(this->size_, x.size_); + std::swap(this->mlf_, x.mlf_); + std::swap(this->cached_begin_bucket_, x.cached_begin_bucket_); + std::swap(this->max_load_, x.max_load_); + } + + template + inline void hash_table::slow_swap(hash_table& x) + { + if(this == &x) return; + + { + // These can throw, but they only affect the function objects + // that aren't in use so it is strongly exception safe, via. + // double buffering. + set_hash_functions op1(*this, x); + set_hash_functions op2(x, *this); + + // Create new buckets in separate hash_buckets objects + // which will clean up if anything throws an exception. + // (all can throw, but with no effect as these are new objects). + + buckets b1(this->node_alloc(), x.min_buckets_for_size(x.size_)); + if(x.size_) x.copy_buckets_to(b1); + + buckets b2(x.node_alloc(), this->min_buckets_for_size(this->size_)); + if(this->size_) copy_buckets_to(b2); + + // Modifying the data, so no throw from now on. + + b1.swap(*this); + b2.swap(x); + op1.commit(); + op2.commit(); + } + + std::swap(this->size_, x.size_); + + if(this->buckets_) this->init_buckets(); + if(x.buckets_) x.init_buckets(); + } + + template + void hash_table::swap(hash_table& x) + { + if(this->node_alloc() == x.node_alloc()) { + if(this != &x) this->fast_swap(x); + } + else { + this->slow_swap(x); + } + } + + + // Move + // + // Strong exception safety (might change unused function objects) + // + // Can throw if hash or predicate object's copy constructor throws + // or if allocators are unequal. + + template + void hash_table::move(hash_table& x) + { + // This can throw, but it only affects the function objects + // that aren't in use so it is strongly exception safe, via. + // double buffering. + set_hash_functions new_func_this(*this, x); + + if(this->node_alloc() == x.node_alloc()) { + this->buckets::move(x); // no throw + this->size_ = x.size_; + this->cached_begin_bucket_ = x.cached_begin_bucket_; + this->max_load_ = x.max_load_; + x.size_ = 0; + } + else { + // Create new buckets in separate HASH_TABLE_DATA objects + // which will clean up if anything throws an exception. + // (all can throw, but with no effect as these are new objects). + + buckets b(this->node_alloc(), x.min_buckets_for_size(x.size_)); + if(x.size_) x.copy_buckets_to(b); + + // Start updating the data here, no throw from now on. + this->size_ = x.size_; + b.swap(*this); + this->init_buckets(); + } + + // We've made it, the rest is no throw. + this->mlf_ = x.mlf_; + new_func_this.commit(); + } + + //////////////////////////////////////////////////////////////////////////// + // Reserve & Rehash + + // basic exception safety + template + inline void hash_table::create_for_insert(std::size_t size) + { + this->bucket_count_ = (std::max)(this->bucket_count_, + this->min_buckets_for_size(size)); + this->create_buckets(); + this->init_buckets(); + } + + // basic exception safety + template + inline bool hash_table::reserve_for_insert(std::size_t size) + { + if(size >= max_load_) { + std::size_t num_buckets + = this->min_buckets_for_size((std::max)(size, + this->size_ + (this->size_ >> 1))); + if(num_buckets != this->bucket_count_) { + rehash_impl(num_buckets); + return true; + } + } + + return false; + } + + // if hash function throws, basic exception safety + // strong otherwise. + // TODO: Should this always create buckets? + template + inline void hash_table::rehash(std::size_t min_buckets) + { + using namespace std; + + if(!this->buckets_) { + this->bucket_count_ = next_prime(min_buckets); + this->create_buckets(); + this->init_buckets(); + } + else { + // no throw: + // TODO: Needlessly calling next_prime twice. + min_buckets = (std::max)( + next_prime(min_buckets), + this->min_buckets_for_size(this->size_)); + if(min_buckets != this->bucket_count_) rehash_impl(min_buckets); + } + } + + // if hash function throws, basic exception safety + // strong otherwise + + template + void hash_table + ::rehash_impl(std::size_t num_buckets) + { + hasher const& hf = this->hash_function(); + std::size_t size = this->size_; + bucket_ptr end = this->get_bucket(this->bucket_count_); + + buckets dst(this->node_alloc(), num_buckets); + dst.create_buckets(); + + buckets src(this->node_alloc(), this->bucket_count_); + src.swap(*this); + this->size_ = 0; + + for(bucket_ptr bucket = this->cached_begin_bucket_; + bucket != end; ++bucket) + { + node_ptr group = bucket->next_; + while(group) { + // Move the first group of equivalent nodes in bucket to dst. + + // This next line throws iff the hash function throws. + bucket_ptr dst_bucket = dst.bucket_ptr_from_hash( + hf(get_key_from_ptr(group))); + + node_ptr& next_group = node::next_group(group); + bucket->next_ = next_group; + next_group = dst_bucket->next_; + dst_bucket->next_ = group; + group = bucket->next_; + } + } + + // Swap the new nodes back into the container and setup the local + // variables. + this->size_ = size; + dst.swap(*this); // no throw + this->init_buckets(); + } + + //////////////////////////////////////////////////////////////////////////// + // copy_buckets_to + + // copy_buckets_to + // + // basic excpetion safety. If an exception is thrown this will + // leave dst partially filled. + + template + void hash_table + ::copy_buckets_to(buckets& dst) const + { + BOOST_ASSERT(this->buckets_ && !dst.buckets_); + + hasher const& hf = this->hash_function(); + bucket_ptr end = this->get_bucket(this->bucket_count_); + + hash_node_constructor a(dst); + dst.create_buckets(); + + // no throw: + for(bucket_ptr i = this->cached_begin_bucket_; i != end; ++i) { + // no throw: + for(node_ptr it = i->next_; it;) { + // hash function can throw. + bucket_ptr dst_bucket = dst.bucket_ptr_from_hash( + hf(get_key_from_ptr(it))); + // throws, strong + + node_ptr group_end = node::next_group(it); + + a.construct(node::get_value(it)); + node_ptr n = a.release(); + node::add_to_bucket(n, *dst_bucket); + + for(it = it->next_; it != group_end; it = it->next_) { + a.construct(node::get_value(it)); + node::add_after_node(a.release(), n); + } + } + } + } + + //////////////////////////////////////////////////////////////////////////// + // Misc. key methods + + // strong exception safety + + // count + // + // strong exception safety, no side effects + + template + std::size_t hash_table::count(key_type const& k) const + { + if(!this->size_) return 0; + node_ptr it = find_iterator(k); // throws, strong + return BOOST_UNORDERED_BORLAND_BOOL(it) ? node::group_count(it) : 0; + } + + // find + // + // strong exception safety, no side effects + template + BOOST_DEDUCED_TYPENAME hash_table::iterator_base + hash_table::find(key_type const& k) const + { + if(!this->size_) return this->end(); + + bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); + node_ptr it = find_iterator(bucket, k); + + if (BOOST_UNORDERED_BORLAND_BOOL(it)) + return iterator_base(bucket, it); + else + return this->end(); + } + + template + BOOST_DEDUCED_TYPENAME A::value_type& + hash_table::at(key_type const& k) const + { + if(!this->size_) + throw std::out_of_range("Unable to find key in unordered_map."); + + bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); + node_ptr it = find_iterator(bucket, k); + + if (BOOST_UNORDERED_BORLAND_BOOL(it)) + return node::get_value(it); + else + throw std::out_of_range("Unable to find key in unordered_map."); + } + + // equal_range + // + // strong exception safety, no side effects + template + BOOST_DEDUCED_TYPENAME hash_table::iterator_pair + hash_table::equal_range(key_type const& k) const + { + if(!this->size_) + return iterator_pair(this->end(), this->end()); + + bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); + node_ptr it = find_iterator(bucket, k); + if (BOOST_UNORDERED_BORLAND_BOOL(it)) { + iterator_base first(iterator_base(bucket, it)); + iterator_base second(first); + second.increment_bucket(node::next_group(second.node_)); + return iterator_pair(first, second); + } + else { + return iterator_pair(this->end(), this->end()); + } + } + + //////////////////////////////////////////////////////////////////////////// + // Erase methods + + template + void hash_table::clear() + { + // TODO: Is this check needed when called internally? + if(!this->size_) return; + + bucket_ptr end = this->get_bucket(this->bucket_count_); + for(bucket_ptr begin = this->buckets_; begin != end; ++begin) { + this->clear_bucket(begin); + } + + this->size_ = 0; + this->cached_begin_bucket_ = end; + } + + template + inline std::size_t hash_table::erase_group( + node_ptr* it, bucket_ptr bucket) + { + node_ptr pos = *it; + node_ptr end = node::next_group(pos); + *it = end; + std::size_t count = this->delete_nodes(pos, end); + this->size_ -= count; + this->recompute_begin_bucket(bucket); + return count; + } + + template + std::size_t hash_table + ::erase_key(key_type const& k) + { + if(!this->size_) return 0; + + // No side effects in initial section + bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); + node_ptr* it = this->find_for_erase(bucket, k); + + // No throw. + return *it ? this->erase_group(it, bucket) : 0; + } + + + template + BOOST_DEDUCED_TYPENAME hash_table::iterator_base + hash_table::erase(iterator_base r) + { + BOOST_ASSERT(r.node_); + iterator_base next = r; + next.increment(); + --this->size_; + node::unlink_node(*r.bucket_, r.node_); + this->delete_node(r.node_); + // r has been invalidated but its bucket is still valid + this->recompute_begin_bucket(r.bucket_, next.bucket_); + return next; + } + + template + BOOST_DEDUCED_TYPENAME hash_table::iterator_base + hash_table::erase_range( + iterator_base r1, iterator_base r2) + { + if(r1 != r2) + { + BOOST_ASSERT(r1.node_); + if (r1.bucket_ == r2.bucket_) { + node::unlink_nodes(*r1.bucket_, r1.node_, r2.node_); + this->size_ -= this->delete_nodes(r1.node_, r2.node_); + + // No need to call recompute_begin_bucket because + // the nodes are only deleted from one bucket, which + // still contains r2 after the erase. + BOOST_ASSERT(r1.bucket_->next_); + } + else { + bucket_ptr end_bucket = r2.node_ ? + r2.bucket_ : this->get_bucket(this->bucket_count_); + BOOST_ASSERT(r1.bucket_ < end_bucket); + node::unlink_nodes(*r1.bucket_, r1.node_, node_ptr()); + this->size_ -= this->delete_nodes(r1.node_, node_ptr()); + + bucket_ptr i = r1.bucket_; + for(++i; i != end_bucket; ++i) { + this->size_ -= this->delete_nodes(i->next_, node_ptr()); + i->next_ = node_ptr(); + } + + if(r2.node_) { + node_ptr first = r2.bucket_->next_; + node::unlink_nodes(*r2.bucket_, r2.node_); + this->size_ -= this->delete_nodes(first, r2.node_); + } + + // r1 has been invalidated but its bucket is still + // valid. + this->recompute_begin_bucket(r1.bucket_, end_bucket); + } + } + + return r2; + } + + template + BOOST_DEDUCED_TYPENAME hash_table::iterator_base + hash_table::emplace_empty_impl_with_node( + node_constructor& a, std::size_t size) + { + key_type const& k = get_key(a.value()); + std::size_t hash_value = this->hash_function()(k); + if(this->buckets_) this->reserve_for_insert(size); + else this->create_for_insert(size); + bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); + node_ptr n = a.release(); + node::add_to_bucket(n, *bucket); + ++this->size_; + this->cached_begin_bucket_ = bucket; + return iterator_base(bucket, n); + } +}} + +#endif diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp new file mode 100644 index 00000000..b4a5157c --- /dev/null +++ b/include/boost/unordered/detail/unique.hpp @@ -0,0 +1,389 @@ + +// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. +// Copyright (C) 2005-2009 Daniel James +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED +#define BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED + +#include +#include + +namespace boost { namespace unordered_detail { + + //////////////////////////////////////////////////////////////////////////// + // Equality + + template + bool hash_unique_table + ::equals(hash_unique_table const& other) const + { + if(this->size_ != other.size_) return false; + if(!this->size_) return true; + + bucket_ptr end = this->get_bucket(this->bucket_count_); + for(bucket_ptr i = this->cached_begin_bucket_; i != end; ++i) + { + node_ptr it1 = i->next_; + while(BOOST_UNORDERED_BORLAND_BOOL(it1)) + { + node_ptr it2 = other.find_iterator(get_key_from_ptr(it1)); + if(!BOOST_UNORDERED_BORLAND_BOOL(it2)) return false; + if(!extractor::compare_mapped( + node::get_value(it1), node::get_value(it2))) + return false; + it1 = it1->next_; + } + } + + return true; + } + + //////////////////////////////////////////////////////////////////////////// + // A convenience method for adding nodes. + + template + inline BOOST_DEDUCED_TYPENAME hash_unique_table::node_ptr + hash_unique_table::add_node(node_constructor& a, + bucket_ptr bucket) + { + node_ptr n = a.release(); + node::add_to_bucket(n, *bucket); + ++this->size_; + if(bucket < this->cached_begin_bucket_) + this->cached_begin_bucket_ = bucket; + return n; + } + + //////////////////////////////////////////////////////////////////////////// + // Insert methods + + // if hash function throws, basic exception safety + // strong otherwise + template + BOOST_DEDUCED_TYPENAME hash_unique_table::value_type& + hash_unique_table::operator[](key_type const& k) + { + typedef BOOST_DEDUCED_TYPENAME value_type::second_type mapped_type; + + std::size_t hash_value = this->hash_function()(k); + bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); + + if(!this->buckets_) { + node_constructor a(*this); + a.construct_pair(k, (mapped_type*) 0); + return *this->emplace_empty_impl_with_node(a, 1); + } + + node_ptr pos = find_iterator(bucket, k); + + if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { + return node::get_value(pos); + } + else { + // 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(*this); + a.construct_pair(k, (mapped_type*) 0); + + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + if(this->reserve_for_insert(this->size_ + 1)) + bucket = this->bucket_ptr_from_hash(hash_value); + + // Nothing after this point can throw. + + return node::get_value(add_node(a, bucket)); + } + } + + template + inline BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return + hash_unique_table + ::emplace_impl_with_node(node_constructor& a) + { + // No side effects in this initial code + key_type const& k = get_key(a.value()); + std::size_t hash_value = this->hash_function()(k); + bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); + node_ptr pos = find_iterator(bucket, k); + + if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { + // Found an existing key, return it (no throw). + return emplace_return(iterator_base(bucket, pos), false); + } else { + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + if(this->reserve_for_insert(this->size_ + 1)) + bucket = this->bucket_ptr_from_hash(hash_value); + + // Nothing after this point can throw. + + return emplace_return( + iterator_base(bucket, add_node(a, bucket)), + true); + } + } + +#if defined(BOOST_UNORDERED_STD_FORWARD) + + template + template + inline BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return + hash_unique_table::emplace_impl(key_type const& k, + Args&&... args) + { + // No side effects in this initial code + std::size_t hash_value = this->hash_function()(k); + bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); + node_ptr pos = find_iterator(bucket, k); + + if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { + // Found an existing key, return it (no throw). + return emplace_return(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(*this); + a.construct(std::forward(args)...); + + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + if(this->reserve_for_insert(this->size_ + 1)) + bucket = this->bucket_ptr_from_hash(hash_value); + + // Nothing after this point can throw. + + return emplace_return( + iterator_base(bucket, add_node(a, bucket)), + true); + } + } + + template + template + inline BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return + hash_unique_table::emplace_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(*this); + a.construct(std::forward(args)...); + return emplace_impl_with_node(a); + } + + template + template + inline BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return + hash_unique_table::emplace_empty_impl(Args&&... args) + { + node_constructor a(*this); + a.construct(std::forward(args)...); + return emplace_return(this->emplace_empty_impl_with_node(a, 1), true); + } + +#else + +#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \ + template \ + template \ + inline BOOST_DEDUCED_TYPENAME \ + hash_unique_table::emplace_return \ + hash_unique_table::emplace_impl( \ + key_type const& k, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ + { \ + std::size_t hash_value = this->hash_function()(k); \ + bucket_ptr bucket \ + = this->bucket_ptr_from_hash(hash_value); \ + node_ptr pos = find_iterator(bucket, k); \ + \ + if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { \ + return emplace_return(iterator_base(bucket, pos), false); \ + } else { \ + node_constructor a(*this); \ + a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ + \ + if(this->reserve_for_insert(this->size_ + 1)) \ + bucket = this->bucket_ptr_from_hash(hash_value); \ + \ + return emplace_return(iterator_base(bucket, \ + add_node(a, bucket)), true); \ + } \ + } \ + \ + template \ + template \ + inline BOOST_DEDUCED_TYPENAME \ + hash_unique_table::emplace_return \ + hash_unique_table:: \ + emplace_impl(no_key, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ + { \ + node_constructor a(*this); \ + a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ + return emplace_impl_with_node(a); \ + } \ + \ + template \ + template \ + inline BOOST_DEDUCED_TYPENAME \ + hash_unique_table::emplace_return \ + hash_unique_table:: \ + emplace_empty_impl( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ + { \ + node_constructor a(*this); \ + a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ + return emplace_return(this->emplace_empty_impl_with_node(a, 1), true); \ + } + + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_INSERT_IMPL, _) + +#undef BOOST_UNORDERED_INSERT_IMPL + +#endif + +#if defined(BOOST_UNORDERED_STD_FORWARD) + + // Emplace (unique keys) + // (I'm using an overloaded emplace for both 'insert' and 'emplace') + + // if hash function throws, basic exception safety + // strong otherwise + + template + template + BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return + hash_unique_table::emplace(Args&&... args) + { + return this->size_ ? + emplace_impl( + extractor::extract(std::forward(args)...), + std::forward(args)...) : + emplace_empty_impl(std::forward(args)...); + } + +#else + + template + template + BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return + hash_unique_table::emplace(Arg0 const& arg0) + { + return this->size_ ? + emplace_impl(extractor::extract(arg0), arg0) : + emplace_empty_impl(arg0); + } + +#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \ + template \ + template \ + BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return \ + hash_unique_table::emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ + { \ + return this->size_ ? \ + emplace_impl(extractor::extract(arg0, arg1), \ + BOOST_UNORDERED_CALL_PARAMS(z, num_params)) : \ + emplace_empty_impl( \ + BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ + } + + BOOST_PP_REPEAT_FROM_TO(2, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_INSERT_IMPL, _) + +#undef BOOST_UNORDERED_INSERT_IMPL + +#endif + + //////////////////////////////////////////////////////////////////////////// + // Insert range methods + + template + template + inline void hash_unique_table::insert_range_impl( + key_type const&, InputIt i, InputIt j) + { + node_constructor a(*this); + + if(!this->size_) { + a.construct(*i); + this->emplace_empty_impl_with_node(a, 1); + ++i; + if(i == j) return; + } + + do { + // No side effects in this initial code + // Note: can't use get_key as '*i' might not be value_type. + // TODO: Check if std::pair has an appropriate constructor. If not + // that might not be true. + // TODO: Test this line better. + key_type const& k = extractor::extract(*i); + std::size_t hash_value = this->hash_function()(k); + bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); + node_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. + + // Create the node before rehashing in case it throws an + // exception (need strong safety in such a case). + a.construct(*i); + + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + if(this->size_ + 1 >= this->max_load_) { + this->reserve_for_insert(this->size_ + insert_size(i, j)); + bucket = this->bucket_ptr_from_hash(hash_value); + } + + // Nothing after this point can throw. + add_node(a, bucket); + } + } while(++i != j); + } + + template + template + inline void hash_unique_table::insert_range_impl( + no_key, InputIt i, InputIt j) + { + node_constructor a(*this); + + if(!this->size_) { + a.construct(*i); + this->emplace_empty_impl_with_node(a, 1); + ++i; + if(i == j) return; + } + + do { + // No side effects in this initial code + a.construct(*i); + emplace_impl_with_node(a); + } while(++i != j); + } + + // if hash function throws, or inserting > 1 element, basic exception safety + // strong otherwise + template + template + void hash_unique_table::insert_range(InputIt i, InputIt j) + { + if(i != j) + return insert_range_impl(extractor::extract(*i), i, j); + } +}} + +#endif diff --git a/include/boost/unordered/detail/util.hpp b/include/boost/unordered/detail/util.hpp new file mode 100644 index 00000000..1f592dd3 --- /dev/null +++ b/include/boost/unordered/detail/util.hpp @@ -0,0 +1,320 @@ + +// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. +// Copyright (C) 2005-2009 Daniel James +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_UNORDERED_DETAIL_UTIL_HPP_INCLUDED +#define BOOST_UNORDERED_DETAIL_UTIL_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { namespace unordered_detail { + + //////////////////////////////////////////////////////////////////////////// + // convert double to std::size_t + + inline std::size_t double_to_size_t(double f) + { + return f >= static_cast( + (std::numeric_limits::max)()) ? + (std::numeric_limits::max)() : + static_cast(f); + } + + //////////////////////////////////////////////////////////////////////////// + // primes + + template struct prime_list_template + { + static std::size_t const value[]; + static std::ptrdiff_t const length; + }; + +#define BOOST_UNORDERED_PRIMES \ + (5ul)(11ul)(17ul)(29ul)(37ul)(53ul)(67ul)(79ul) \ + (97ul)(131ul)(193ul)(257ul)(389ul)(521ul)(769ul) \ + (1031ul)(1543ul)(2053ul)(3079ul)(6151ul)(12289ul)(24593ul) \ + (49157ul)(98317ul)(196613ul)(393241ul)(786433ul) \ + (1572869ul)(3145739ul)(6291469ul)(12582917ul)(25165843ul) \ + (50331653ul)(100663319ul)(201326611ul)(402653189ul)(805306457ul) \ + (1610612741ul)(3221225473ul)(4294967291ul) + + template + std::size_t const prime_list_template::value[] = { + BOOST_PP_SEQ_ENUM(BOOST_UNORDERED_PRIMES) + }; + + template + std::ptrdiff_t const prime_list_template::length + = BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES); + +#undef BOOST_UNORDERED_PRIMES + + typedef prime_list_template prime_list; + + // no throw + inline std::size_t next_prime(std::size_t num) { + std::size_t const* const prime_list_begin = prime_list::value; + std::size_t const* const prime_list_end = prime_list_begin + + prime_list::length; + std::size_t const* bound = + std::lower_bound(prime_list_begin, prime_list_end, num); + if(bound == prime_list_end) + bound--; + return *bound; + } + + // no throw + inline std::size_t prev_prime(std::size_t num) { + std::size_t const* const prime_list_begin = prime_list::value; + std::size_t const* const prime_list_end = prime_list_begin + + prime_list::length; + std::size_t const* bound = + std::upper_bound(prime_list_begin,prime_list_end, num); + if(bound != prime_list_begin) + bound--; + return *bound; + } + + //////////////////////////////////////////////////////////////////////////// + // pair_cast - because some libraries don't have the full pair constructors. + + template + inline std::pair pair_cast(std::pair const& x) + { + return std::pair(Dst1(x.first), Dst2(x.second)); + } + + //////////////////////////////////////////////////////////////////////////// + // insert_size/initial_size + +#if !defined(BOOST_NO_STD_DISTANCE) + using ::std::distance; +#else + template + inline std::size_t distance(ForwardIterator i, ForwardIterator j) { + std::size_t x; + std::distance(i, j, x); + return x; + } +#endif + + template + inline std::size_t insert_size(I i, I j, boost::forward_traversal_tag) + { + return std::distance(i, j); + } + + template + inline std::size_t insert_size(I, I, boost::incrementable_traversal_tag) + { + return 1; + } + + template + inline std::size_t insert_size(I i, I j) + { + BOOST_DEDUCED_TYPENAME boost::iterator_traversal::type + iterator_traversal_tag; + return insert_size(i, j, iterator_traversal_tag); + } + + template + inline std::size_t initial_size(I i, I j, + std::size_t num_buckets = boost::unordered_detail::default_bucket_count) + { + return (std::max)(static_cast(insert_size(i, j)) + 1, + num_buckets); + } + + //////////////////////////////////////////////////////////////////////////// + // Node Constructors + +#if defined(BOOST_UNORDERED_STD_FORWARD) + + template + inline void construct_impl(T*, void* address, Args&&... args) + { + new(address) T(std::forward(args)...); + } + +#if defined(BOOST_UNORDERED_CPP0X_PAIR) + template + inline void construct_impl(std::pair*, void* address, + Key&& k, Arg0&& arg0, Args&&... args) + ) + { + new(address) std::pair(k, + Second(arg0, std::forward(args)...); + } +#endif + +#else + +#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \ + template < \ + class T, \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \ + > \ + inline void construct_impl( \ + T*, void* address, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \ + ) \ + { \ + new(address) T( \ + BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ + } \ + \ + template \ + inline void construct_impl( \ + std::pair*, void* address, \ + Key const& k, BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ + { \ + new(address) std::pair(k, \ + Second(BOOST_UNORDERED_CALL_PARAMS(z, num_params))); \ + } + + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_CONSTRUCT_IMPL, _) + +#undef BOOST_UNORDERED_CONSTRUCT_IMPL +#endif + + // hash_node_constructor + // + // Used to construct nodes in an exception safe manner. + + template + class hash_node_constructor + { + typedef hash_buckets buckets; + typedef BOOST_DEDUCED_TYPENAME buckets::node node; + typedef BOOST_DEDUCED_TYPENAME buckets::real_node_ptr real_node_ptr; + typedef BOOST_DEDUCED_TYPENAME buckets::value_type value_type; + + buckets& buckets_; + real_node_ptr node_; + bool node_constructed_; + bool value_constructed_; + + public: + + hash_node_constructor(buckets& m) : + buckets_(m), + node_(), + node_constructed_(false), + value_constructed_(false) + { + } + + ~hash_node_constructor(); + void construct_preamble(); + +#if defined(BOOST_UNORDERED_STD_FORWARD) + template + void construct(Args&&... args) + { + construct_preamble(); + construct_impl((value_type*) 0, node_->address(), + std::forward(args)...); + value_constructed_ = true; + } +#else + +#define BOOST_UNORDERED_CONSTRUCT(z, num_params, _) \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \ + > \ + void construct( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \ + ) \ + { \ + construct_preamble(); \ + construct_impl( \ + (value_type*) 0, node_->address(), \ + BOOST_UNORDERED_CALL_PARAMS(z, num_params) \ + ); \ + value_constructed_ = true; \ + } + + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_CONSTRUCT, _) + +#undef BOOST_UNORDERED_CONSTRUCT + +#endif + template + void construct_pair(K const& k, M*) + { + construct_preamble(); + new(node_->address()) value_type(k, M()); + value_constructed_ = true; + } + + value_type& value() const + { + BOOST_ASSERT(node_); + return node_->value(); + } + + // no throw + BOOST_DEDUCED_TYPENAME buckets::node_ptr release() + { + real_node_ptr p = node_; + node_ = real_node_ptr(); + // node_ptr cast + return buckets_.bucket_alloc().address(*p); + } + + private: + hash_node_constructor(hash_node_constructor const&); + hash_node_constructor& operator=(hash_node_constructor const&); + }; + + // hash_node_constructor + + template + inline hash_node_constructor::~hash_node_constructor() + { + if (node_) { + if (value_constructed_) { + boost::unordered_detail::destroy(&node_->value()); + } + + if (node_constructed_) + buckets_.node_alloc().destroy(node_); + + buckets_.node_alloc().deallocate(node_, 1); + } + } + + template + inline void hash_node_constructor::construct_preamble() + { + if(!node_) { + node_constructed_ = false; + value_constructed_ = false; + + node_ = buckets_.node_alloc().allocate(1); + buckets_.node_alloc().construct(node_, node()); + node_constructed_ = true; + } + else { + BOOST_ASSERT(node_constructed_ && value_constructed_); + boost::unordered_detail::destroy(&node_->value()); + value_constructed_ = false; + } + } +}} + +#endif diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index b0658bad..f4c052f5 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -15,7 +15,9 @@ #include #include -#include +#include +#include +#include #if !defined(BOOST_HAS_RVALUE_REFS) #include @@ -39,141 +41,62 @@ namespace boost template class unordered_map { -#if BOOST_WORKAROUND(__BORLANDC__, < 0x0582) public: -#endif - typedef boost::unordered_detail::hash_types_unique_keys< - std::pair, Key, Hash, Pred, Alloc - > implementation; - - BOOST_DEDUCED_TYPENAME implementation::hash_table base; - - public: - - // types - typedef Key key_type; typedef std::pair value_type; typedef T mapped_type; typedef Hash hasher; typedef Pred key_equal; - typedef Alloc allocator_type; - typedef BOOST_DEDUCED_TYPENAME allocator_type::pointer pointer; - typedef BOOST_DEDUCED_TYPENAME allocator_type::const_pointer const_pointer; - typedef BOOST_DEDUCED_TYPENAME allocator_type::reference reference; - typedef BOOST_DEDUCED_TYPENAME allocator_type::const_reference const_reference; - - typedef BOOST_DEDUCED_TYPENAME implementation::size_type size_type; - typedef BOOST_DEDUCED_TYPENAME implementation::difference_type difference_type; - - typedef BOOST_DEDUCED_TYPENAME implementation::iterator iterator; - typedef BOOST_DEDUCED_TYPENAME implementation::const_iterator const_iterator; - typedef BOOST_DEDUCED_TYPENAME implementation::local_iterator local_iterator; - typedef BOOST_DEDUCED_TYPENAME implementation::const_local_iterator const_local_iterator; - - // construct/destroy/copy - - explicit unordered_map( - size_type n = boost::unordered_detail::default_initial_bucket_count, - const hasher &hf = hasher(), - const key_equal &eql = key_equal(), - const allocator_type &a = allocator_type()) - : base(n, hf, eql, a) - { - } - - explicit unordered_map(allocator_type const& a) - : base(boost::unordered_detail::default_initial_bucket_count, - hasher(), key_equal(), a) - { - } - - unordered_map(unordered_map const& other, allocator_type const& a) - : base(other.base, a) - { - } - - template - unordered_map(InputIterator f, InputIterator l) - : base(f, l, boost::unordered_detail::default_initial_bucket_count, - hasher(), key_equal(), allocator_type()) - { - } - - template - unordered_map(InputIterator f, InputIterator l, - size_type n, - const hasher &hf = hasher(), - const key_equal &eql = key_equal()) - : base(f, l, n, hf, eql, allocator_type()) - { - } - - template - unordered_map(InputIterator f, InputIterator l, - size_type n, - const hasher &hf, - const key_equal &eql, - const allocator_type &a) - : base(f, l, n, hf, eql, a) - { - } - - ~unordered_map() {} - -#if defined(BOOST_HAS_RVALUE_REFS) - unordered_map(unordered_map&& other) - : base(other.base, boost::unordered_detail::move_tag()) - { - } - - unordered_map(unordered_map&& other, allocator_type const& a) - : base(other.base, a, boost::unordered_detail::move_tag()) - { - } - - unordered_map& operator=(unordered_map&& x) - { - base.move(x.base); - return *this; - } -#else - unordered_map(boost::unordered_detail::move_from > other) - : base(other.source.base, boost::unordered_detail::move_tag()) - { - } - -#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) - unordered_map& operator=(unordered_map x) - { - base.move(x.base); - return *this; - } -#endif -#endif - -#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) - unordered_map(std::initializer_list list, - size_type n = boost::unordered_detail::default_initial_bucket_count, - const hasher &hf = hasher(), - const key_equal &eql = key_equal(), - const allocator_type &a = allocator_type()) - : base(list.begin(), list.end(), n, hf, eql, a) - { - } - - unordered_map& operator=(std::initializer_list list) - { - base.data_.clear(); - base.insert_range(list.begin(), list.end()); - return *this; - } -#endif +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) private: +#endif - BOOST_DEDUCED_TYPENAME implementation::iterator_base const& + typedef BOOST_DEDUCED_TYPENAME + boost::unordered_detail::rebind_wrap< + allocator_type, value_type>::type + value_allocator; + + typedef boost::unordered_detail::hash_unique_table table; + + typedef BOOST_DEDUCED_TYPENAME table::iterator_base iterator_base; + + public: + + typedef BOOST_DEDUCED_TYPENAME + value_allocator::pointer pointer; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::const_pointer const_pointer; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::reference reference; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::const_reference const_reference; + + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef boost::unordered_detail::hash_const_local_iterator< + value_allocator, boost::unordered_detail::ungrouped> + const_local_iterator; + typedef boost::unordered_detail::hash_local_iterator< + value_allocator, boost::unordered_detail::ungrouped> + local_iterator; + typedef boost::unordered_detail::hash_const_iterator< + value_allocator, boost::unordered_detail::ungrouped> + const_iterator; + typedef boost::unordered_detail::hash_iterator< + value_allocator, boost::unordered_detail::ungrouped> + iterator; + +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) + private: +#endif + + table table_; + + BOOST_DEDUCED_TYPENAME table::iterator_base const& get(const_iterator const& it) { return boost::unordered_detail::iterator_access::get(it); @@ -181,58 +104,166 @@ namespace boost public: + // construct/destroy/copy + + explicit unordered_map( + size_type n = boost::unordered_detail::default_bucket_count, + const hasher &hf = hasher(), + const key_equal &eql = key_equal(), + const allocator_type &a = allocator_type()) + : table_(n, hf, eql, a) + { + } + + explicit unordered_map(allocator_type const& a) + : table_(boost::unordered_detail::default_bucket_count, + hasher(), key_equal(), a) + { + } + + unordered_map(unordered_map const& other, allocator_type const& a) + : table_(other.table_, a) + { + } + + template + unordered_map(InputIt f, InputIt l) + : table_(boost::unordered_detail::initial_size(f, l), + hasher(), key_equal(), allocator_type()) + { + table_.insert_range(f, l); + } + + template + unordered_map(InputIt f, InputIt l, + size_type n, + const hasher &hf = hasher(), + const key_equal &eql = key_equal()) + : table_(boost::unordered_detail::initial_size(f, l, n), + hf, eql, allocator_type()) + { + table_.insert_range(f, l); + } + + template + unordered_map(InputIt f, InputIt l, + size_type n, + const hasher &hf, + const key_equal &eql, + const allocator_type &a) + : table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, a) + { + table_.insert_range(f, l); + } + + ~unordered_map() {} + +#if defined(BOOST_HAS_RVALUE_REFS) + unordered_map(unordered_map&& other) + : table_(other.table_, boost::unordered_detail::move_tag()) + { + } + + unordered_map(unordered_map&& other, allocator_type const& a) + : table_(other.table_, a, boost::unordered_detail::move_tag()) + { + } + + unordered_map& operator=(unordered_map&& x) + { + table_.move(x.table_); + return *this; + } +#else + unordered_map(boost::unordered_detail::move_from< + unordered_map + > other) + : table_(other.source.table_, boost::unordered_detail::move_tag()) + { + } + +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) + unordered_map& operator=(unordered_map x) + { + table_.move(x.table_); + return *this; + } +#endif +#endif + +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + unordered_map(std::initializer_list list, + size_type n = boost::unordered_detail::default_bucket_count, + const hasher &hf = hasher(), + const key_equal &eql = key_equal(), + const allocator_type &a = allocator_type()) + : table_(boost::unordered_detail::initial_size( + list.begin(), list.end(), n), + hf, eql, allocator_type()) + { + table_.insert_range(list.begin(), list.end()); + } + + unordered_map& operator=(std::initializer_list list) + { + table_.clear(); + table_.insert_range(list.begin(), list.end()); + return *this; + } +#endif + allocator_type get_allocator() const { - return base.get_allocator(); + return table_.node_alloc(); } // size and capacity bool empty() const { - return base.empty(); + return table_.size_ == 0; } size_type size() const { - return base.size(); + return table_.size_; } size_type max_size() const { - return base.max_size(); + return table_.max_size(); } // iterators iterator begin() { - return iterator(base.data_.begin()); + return iterator(table_.begin()); } const_iterator begin() const { - return const_iterator(base.data_.begin()); + return const_iterator(table_.begin()); } iterator end() { - return iterator(base.data_.end()); + return iterator(table_.end()); } const_iterator end() const { - return const_iterator(base.data_.end()); + return const_iterator(table_.end()); } const_iterator cbegin() const { - return const_iterator(base.data_.begin()); + return const_iterator(table_.begin()); } const_iterator cend() const { - return const_iterator(base.data_.end()); + return const_iterator(table_.end()); } // modifiers @@ -242,51 +273,50 @@ namespace boost std::pair emplace(Args&&... args) { return boost::unordered_detail::pair_cast( - base.emplace(std::forward(args)...)); + table_.emplace(std::forward(args)...)); } template - iterator emplace_hint(const_iterator hint, Args&&... args) + iterator emplace_hint(const_iterator, Args&&... args) { - return iterator(base.emplace_hint(get(hint), std::forward(args)...)); + return iterator(table_.emplace(std::forward(args)...).first); } #else std::pair emplace(value_type const& v = value_type()) { return boost::unordered_detail::pair_cast( - base.emplace(v)); + table_.emplace(v)); } - iterator emplace_hint(const_iterator hint, value_type const& v = value_type()) + iterator emplace_hint(const_iterator, value_type const& v = value_type()) { - return iterator(base.emplace_hint(get(hint), v)); + return iterator(table_.emplace(v).first); } -#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) \ - )); \ +#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( \ + table_.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(table_.emplace( \ + BOOST_UNORDERED_CALL_PARAMS(z, n)).first); \ } BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, @@ -299,183 +329,184 @@ namespace boost std::pair insert(const value_type& obj) { return boost::unordered_detail::pair_cast( - base.emplace(obj)); + table_.emplace(obj)); } iterator insert(const_iterator hint, const value_type& obj) { - return iterator(base.emplace_hint(get(hint), obj)); + return iterator(table_.emplace(obj).first); } - template - void insert(InputIterator first, InputIterator last) + template + void insert(InputIt first, InputIt last) { - base.insert_range(first, last); + table_.insert_range(first, last); } iterator erase(const_iterator position) { - return iterator(base.data_.erase(get(position))); + return iterator(table_.erase(get(position))); } size_type erase(const key_type& k) { - return base.erase_key(k); + return table_.erase_key(k); } iterator erase(const_iterator first, const_iterator last) { - return iterator(base.data_.erase_range(get(first), get(last))); + return iterator(table_.erase_range(get(first), get(last))); } void clear() { - base.data_.clear(); + table_.clear(); } void swap(unordered_map& other) { - base.swap(other.base); + table_.swap(other.table_); } // observers hasher hash_function() const { - return base.hash_function(); + return table_.hash_function(); } key_equal key_eq() const { - return base.key_eq(); + return table_.key_eq(); } mapped_type& operator[](const key_type &k) { - return base[k].second; + return table_[k].second; } mapped_type& at(const key_type& k) { - return base.at(k).second; + return table_.at(k).second; } mapped_type const& at(const key_type& k) const { - return base.at(k).second; + return table_.at(k).second; } // lookup iterator find(const key_type& k) { - return iterator(base.find(k)); + return iterator(table_.find(k)); } const_iterator find(const key_type& k) const { - return const_iterator(base.find(k)); + return const_iterator(table_.find(k)); } size_type count(const key_type& k) const { - return base.count(k); + return table_.count(k); } std::pair equal_range(const key_type& k) { - return boost::unordered_detail::pair_cast( - base.equal_range(k)); + return boost::unordered_detail::pair_cast< + iterator, iterator>( + table_.equal_range(k)); } std::pair equal_range(const key_type& k) const { - return boost::unordered_detail::pair_cast( - base.equal_range(k)); + return boost::unordered_detail::pair_cast< + const_iterator, const_iterator>( + table_.equal_range(k)); } // bucket interface size_type bucket_count() const { - return base.bucket_count(); + return table_.bucket_count_; } size_type max_bucket_count() const { - return base.max_bucket_count(); + return table_.max_bucket_count(); } size_type bucket_size(size_type n) const { - return base.data_.bucket_size(n); + return table_.bucket_size(n); } size_type bucket(const key_type& k) const { - return base.bucket(k); + return table_.bucket_index(k); } local_iterator begin(size_type n) { - return local_iterator(base.data_.begin(n)); + return local_iterator(table_.bucket_begin(n)); } const_local_iterator begin(size_type n) const { - return const_local_iterator(base.data_.begin(n)); + return const_local_iterator(table_.bucket_begin(n)); } - local_iterator end(size_type n) + local_iterator end(size_type) { - return local_iterator(base.data_.end(n)); + return local_iterator(); } - const_local_iterator end(size_type n) const + const_local_iterator end(size_type) const { - return const_local_iterator(base.data_.end(n)); + return const_local_iterator(); } const_local_iterator cbegin(size_type n) const { - return const_local_iterator(base.data_.begin(n)); + return const_local_iterator(table_.bucket_begin(n)); } - const_local_iterator cend(size_type n) const + const_local_iterator cend(size_type) const { - return const_local_iterator(base.data_.end(n)); + return const_local_iterator(); } // hash policy float load_factor() const { - return base.load_factor(); + return table_.load_factor(); } float max_load_factor() const { - return base.max_load_factor(); + return table_.mlf_; } void max_load_factor(float m) { - base.max_load_factor(m); + table_.max_load_factor(m); } void rehash(size_type n) { - base.rehash(n); + table_.rehash(n); } -#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) - friend bool operator==(unordered_map const&, unordered_map const&); - friend bool operator!=(unordered_map const&, unordered_map const&); -#elif !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) - friend bool operator==(unordered_map const&, unordered_map const&); - friend bool operator!=(unordered_map const&, unordered_map const&); +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) + friend bool operator==( + unordered_map const&, unordered_map const&); + friend bool operator!=( + unordered_map const&, unordered_map const&); #endif }; // class template unordered_map @@ -483,14 +514,14 @@ namespace boost inline bool operator==(unordered_map const& m1, unordered_map const& m2) { - return boost::unordered_detail::equals(m1.base, m2.base); + return m1.table_.equals(m2.table_); } template inline bool operator!=(unordered_map const& m1, unordered_map const& m2) { - return !boost::unordered_detail::equals(m1.base, m2.base); + return !m1.table_.equals(m2.table_); } template @@ -503,142 +534,61 @@ namespace boost template class unordered_multimap { -#if BOOST_WORKAROUND(__BORLANDC__, < 0x0582) public: -#endif - typedef boost::unordered_detail::hash_types_equivalent_keys< - std::pair, Key, Hash, Pred, Alloc - > implementation; - - BOOST_DEDUCED_TYPENAME implementation::hash_table base; - - public: - - // types typedef Key key_type; typedef std::pair value_type; typedef T mapped_type; typedef Hash hasher; typedef Pred key_equal; - typedef Alloc allocator_type; - typedef BOOST_DEDUCED_TYPENAME allocator_type::pointer pointer; - typedef BOOST_DEDUCED_TYPENAME allocator_type::const_pointer const_pointer; - typedef BOOST_DEDUCED_TYPENAME allocator_type::reference reference; - typedef BOOST_DEDUCED_TYPENAME allocator_type::const_reference const_reference; - - typedef BOOST_DEDUCED_TYPENAME implementation::size_type size_type; - typedef BOOST_DEDUCED_TYPENAME implementation::difference_type difference_type; - - typedef BOOST_DEDUCED_TYPENAME implementation::iterator iterator; - typedef BOOST_DEDUCED_TYPENAME implementation::const_iterator const_iterator; - typedef BOOST_DEDUCED_TYPENAME implementation::local_iterator local_iterator; - typedef BOOST_DEDUCED_TYPENAME implementation::const_local_iterator const_local_iterator; - - // construct/destroy/copy - - explicit unordered_multimap( - size_type n = boost::unordered_detail::default_initial_bucket_count, - const hasher &hf = hasher(), - const key_equal &eql = key_equal(), - const allocator_type &a = allocator_type()) - : base(n, hf, eql, a) - { - } - - explicit unordered_multimap(allocator_type const& a) - : base(boost::unordered_detail::default_initial_bucket_count, - hasher(), key_equal(), a) - { - } - - unordered_multimap(unordered_multimap const& other, allocator_type const& a) - : base(other.base, a) - { - } - - template - unordered_multimap(InputIterator f, InputIterator l) - : base(f, l, boost::unordered_detail::default_initial_bucket_count, - hasher(), key_equal(), allocator_type()) - { - } - - template - unordered_multimap(InputIterator f, InputIterator l, - size_type n, - const hasher &hf = hasher(), - const key_equal &eql = key_equal()) - : base(f, l, n, hf, eql, allocator_type()) - { - } - - template - unordered_multimap(InputIterator f, InputIterator l, - size_type n, - const hasher &hf, - const key_equal &eql, - const allocator_type &a) - : base(f, l, n, hf, eql, a) - { - } - - ~unordered_multimap() {} - -#if defined(BOOST_HAS_RVALUE_REFS) - unordered_multimap(unordered_multimap&& other) - : base(other.base, boost::unordered_detail::move_tag()) - { - } - - unordered_multimap(unordered_multimap&& other, allocator_type const& a) - : base(other.base, a, boost::unordered_detail::move_tag()) - { - } - - unordered_multimap& operator=(unordered_multimap&& x) - { - base.move(x.base); - return *this; - } -#else - unordered_multimap(boost::unordered_detail::move_from > other) - : base(other.source.base, boost::unordered_detail::move_tag()) - { - } - -#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) - unordered_multimap& operator=(unordered_multimap x) - { - base.move(x.base); - return *this; - } -#endif -#endif - -#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) - unordered_multimap(std::initializer_list list, - size_type n = boost::unordered_detail::default_initial_bucket_count, - const hasher &hf = hasher(), - const key_equal &eql = key_equal(), - const allocator_type &a = allocator_type()) - : base(list.begin(), list.end(), n, hf, eql, a) - { - } - - unordered_multimap& operator=(std::initializer_list list) - { - base.data_.clear(); - base.insert_range(list.begin(), list.end()); - return *this; - } -#endif - +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) private: +#endif + typedef BOOST_DEDUCED_TYPENAME + boost::unordered_detail::rebind_wrap< + allocator_type, value_type>::type + value_allocator; - BOOST_DEDUCED_TYPENAME implementation::iterator_base const& + typedef boost::unordered_detail::hash_equivalent_table table; + typedef BOOST_DEDUCED_TYPENAME table::iterator_base iterator_base; + + public: + + typedef BOOST_DEDUCED_TYPENAME + value_allocator::pointer pointer; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::const_pointer const_pointer; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::reference reference; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::const_reference const_reference; + + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef boost::unordered_detail::hash_const_local_iterator< + value_allocator, boost::unordered_detail::grouped> + const_local_iterator; + typedef boost::unordered_detail::hash_local_iterator< + value_allocator, boost::unordered_detail::grouped> + local_iterator; + typedef boost::unordered_detail::hash_const_iterator< + value_allocator, boost::unordered_detail::grouped> + const_iterator; + typedef boost::unordered_detail::hash_iterator< + value_allocator, boost::unordered_detail::grouped> + iterator; + +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) + private: +#endif + + table table_; + + BOOST_DEDUCED_TYPENAME table::iterator_base const& get(const_iterator const& it) { return boost::unordered_detail::iterator_access::get(it); @@ -646,58 +596,167 @@ namespace boost public: + // construct/destroy/copy + + explicit unordered_multimap( + size_type n = boost::unordered_detail::default_bucket_count, + const hasher &hf = hasher(), + const key_equal &eql = key_equal(), + const allocator_type &a = allocator_type()) + : table_(n, hf, eql, a) + { + } + + explicit unordered_multimap(allocator_type const& a) + : table_(boost::unordered_detail::default_bucket_count, + hasher(), key_equal(), a) + { + } + + unordered_multimap(unordered_multimap const& other, + allocator_type const& a) + : table_(other.table_, a) + { + } + + template + unordered_multimap(InputIt f, InputIt l) + : table_(boost::unordered_detail::initial_size(f, l), + hasher(), key_equal(), allocator_type()) + { + table_.insert_range(f, l); + } + + template + unordered_multimap(InputIt f, InputIt l, + size_type n, + const hasher &hf = hasher(), + const key_equal &eql = key_equal()) + : table_(boost::unordered_detail::initial_size(f, l, n), + hf, eql, allocator_type()) + { + table_.insert_range(f, l); + } + + template + unordered_multimap(InputIt f, InputIt l, + size_type n, + const hasher &hf, + const key_equal &eql, + const allocator_type &a) + : table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, a) + { + table_.insert_range(f, l); + } + + ~unordered_multimap() {} + +#if defined(BOOST_HAS_RVALUE_REFS) + unordered_multimap(unordered_multimap&& other) + : table_(other.table_, boost::unordered_detail::move_tag()) + { + } + + unordered_multimap(unordered_multimap&& other, allocator_type const& a) + : table_(other.table_, a, boost::unordered_detail::move_tag()) + { + } + + unordered_multimap& operator=(unordered_multimap&& x) + { + table_.move(x.table_); + return *this; + } +#else + unordered_multimap(boost::unordered_detail::move_from< + unordered_multimap + > other) + : table_(other.source.table_, boost::unordered_detail::move_tag()) + { + } + +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) + unordered_multimap& operator=(unordered_multimap x) + { + table_.move(x.table_); + return *this; + } +#endif +#endif + +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + unordered_multimap(std::initializer_list list, + size_type n = boost::unordered_detail::default_bucket_count, + const hasher &hf = hasher(), + const key_equal &eql = key_equal(), + const allocator_type &a = allocator_type()) + : table_(boost::unordered_detail::initial_size( + list.begin(), list.end(), n), + hf, eql, allocator_type()) + { + table_.insert_range(list.begin(), list.end()); + } + + unordered_multimap& operator=(std::initializer_list list) + { + table_.clear(); + table_.insert_range(list.begin(), list.end()); + return *this; + } +#endif + allocator_type get_allocator() const { - return base.get_allocator(); + return table_.node_alloc(); } // size and capacity bool empty() const { - return base.empty(); + return table_.size_ == 0; } size_type size() const { - return base.size(); + return table_.size_; } size_type max_size() const { - return base.max_size(); + return table_.max_size(); } // iterators iterator begin() { - return iterator(base.data_.begin()); + return iterator(table_.begin()); } const_iterator begin() const { - return const_iterator(base.data_.begin()); + return const_iterator(table_.begin()); } iterator end() { - return iterator(base.data_.end()); + return iterator(table_.end()); } const_iterator end() const { - return const_iterator(base.data_.end()); + return const_iterator(table_.end()); } const_iterator cbegin() const { - return const_iterator(base.data_.begin()); + return const_iterator(table_.begin()); } const_iterator cend() const { - return const_iterator(base.data_.end()); + return const_iterator(table_.end()); } // modifiers @@ -706,51 +765,53 @@ namespace boost template iterator emplace(Args&&... args) { - return iterator(base.emplace(std::forward(args)...)); + return iterator(table_.emplace(std::forward(args)...)); } template iterator emplace_hint(const_iterator hint, Args&&... args) { - return iterator(base.emplace_hint(get(hint), std::forward(args)...)); + return iterator(table_.emplace_hint(get(hint), + std::forward(args)...)); } #else iterator emplace(value_type const& v = value_type()) { - return iterator(base.emplace(v)); + return iterator(table_.emplace(v)); } - iterator emplace_hint(const_iterator hint, value_type const& v = value_type()) + iterator emplace_hint(const_iterator hint, + value_type const& v = value_type()) { - return iterator(base.emplace_hint(get(hint), v)); + return iterator(table_.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) \ - )); \ +#define BOOST_UNORDERED_EMPLACE(z, n, _) \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + iterator emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + return iterator( \ + table_.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(table_.emplace_hint(get(hint), \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + )); \ } BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, @@ -762,168 +823,169 @@ namespace boost iterator insert(const value_type& obj) { - return iterator(base.emplace(obj)); + return iterator(table_.emplace(obj)); } iterator insert(const_iterator hint, const value_type& obj) { - return iterator(base.emplace_hint(get(hint), obj)); + return iterator(table_.emplace_hint(get(hint), obj)); } - template - void insert(InputIterator first, InputIterator last) + template + void insert(InputIt first, InputIt last) { - base.insert_range(first, last); + table_.insert_range(first, last); } iterator erase(const_iterator position) { - return iterator(base.data_.erase(get(position))); + return iterator(table_.erase(get(position))); } size_type erase(const key_type& k) { - return base.erase_key(k); + return table_.erase_key(k); } iterator erase(const_iterator first, const_iterator last) { - return iterator(base.data_.erase_range(get(first), get(last))); + return iterator(table_.erase_range(get(first), get(last))); } void clear() { - base.data_.clear(); + table_.clear(); } void swap(unordered_multimap& other) { - base.swap(other.base); + table_.swap(other.table_); } // observers hasher hash_function() const { - return base.hash_function(); + return table_.hash_function(); } key_equal key_eq() const { - return base.key_eq(); + return table_.key_eq(); } // lookup iterator find(const key_type& k) { - return iterator(base.find(k)); + return iterator(table_.find(k)); } const_iterator find(const key_type& k) const { - return const_iterator(base.find(k)); + return const_iterator(table_.find(k)); } size_type count(const key_type& k) const { - return base.count(k); + return table_.count(k); } std::pair equal_range(const key_type& k) { - return boost::unordered_detail::pair_cast( - base.equal_range(k)); + return boost::unordered_detail::pair_cast< + iterator, iterator>( + table_.equal_range(k)); } std::pair equal_range(const key_type& k) const { - return boost::unordered_detail::pair_cast( - base.equal_range(k)); + return boost::unordered_detail::pair_cast< + const_iterator, const_iterator>( + table_.equal_range(k)); } // bucket interface size_type bucket_count() const { - return base.bucket_count(); + return table_.bucket_count_; } size_type max_bucket_count() const { - return base.max_bucket_count(); + return table_.max_bucket_count(); } size_type bucket_size(size_type n) const { - return base.data_.bucket_size(n); + return table_.bucket_size(n); } size_type bucket(const key_type& k) const { - return base.bucket(k); + return table_.bucket_index(k); } local_iterator begin(size_type n) { - return local_iterator(base.data_.begin(n)); + return local_iterator(table_.bucket_begin(n)); } const_local_iterator begin(size_type n) const { - return const_local_iterator(base.data_.begin(n)); + return const_local_iterator(table_.bucket_begin(n)); } - local_iterator end(size_type n) + local_iterator end(size_type) { - return local_iterator(base.data_.end(n)); + return local_iterator(); } - const_local_iterator end(size_type n) const + const_local_iterator end(size_type) const { - return const_local_iterator(base.data_.end(n)); + return const_local_iterator(); } const_local_iterator cbegin(size_type n) const { - return const_local_iterator(base.data_.begin(n)); + return const_local_iterator(table_.bucket_begin(n)); } - const_local_iterator cend(size_type n) const + const_local_iterator cend(size_type) const { - return const_local_iterator(base.data_.end(n)); + return const_local_iterator(); } // hash policy float load_factor() const { - return base.load_factor(); + return table_.load_factor(); } float max_load_factor() const { - return base.max_load_factor(); + return table_.mlf_; } void max_load_factor(float m) { - base.max_load_factor(m); + table_.max_load_factor(m); } void rehash(size_type n) { - base.rehash(n); + table_.rehash(n); } -#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) - friend bool operator==(unordered_multimap const&, unordered_multimap const&); - friend bool operator!=(unordered_multimap const&, unordered_multimap const&); -#elif !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) - friend bool operator==(unordered_multimap const&, unordered_multimap const&); - friend bool operator!=(unordered_multimap const&, unordered_multimap const&); +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) + friend bool operator==( + unordered_multimap const&, unordered_multimap const&); + friend bool operator!=( + unordered_multimap const&, unordered_multimap const&); #endif }; // class template unordered_multimap @@ -931,14 +993,14 @@ namespace boost inline bool operator==(unordered_multimap const& m1, unordered_multimap const& m2) { - return boost::unordered_detail::equals(m1.base, m2.base); + return m1.table_.equals(m2.table_); } template inline bool operator!=(unordered_multimap const& m1, unordered_multimap const& m2) { - return !boost::unordered_detail::equals(m1.base, m2.base); + return !m1.table_.equals(m2.table_); } template diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index aecb54b4..2b147b28 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -15,7 +15,9 @@ #include #include -#include +#include +#include +#include #if !defined(BOOST_HAS_RVALUE_REFS) #include @@ -39,138 +41,57 @@ namespace boost template class unordered_set { -#if BOOST_WORKAROUND(__BORLANDC__, < 0x0582) public: -#endif - typedef boost::unordered_detail::hash_types_unique_keys< - Value, Value, Hash, Pred, Alloc - > implementation; - - BOOST_DEDUCED_TYPENAME implementation::hash_table base; - - public: - - // types typedef Value key_type; typedef Value value_type; typedef Hash hasher; typedef Pred key_equal; - typedef Alloc allocator_type; - typedef BOOST_DEDUCED_TYPENAME allocator_type::pointer pointer; - typedef BOOST_DEDUCED_TYPENAME allocator_type::const_pointer const_pointer; - typedef BOOST_DEDUCED_TYPENAME allocator_type::reference reference; - typedef BOOST_DEDUCED_TYPENAME allocator_type::const_reference const_reference; - - typedef BOOST_DEDUCED_TYPENAME implementation::size_type size_type; - typedef BOOST_DEDUCED_TYPENAME implementation::difference_type difference_type; - - typedef BOOST_DEDUCED_TYPENAME implementation::const_iterator iterator; - typedef BOOST_DEDUCED_TYPENAME implementation::const_iterator const_iterator; - typedef BOOST_DEDUCED_TYPENAME implementation::const_local_iterator local_iterator; - typedef BOOST_DEDUCED_TYPENAME implementation::const_local_iterator const_local_iterator; - - // construct/destroy/copy - - explicit unordered_set( - size_type n = boost::unordered_detail::default_initial_bucket_count, - const hasher &hf = hasher(), - const key_equal &eql = key_equal(), - const allocator_type &a = allocator_type()) - : base(n, hf, eql, a) - { - } - - explicit unordered_set(allocator_type const& a) - : base(boost::unordered_detail::default_initial_bucket_count, - hasher(), key_equal(), a) - { - } - - unordered_set(unordered_set const& other, allocator_type const& a) - : base(other.base, a) - { - } - - template - unordered_set(InputIterator f, InputIterator l) - : base(f, l, boost::unordered_detail::default_initial_bucket_count, - hasher(), key_equal(), allocator_type()) - { - } - - template - unordered_set(InputIterator f, InputIterator l, size_type n, - const hasher &hf = hasher(), - const key_equal &eql = key_equal()) - : base(f, l, n, hf, eql, allocator_type()) - { - } - - template - unordered_set(InputIterator f, InputIterator l, size_type n, - const hasher &hf, - const key_equal &eql, - const allocator_type &a) - : base(f, l, n, hf, eql, a) - { - } - - ~unordered_set() {} - -#if defined(BOOST_HAS_RVALUE_REFS) - unordered_set(unordered_set&& other) - : base(other.base, boost::unordered_detail::move_tag()) - { - } - - unordered_set(unordered_set&& other, allocator_type const& a) - : base(other.base, a, boost::unordered_detail::move_tag()) - { - } - - unordered_set& operator=(unordered_set&& x) - { - base.move(x.base); - return *this; - } -#else - unordered_set(boost::unordered_detail::move_from > other) - : base(other.source.base, boost::unordered_detail::move_tag()) - { - } - -#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) - unordered_set& operator=(unordered_set x) - { - base.move(x.base); - return *this; - } -#endif -#endif - -#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) - unordered_set(std::initializer_list list, - size_type n = boost::unordered_detail::default_initial_bucket_count, - const hasher &hf = hasher(), - const key_equal &eql = key_equal(), - const allocator_type &a = allocator_type()) - : base(list.begin(), list.end(), n, hf, eql, a) - { - } - - unordered_set& operator=(std::initializer_list list) - { - base.data_.clear(); - base.insert_range(list.begin(), list.end()); - return *this; - } -#endif +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) private: +#endif - BOOST_DEDUCED_TYPENAME implementation::iterator_base const& + typedef BOOST_DEDUCED_TYPENAME + boost::unordered_detail::rebind_wrap< + allocator_type, value_type>::type + value_allocator; + + typedef boost::unordered_detail::hash_unique_table table; + typedef BOOST_DEDUCED_TYPENAME table::iterator_base iterator_base; + + public: + + typedef BOOST_DEDUCED_TYPENAME + value_allocator::pointer pointer; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::const_pointer const_pointer; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::reference reference; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::const_reference const_reference; + + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef boost::unordered_detail::hash_const_local_iterator< + value_allocator, boost::unordered_detail::ungrouped> + const_local_iterator; + typedef boost::unordered_detail::hash_const_iterator< + value_allocator, boost::unordered_detail::ungrouped> + const_iterator; + typedef const_local_iterator local_iterator; + typedef const_iterator iterator; + +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) + private: +#endif + + table table_; + + BOOST_DEDUCED_TYPENAME table::iterator_base const& get(const_iterator const& it) { return boost::unordered_detail::iterator_access::get(it); @@ -178,58 +99,164 @@ namespace boost public: + // construct/destroy/copy + + explicit unordered_set( + size_type n = boost::unordered_detail::default_bucket_count, + const hasher &hf = hasher(), + const key_equal &eql = key_equal(), + const allocator_type &a = allocator_type()) + : table_(n, hf, eql, a) + { + } + + explicit unordered_set(allocator_type const& a) + : table_(boost::unordered_detail::default_bucket_count, + hasher(), key_equal(), a) + { + } + + unordered_set(unordered_set const& other, allocator_type const& a) + : table_(other.table_, a) + { + } + + template + unordered_set(InputIt f, InputIt l) + : table_(boost::unordered_detail::initial_size(f, l), + hasher(), key_equal(), allocator_type()) + { + table_.insert_range(f, l); + } + + template + unordered_set(InputIt f, InputIt l, size_type n, + const hasher &hf = hasher(), + const key_equal &eql = key_equal()) + : table_(boost::unordered_detail::initial_size(f, l, n), + hf, eql, allocator_type()) + { + table_.insert_range(f, l); + } + + template + unordered_set(InputIt f, InputIt l, size_type n, + const hasher &hf, + const key_equal &eql, + const allocator_type &a) + : table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, a) + { + table_.insert_range(f, l); + } + + ~unordered_set() {} + +#if defined(BOOST_HAS_RVALUE_REFS) + unordered_set(unordered_set&& other) + : table_(other.table_, boost::unordered_detail::move_tag()) + { + } + + unordered_set(unordered_set&& other, allocator_type const& a) + : table_(other.table_, a, boost::unordered_detail::move_tag()) + { + } + + unordered_set& operator=(unordered_set&& x) + { + table_.move(x.table_); + return *this; + } +#else + unordered_set(boost::unordered_detail::move_from< + unordered_set + > other) + : table_(other.source.table_, boost::unordered_detail::move_tag()) + { + } + +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) + unordered_set& operator=(unordered_set x) + { + table_.move(x.table_); + return *this; + } +#endif +#endif + +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + unordered_set(std::initializer_list list, + size_type n = boost::unordered_detail::default_bucket_count, + const hasher &hf = hasher(), + const key_equal &eql = key_equal(), + const allocator_type &a = allocator_type()) + : table_(boost::unordered_detail::initial_size( + list.begin(), list.end(), n), + hf, eql, allocator_type()) + { + table_.insert_range(list.begin(), list.end()); + } + + unordered_set& operator=(std::initializer_list list) + { + table_.clear(); + table_.insert_range(list.begin(), list.end()); + return *this; + } +#endif + allocator_type get_allocator() const { - return base.get_allocator(); + return table_.node_alloc(); } // size and capacity bool empty() const { - return base.empty(); + return table_.size_ == 0; } size_type size() const { - return base.size(); + return table_.size_; } size_type max_size() const { - return base.max_size(); + return table_.max_size(); } // iterators iterator begin() { - return iterator(base.data_.begin()); + return iterator(table_.begin()); } const_iterator begin() const { - return const_iterator(base.data_.begin()); + return const_iterator(table_.begin()); } iterator end() { - return iterator(base.data_.end()); + return iterator(table_.end()); } const_iterator end() const { - return const_iterator(base.data_.end()); + return const_iterator(table_.end()); } const_iterator cbegin() const { - return const_iterator(base.data_.begin()); + return const_iterator(table_.begin()); } const_iterator cend() const { - return const_iterator(base.data_.end()); + return const_iterator(table_.end()); } // modifiers @@ -239,52 +266,51 @@ namespace boost std::pair emplace(Args&&... args) { return boost::unordered_detail::pair_cast( - base.emplace(std::forward(args)...)); + table_.emplace(std::forward(args)...)); } template - iterator emplace_hint(const_iterator hint, Args&&... args) + iterator emplace_hint(const_iterator, Args&&... args) { - return iterator( - base.emplace_hint(get(hint), std::forward(args)...)); + return iterator(table_.emplace(std::forward(args)...).first); } #else std::pair emplace(value_type const& v = value_type()) { return boost::unordered_detail::pair_cast( - base.emplace(v)); + table_.emplace(v)); } - iterator emplace_hint(const_iterator hint, value_type const& v = value_type()) + iterator emplace_hint(const_iterator, + value_type const& v = value_type()) { - return iterator(base.emplace_hint(get(hint), v)); + return iterator(table_.emplace(v).first); } -#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) \ - )); \ +#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( \ + table_.emplace( \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + )); \ + } \ + \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + iterator emplace_hint(const_iterator, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + return iterator(table_.emplace( \ + BOOST_UNORDERED_CALL_PARAMS(z, n)).first); \ } BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, @@ -297,156 +323,156 @@ namespace boost std::pair insert(const value_type& obj) { return boost::unordered_detail::pair_cast( - base.emplace(obj)); + table_.emplace(obj)); } iterator insert(const_iterator hint, const value_type& obj) { - return iterator(base.emplace_hint(get(hint), obj)); + return iterator(table_.emplace(obj).first); } - template - void insert(InputIterator first, InputIterator last) + template + void insert(InputIt first, InputIt last) { - base.insert_range(first, last); + table_.insert_range(first, last); } iterator erase(const_iterator position) { - return iterator(base.data_.erase(get(position))); + return iterator(table_.erase(get(position))); } size_type erase(const key_type& k) { - return base.erase_key(k); + return table_.erase_key(k); } iterator erase(const_iterator first, const_iterator last) { - return iterator(base.data_.erase_range(get(first), get(last))); + return iterator(table_.erase_range(get(first), get(last))); } void clear() { - base.data_.clear(); + table_.clear(); } void swap(unordered_set& other) { - base.swap(other.base); + table_.swap(other.table_); } // observers hasher hash_function() const { - return base.hash_function(); + return table_.hash_function(); } key_equal key_eq() const { - return base.key_eq(); + return table_.key_eq(); } // lookup const_iterator find(const key_type& k) const { - return const_iterator(base.find(k)); + return const_iterator(table_.find(k)); } size_type count(const key_type& k) const { - return base.count(k); + return table_.count(k); } std::pair equal_range(const key_type& k) const { - return boost::unordered_detail::pair_cast( - base.equal_range(k)); + return boost::unordered_detail::pair_cast< + const_iterator, const_iterator>( + table_.equal_range(k)); } // bucket interface size_type bucket_count() const { - return base.bucket_count(); + return table_.bucket_count_; } size_type max_bucket_count() const { - return base.max_bucket_count(); + return table_.max_bucket_count(); } size_type bucket_size(size_type n) const { - return base.data_.bucket_size(n); + return table_.bucket_size(n); } size_type bucket(const key_type& k) const { - return base.bucket(k); + return table_.bucket_index(k); } local_iterator begin(size_type n) { - return local_iterator(base.data_.begin(n)); + return local_iterator(table_.bucket_begin(n)); } const_local_iterator begin(size_type n) const { - return const_local_iterator(base.data_.begin(n)); + return const_local_iterator(table_.bucket_begin(n)); } - local_iterator end(size_type n) + local_iterator end(size_type) { - return local_iterator(base.data_.end(n)); + return local_iterator(); } - const_local_iterator end(size_type n) const + const_local_iterator end(size_type) const { - return const_local_iterator(base.data_.end(n)); + return const_local_iterator(); } const_local_iterator cbegin(size_type n) const { - return const_local_iterator(base.data_.begin(n)); + return const_local_iterator(table_.bucket_begin(n)); } - const_local_iterator cend(size_type n) const + const_local_iterator cend(size_type) const { - return const_local_iterator(base.data_.end(n)); + return const_local_iterator(); } // hash policy float load_factor() const { - return base.load_factor(); + return table_.load_factor(); } float max_load_factor() const { - return base.max_load_factor(); + return table_.mlf_; } void max_load_factor(float m) { - base.max_load_factor(m); + table_.max_load_factor(m); } void rehash(size_type n) { - base.rehash(n); + table_.rehash(n); } -#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) - friend bool operator==(unordered_set const&, unordered_set const&); - friend bool operator!=(unordered_set const&, unordered_set const&); -#elif !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) - friend bool operator==(unordered_set const&, unordered_set const&); - friend bool operator!=(unordered_set const&, unordered_set const&); +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) + friend bool operator==( + unordered_set const&, unordered_set const&); + friend bool operator!=( + unordered_set const&, unordered_set const&); #endif }; // class template unordered_set @@ -454,14 +480,14 @@ namespace boost inline bool operator==(unordered_set const& m1, unordered_set const& m2) { - return boost::unordered_detail::equals(m1.base, m2.base); + return m1.table_.equals(m2.table_); } template inline bool operator!=(unordered_set const& m1, unordered_set const& m2) { - return !boost::unordered_detail::equals(m1.base, m2.base); + return !m1.table_.equals(m2.table_); } template @@ -474,138 +500,56 @@ namespace boost template class unordered_multiset { -#if BOOST_WORKAROUND(__BORLANDC__, < 0x0582) public: -#endif - typedef boost::unordered_detail::hash_types_equivalent_keys< - Value, Value, Hash, Pred, Alloc - > implementation; - - BOOST_DEDUCED_TYPENAME implementation::hash_table base; - - public: - - //types typedef Value key_type; typedef Value value_type; typedef Hash hasher; typedef Pred key_equal; - typedef Alloc allocator_type; - typedef BOOST_DEDUCED_TYPENAME allocator_type::pointer pointer; - typedef BOOST_DEDUCED_TYPENAME allocator_type::const_pointer const_pointer; - typedef BOOST_DEDUCED_TYPENAME allocator_type::reference reference; - typedef BOOST_DEDUCED_TYPENAME allocator_type::const_reference const_reference; - - typedef BOOST_DEDUCED_TYPENAME implementation::size_type size_type; - typedef BOOST_DEDUCED_TYPENAME implementation::difference_type difference_type; - - typedef BOOST_DEDUCED_TYPENAME implementation::const_iterator iterator; - typedef BOOST_DEDUCED_TYPENAME implementation::const_iterator const_iterator; - typedef BOOST_DEDUCED_TYPENAME implementation::const_local_iterator local_iterator; - typedef BOOST_DEDUCED_TYPENAME implementation::const_local_iterator const_local_iterator; - - // construct/destroy/copy - - explicit unordered_multiset( - size_type n = boost::unordered_detail::default_initial_bucket_count, - const hasher &hf = hasher(), - const key_equal &eql = key_equal(), - const allocator_type &a = allocator_type()) - : base(n, hf, eql, a) - { - } - - explicit unordered_multiset(allocator_type const& a) - : base(boost::unordered_detail::default_initial_bucket_count, - hasher(), key_equal(), a) - { - } - - unordered_multiset(unordered_multiset const& other, allocator_type const& a) - : base(other.base, a) - { - } - - template - unordered_multiset(InputIterator f, InputIterator l) - : base(f, l, boost::unordered_detail::default_initial_bucket_count, - hasher(), key_equal(), allocator_type()) - { - } - - template - unordered_multiset(InputIterator f, InputIterator l, size_type n, - const hasher &hf = hasher(), - const key_equal &eql = key_equal()) - : base(f, l, n, hf, eql, allocator_type()) - { - } - - template - unordered_multiset(InputIterator f, InputIterator l, size_type n, - const hasher &hf, - const key_equal &eql, - const allocator_type &a) - : base(f, l, n, hf, eql, a) - { - } - - ~unordered_multiset() {} - -#if defined(BOOST_HAS_RVALUE_REFS) - unordered_multiset(unordered_multiset&& other) - : base(other.base, boost::unordered_detail::move_tag()) - { - } - - unordered_multiset(unordered_multiset&& other, allocator_type const& a) - : base(other.base, a, boost::unordered_detail::move_tag()) - { - } - - unordered_multiset& operator=(unordered_multiset&& x) - { - base.move(x.base); - return *this; - } -#else - unordered_multiset(boost::unordered_detail::move_from > other) - : base(other.source.base, boost::unordered_detail::move_tag()) - { - } - -#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) - unordered_multiset& operator=(unordered_multiset x) - { - base.move(x.base); - return *this; - } -#endif -#endif - -#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) - unordered_multiset(std::initializer_list list, - size_type n = boost::unordered_detail::default_initial_bucket_count, - const hasher &hf = hasher(), - const key_equal &eql = key_equal(), - const allocator_type &a = allocator_type()) - : base(list.begin(), list.end(), n, hf, eql, a) - { - } - - unordered_multiset& operator=(std::initializer_list list) - { - base.data_.clear(); - base.insert_range(list.begin(), list.end()); - return *this; - } -#endif +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) private: +#endif + typedef BOOST_DEDUCED_TYPENAME + boost::unordered_detail::rebind_wrap< + allocator_type, value_type>::type + value_allocator; - BOOST_DEDUCED_TYPENAME implementation::iterator_base const& + typedef boost::unordered_detail::hash_equivalent_table table; + typedef BOOST_DEDUCED_TYPENAME table::iterator_base iterator_base; + + public: + + typedef BOOST_DEDUCED_TYPENAME + value_allocator::pointer pointer; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::const_pointer const_pointer; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::reference reference; + typedef BOOST_DEDUCED_TYPENAME + value_allocator::const_reference const_reference; + + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef boost::unordered_detail::hash_const_local_iterator< + value_allocator, boost::unordered_detail::grouped> + const_local_iterator; + typedef boost::unordered_detail::hash_const_iterator< + value_allocator, boost::unordered_detail::grouped> + const_iterator; + typedef const_local_iterator local_iterator; + typedef const_iterator iterator; + +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) + private: +#endif + + table table_; + + BOOST_DEDUCED_TYPENAME table::iterator_base const& get(const_iterator const& it) { return boost::unordered_detail::iterator_access::get(it); @@ -613,58 +557,165 @@ namespace boost public: + // construct/destroy/copy + + explicit unordered_multiset( + size_type n = boost::unordered_detail::default_bucket_count, + const hasher &hf = hasher(), + const key_equal &eql = key_equal(), + const allocator_type &a = allocator_type()) + : table_(n, hf, eql, a) + { + } + + explicit unordered_multiset(allocator_type const& a) + : table_(boost::unordered_detail::default_bucket_count, + hasher(), key_equal(), a) + { + } + + unordered_multiset(unordered_multiset const& other, + allocator_type const& a) + : table_(other.table_, a) + { + } + + template + unordered_multiset(InputIt f, InputIt l) + : table_(boost::unordered_detail::initial_size(f, l), + hasher(), key_equal(), allocator_type()) + { + table_.insert_range(f, l); + } + + template + unordered_multiset(InputIt f, InputIt l, size_type n, + const hasher &hf = hasher(), + const key_equal &eql = key_equal()) + : table_(boost::unordered_detail::initial_size(f, l, n), + hf, eql, allocator_type()) + { + table_.insert_range(f, l); + } + + template + unordered_multiset(InputIt f, InputIt l, size_type n, + const hasher &hf, + const key_equal &eql, + const allocator_type &a) + : table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, a) + { + table_.insert_range(f, l); + } + + ~unordered_multiset() {} + +#if defined(BOOST_HAS_RVALUE_REFS) + unordered_multiset(unordered_multiset&& other) + : table_(other.table_, boost::unordered_detail::move_tag()) + { + } + + unordered_multiset(unordered_multiset&& other, allocator_type const& a) + : table_(other.table_, a, boost::unordered_detail::move_tag()) + { + } + + unordered_multiset& operator=(unordered_multiset&& x) + { + table_.move(x.table_); + return *this; + } +#else + unordered_multiset(boost::unordered_detail::move_from< + unordered_multiset + > other) + : table_(other.source.table_, boost::unordered_detail::move_tag()) + { + } + +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) + unordered_multiset& operator=(unordered_multiset x) + { + table_.move(x.table_); + return *this; + } +#endif +#endif + +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + unordered_multiset(std::initializer_list list, + size_type n = boost::unordered_detail::default_bucket_count, + const hasher &hf = hasher(), + const key_equal &eql = key_equal(), + const allocator_type &a = allocator_type()) + : table_(boost::unordered_detail::initial_size( + list.begin(), list.end(), n), + hf, eql, allocator_type()) + { + table_.insert_range(list.begin(), list.end()); + } + + unordered_multiset& operator=(std::initializer_list list) + { + table_.clear(); + table_.insert_range(list.begin(), list.end()); + return *this; + } +#endif + allocator_type get_allocator() const { - return base.get_allocator(); + return table_.node_alloc(); } // size and capacity bool empty() const { - return base.empty(); + return table_.size_ == 0; } size_type size() const { - return base.size(); + return table_.size_; } size_type max_size() const { - return base.max_size(); + return table_.max_size(); } // iterators iterator begin() { - return iterator(base.data_.begin()); + return iterator(table_.begin()); } const_iterator begin() const { - return const_iterator(base.data_.begin()); + return const_iterator(table_.begin()); } iterator end() { - return iterator(base.data_.end()); + return iterator(table_.end()); } const_iterator end() const { - return const_iterator(base.data_.end()); + return const_iterator(table_.end()); } const_iterator cbegin() const { - return const_iterator(base.data_.begin()); + return const_iterator(table_.begin()); } const_iterator cend() const { - return const_iterator(base.data_.end()); + return const_iterator(table_.end()); } // modifiers @@ -673,50 +724,50 @@ namespace boost template iterator emplace(Args&&... args) { - return iterator(base.emplace(std::forward(args)...)); + return iterator(table_.emplace(std::forward(args)...)); } template iterator emplace_hint(const_iterator hint, Args&&... args) { - return iterator(base.emplace_hint(get(hint), std::forward(args)...)); + return iterator(table_.emplace_hint(get(hint), + std::forward(args)...)); } #else iterator emplace(value_type const& v = value_type()) { - return iterator(base.emplace(v)); + return iterator(table_.emplace(v)); } - iterator emplace_hint(const_iterator hint, value_type const& v = value_type()) + iterator emplace_hint(const_iterator hint, + value_type const& v = value_type()) { - return iterator(base.emplace_hint(get(hint), v)); + return iterator(table_.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) \ - )); \ +#define BOOST_UNORDERED_EMPLACE(z, n, _) \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + iterator emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + return iterator( \ + table_.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(table_.emplace_hint(get(hint), \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + )); \ } BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, @@ -728,156 +779,156 @@ namespace boost iterator insert(const value_type& obj) { - return iterator(base.emplace(obj)); + return iterator(table_.emplace(obj)); } iterator insert(const_iterator hint, const value_type& obj) { - return iterator(base.emplace_hint(get(hint), obj)); + return iterator(table_.emplace_hint(get(hint), obj)); } - template - void insert(InputIterator first, InputIterator last) + template + void insert(InputIt first, InputIt last) { - base.insert_range(first, last); + table_.insert_range(first, last); } iterator erase(const_iterator position) { - return iterator(base.data_.erase(get(position))); + return iterator(table_.erase(get(position))); } size_type erase(const key_type& k) { - return base.erase_key(k); + return table_.erase_key(k); } iterator erase(const_iterator first, const_iterator last) { - return iterator(base.data_.erase_range(get(first), get(last))); + return iterator(table_.erase_range(get(first), get(last))); } void clear() { - base.data_.clear(); + table_.clear(); } void swap(unordered_multiset& other) { - base.swap(other.base); + table_.swap(other.table_); } // observers hasher hash_function() const { - return base.hash_function(); + return table_.hash_function(); } key_equal key_eq() const { - return base.key_eq(); + return table_.key_eq(); } // lookup const_iterator find(const key_type& k) const { - return const_iterator(base.find(k)); + return const_iterator(table_.find(k)); } size_type count(const key_type& k) const { - return base.count(k); + return table_.count(k); } std::pair equal_range(const key_type& k) const { - return boost::unordered_detail::pair_cast( - base.equal_range(k)); + return boost::unordered_detail::pair_cast< + const_iterator, const_iterator>( + table_.equal_range(k)); } // bucket interface size_type bucket_count() const { - return base.bucket_count(); + return table_.bucket_count_; } size_type max_bucket_count() const { - return base.max_bucket_count(); + return table_.max_bucket_count(); } size_type bucket_size(size_type n) const { - return base.data_.bucket_size(n); + return table_.bucket_size(n); } size_type bucket(const key_type& k) const { - return base.bucket(k); + return table_.bucket_index(k); } local_iterator begin(size_type n) { - return local_iterator(base.data_.begin(n)); + return local_iterator(table_.bucket_begin(n)); } const_local_iterator begin(size_type n) const { - return const_local_iterator(base.data_.begin(n)); + return const_local_iterator(table_.bucket_begin(n)); } - local_iterator end(size_type n) + local_iterator end(size_type) { - return local_iterator(base.data_.end(n)); + return local_iterator(); } - const_local_iterator end(size_type n) const + const_local_iterator end(size_type) const { - return const_local_iterator(base.data_.end(n)); + return const_local_iterator(); } const_local_iterator cbegin(size_type n) const { - return const_local_iterator(base.data_.begin(n)); + return const_local_iterator(table_.bucket_begin(n)); } - const_local_iterator cend(size_type n) const + const_local_iterator cend(size_type) const { - return const_local_iterator(base.data_.end(n)); + return const_local_iterator(); } // hash policy float load_factor() const { - return base.load_factor(); + return table_.load_factor(); } float max_load_factor() const { - return base.max_load_factor(); + return table_.mlf_; } void max_load_factor(float m) { - base.max_load_factor(m); + table_.max_load_factor(m); } void rehash(size_type n) { - base.rehash(n); + table_.rehash(n); } -#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) - friend bool operator==(unordered_multiset const&, unordered_multiset const&); - friend bool operator!=(unordered_multiset const&, unordered_multiset const&); -#elif !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) - friend bool operator==(unordered_multiset const&, unordered_multiset const&); - friend bool operator!=(unordered_multiset const&, unordered_multiset const&); +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) + friend bool operator==( + unordered_multiset const&, unordered_multiset const&); + friend bool operator!=( + unordered_multiset const&, unordered_multiset const&); #endif }; // class template unordered_multiset @@ -885,14 +936,14 @@ namespace boost inline bool operator==(unordered_multiset const& m1, unordered_multiset const& m2) { - return boost::unordered_detail::equals(m1.base, m2.base); + return m1.table_.equals(m2.table_); } template inline bool operator!=(unordered_multiset const& m1, unordered_multiset const& m2) { - return !boost::unordered_detail::equals(m1.base, m2.base); + return !m1.table_.equals(m2.table_); } template diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 97cc7fd2..a6ab923c 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -3,5 +3,7 @@ # Distributed under the Boost Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +import testing ; + build-project unordered ; build-project exception ; diff --git a/test/helpers/list.hpp b/test/helpers/list.hpp index f4985841..d5a8b170 100644 --- a/test/helpers/list.hpp +++ b/test/helpers/list.hpp @@ -21,14 +21,17 @@ namespace test namespace test_detail { - template struct list_node; + template class list_node; template class list_data; template class list_iterator; template class list_const_iterator; template - struct list_node + class list_node { + list_node(list_node const&); + list_node& operator=(list_node const&); + public: T value_; list_node* next_; @@ -243,8 +246,8 @@ namespace test node** merge_adjacent_ranges(node** first, node** second, node** third, Less less) { - while(true) { - while(true) { + for(;;) { + for(;;) { if(first == second) return third; if(less((*second)->value_, (*first)->value_)) break; first = &(*first)->next_; @@ -256,7 +259,7 @@ namespace test // Since the two ranges we just swapped, the order is now: // first...third...second - while(true) { + for(;;) { if(first == third) return second; if(!less((*first)->value_, (*third)->value_)) break; first = &(*first)->next_; diff --git a/test/unordered/Jamfile.v2 b/test/unordered/Jamfile.v2 index 9ecec284..ee1505f7 100644 --- a/test/unordered/Jamfile.v2 +++ b/test/unordered/Jamfile.v2 @@ -10,6 +10,7 @@ project unordered-test/unordered intel-linux:"-strict_ansi -cxxlib-icc" gcc:"-Wsign-promo -Wunused-parameter" #msvc:/W4 + all ; test-suite unordered diff --git a/test/unordered/constructor_tests.cpp b/test/unordered/constructor_tests.cpp index d5475b1f..0702e4e6 100644 --- a/test/unordered/constructor_tests.cpp +++ b/test/unordered/constructor_tests.cpp @@ -250,6 +250,19 @@ void constructor_tests2(T*, test::random_generator const& generator = test::defa test::check_equivalent_keys(x); test::check_equivalent_keys(y); } + + std::cerr<<"Construct 9\n"; + { + test::random_values v(100, generator); + T x(50); + BOOST_TEST(x.bucket_count() >= 50); + x.max_load_factor(10); + BOOST_TEST(x.bucket_count() >= 50); + x.insert(v.begin(), v.end()); + BOOST_TEST(x.bucket_count() >= 50); + test::check_container(x, v); + test::check_equivalent_keys(x); + } } template diff --git a/test/unordered/copy_tests.cpp b/test/unordered/copy_tests.cpp index dc143bb8..a4eea801 100644 --- a/test/unordered/copy_tests.cpp +++ b/test/unordered/copy_tests.cpp @@ -41,7 +41,7 @@ void copy_construct_tests1(T*, test::random_generator const& generator = test::d T x(v.begin(), v.end()); T y(x); test::unordered_equivalence_tester equivalent(x); - equivalent(y); + BOOST_TEST(equivalent(y)); test::check_equivalent_keys(y); } @@ -55,7 +55,7 @@ void copy_construct_tests1(T*, test::random_generator const& generator = test::d x.max_load_factor(x.load_factor() / 4); T y(x); test::unordered_equivalence_tester equivalent(x); - equivalent(y); + BOOST_TEST(equivalent(y)); // This isn't guaranteed: BOOST_TEST(y.load_factor() < y.max_load_factor()); test::check_equivalent_keys(y); @@ -100,7 +100,7 @@ void copy_construct_tests2(T* ptr, test::random_generator const& generator = tes T x(v.begin(), v.end(), 0, hf, eq, al); T y(x); test::unordered_equivalence_tester equivalent(x); - equivalent(y); + BOOST_TEST(equivalent(y)); test::check_equivalent_keys(y); BOOST_TEST(test::equivalent(y.get_allocator(), al)); } @@ -111,7 +111,7 @@ void copy_construct_tests2(T* ptr, test::random_generator const& generator = tes T x(v.begin(), v.end(), 0, hf, eq, al); T y(x, al2); test::unordered_equivalence_tester equivalent(x); - equivalent(y); + BOOST_TEST(equivalent(y)); test::check_equivalent_keys(y); BOOST_TEST(test::equivalent(y.get_allocator(), al2)); } diff --git a/test/unordered/erase_equiv_tests.cpp b/test/unordered/erase_equiv_tests.cpp index fbd56c27..a1bebf45 100644 --- a/test/unordered/erase_equiv_tests.cpp +++ b/test/unordered/erase_equiv_tests.cpp @@ -116,7 +116,7 @@ bool compare(Range1 const& x, Range2 const& y) } template -bool general_erase_range_test(Container& x, int start, int end) +bool general_erase_range_test(Container& x, std::size_t start, std::size_t end) { collide_list l(x.begin(), x.end()); l.erase(boost::next(l.begin(), start), boost::next(l.begin(), end)); diff --git a/test/unordered/move_tests.cpp b/test/unordered/move_tests.cpp index a78e6f8b..3d06686b 100644 --- a/test/unordered/move_tests.cpp +++ b/test/unordered/move_tests.cpp @@ -119,7 +119,7 @@ namespace move_tests BOOST_TEST(y.max_load_factor() == 2.0); // Not necessarily required. test::check_equivalent_keys(y); } - +/* { test::random_values v(25, generator); T y(create(v, count, hf, eq, al, 1.0), al); @@ -137,7 +137,7 @@ namespace move_tests BOOST_TEST(y.max_load_factor() == 1.0); // Not necessarily required. test::check_equivalent_keys(y); } - } +*/ } boost::unordered_set >* test_set; boost::unordered_multiset >* test_multiset; diff --git a/test/unordered/simple_tests.cpp b/test/unordered/simple_tests.cpp index fab91746..1e8063f5 100644 --- a/test/unordered/simple_tests.cpp +++ b/test/unordered/simple_tests.cpp @@ -60,6 +60,7 @@ void simple_test(X const& a) X u; X& r = u; BOOST_TEST(&(r = r) == &r); + BOOST_TEST(r.empty()); BOOST_TEST(&(r = a) == &r); BOOST_TEST(equivalent(r)); @@ -91,7 +92,7 @@ UNORDERED_AUTO_TEST(simple_tests) std::cout<<"Test unordered_set.\n"; boost::unordered_set set; simple_test(set); - + set.insert(1); set.insert(2); set.insert(1456); simple_test(set); From 3529bc00dc52c5f698be850bb141664a3088de63 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 10 Oct 2009 13:52:53 +0000 Subject: [PATCH 036/100] Merge unordred changes. Merged revisions 56441,56461,56468,56557-56562 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r56441 | danieljames | 2009-09-27 20:12:04 +0100 (Sun, 27 Sep 2009) | 1 line Try supporting reference parameters in pairs. Probably not required. ........ r56461 | danieljames | 2009-09-29 00:06:03 +0100 (Tue, 29 Sep 2009) | 1 line Remove the optimization for std::pair with a key reference. It'll be too much hassle to get a very unusual use case to work on all compilers. ........ r56468 | danieljames | 2009-09-29 08:46:44 +0100 (Tue, 29 Sep 2009) | 1 line Just remove the test since the test itself doesn't work on most compilers. ........ r56557 | danieljames | 2009-10-03 17:40:26 +0100 (Sat, 03 Oct 2009) | 1 line Fix the iterator category. ........ r56558 | danieljames | 2009-10-03 17:40:53 +0100 (Sat, 03 Oct 2009) | 2 lines Update reference docs to latest version of draft standard and fill in some missing details. ........ r56559 | danieljames | 2009-10-03 17:41:11 +0100 (Sat, 03 Oct 2009) | 1 line Stricter insert exception tests. ........ r56560 | danieljames | 2009-10-03 17:41:32 +0100 (Sat, 03 Oct 2009) | 1 line Insert using initializer lists. ........ r56561 | danieljames | 2009-10-03 17:42:00 +0100 (Sat, 03 Oct 2009) | 1 line Update the unordered rationale. ........ r56562 | danieljames | 2009-10-03 17:42:20 +0100 (Sat, 03 Oct 2009) | 1 line Make sure inserting from a range of types other than the value type is better tested. ........ [SVN r56700] --- doc/intro.qbk | 2 +- doc/rationale.qbk | 122 ++------ doc/ref.xml | 260 ++++++++++++++++-- .../boost/unordered/detail/extract_key.hpp | 15 - include/boost/unordered/detail/unique.hpp | 7 +- include/boost/unordered/unordered_map.hpp | 14 + include/boost/unordered/unordered_set.hpp | 14 + test/exception/insert_exception_tests.cpp | 14 +- test/helpers/strong.hpp | 8 +- test/objects/test.hpp | 4 + test/unordered/insert_tests.cpp | 75 ++++- 11 files changed, 395 insertions(+), 140 deletions(-) diff --git a/doc/intro.qbk b/doc/intro.qbk index 6e4b4ce1..ea06bfb7 100644 --- a/doc/intro.qbk +++ b/doc/intro.qbk @@ -9,7 +9,7 @@ [@http://www.boost.org/doc/html/boost_tr1.html Boost.TR1]] [def __draft__ - [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2691.pdf + [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2960.pdf Working Draft of the C++ Standard]] [def __hash-table__ [@http://en.wikipedia.org/wiki/Hash_table hash table]] diff --git a/doc/rationale.qbk b/doc/rationale.qbk index 62774a66..ff371386 100644 --- a/doc/rationale.qbk +++ b/doc/rationale.qbk @@ -5,12 +5,6 @@ [def __wang__ [@http://www.concentric.net/~Ttwang/tech/inthash.htm Thomas Wang's article on integer hash functions]] -[def __n2345__ - [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2007/n2345.pdf - N2345, 'Placement Insert for Containers']] -[def __n2369__ - [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2007/n2369.pdf - the August 2007 version of the working draft standard]] [section:rationale Implementation Rationale] @@ -99,105 +93,49 @@ So, this implementation uses a prime number for the hash table size. [h2 Equality operators] `operator==` and `operator!=` are not included in the standard, but I've -added them as I think they could be useful and can be efficiently -implemented. They are specified -differently to the standard associative containers, comparing keys -using the equality predicate rather than `operator==`. This is inconsistent -with the other containers but it is probably closer to user's expectations. +added them as I think they could be useful and can be implemented +fairly efficiently. They are specified differently to the other standard +containers, comparing keys using the equality predicate rather than +`operator==`. + +It's also different to the proposal +[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2944.pdf n2944]. +which uses the equality operators for the whole of `value_type`. This +implementation just uses the key equality function for the key, +and `mapped_type`'s equality operator in `unordered_map` and +`unordered_multimap` for the mapped part of the element. + +Also, in `unordered_multimap`, the mapped values for a group of elements with +equivalent keys are only considered equal if they are in the same order, +in n2944 they just need to be a permutation of each other. Since the +order of elements with equal keys is now defined to be stable, it seems to me +that their order can be considered part of the container's value. [h2 Active Issues and Proposals] -[h3 Removing unused allocator functions] +[h3 C++0x allocators] -In -[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2257.html -N2257, removing unused allocator functions], -Matt Austern suggests removing the `construct`, `destroy` and `address` member -functions - all of which Boost.Unordered calls. Changing this will simplify the -implementation, as well as make supporting `emplace` easier, but means that the -containers won't support allocators which require these methods to be called. -Detlef Vollmann opposed this change in -[@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2007/n2339.htm N2339]. +Recent drafts have included an overhaul of the allocators, but this was +dependent on concepts which are no longer in the standard. +[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2946.pdf n2946] +attempts to respecify them without concepts. I'll try to implement this (or +an appropriate later version) in a future version of boost, possibly changed +a little to accomodate non-C++0x compilers. [h3 Swapping containers with unequal allocators] It isn't clear how to swap containers when their allocators aren't equal. This is [@http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#431 -Issue 431: Swapping containers with unequal allocators]. - -Howard Hinnant wrote about this in -[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1599.html N1599] -and suggested swapping both the allocators and the containers' contents. -But the committee have now decided that `swap` should do a fast swap if the -allocator is Swappable and a slow swap using copy construction otherwise. To -make this distinction requires concepts. - -In -[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2387.pdf -N2387, Omnibus Allocator Fix-up Proposals], -Pablo Halpern suggests that there are actually two distinct allocator models, -"Moves with Value" and "Scoped" which behave differently: - -[: -When allocators are allowed to have state, it is necessary to have a model for -determining from where an object obtains its allocator. We’ve identified two such -models: the “Moves with Value” allocator model and the “Scoped” allocator model. - -In the “Moves with Value” allocator model, the copy constructor of an allocator-aware -class will copy both the value and the allocator from its argument. This is the model -specified in the C++03 standard. With this model, inserting an object into a container -usually causes the new container item to copy the allocator from the object that was -inserted. This model can be useful in special circumstances, e.g., if the items within a -container use an allocator that is specially tuned to the item’s type. - -In the “Scoped” allocator model, the allocator used to construct an object is determined -by the context of that object, much like a storage class. With this model, inserting an -object into a container causes the new container item to use the same allocator as the -container. To avoid allocators being used in the wrong context, the allocator is never -copied during copy or move construction. Thus, it is possible using this model to use -allocators based on short-lived resources without fear that an object will transfer its -allocator to a copy that might outlive the (shared) allocator resource. This model is -reasonably safe and generally useful on a large scale. There was strong support in the -2005 Tremblant meeting for pursuing an allocator model that propagates allocators -from container to contained objects. -] - -With these models the choice becomes clearer: - -[: -I introduced the “Moves with Value” allocator model and the -“Scoped” allocator model. In the former case, the allocator is copied when the container -is copy-constructed. In the latter case it is not. Swapping the allocators is the right thing -to do if the containers conform to the “Moves with Value” allocator model and -absolutely the wrong thing to do if the containers conform to the “Scoped” allocator -model. With the two allocator models well-defined, the desired behavior becomes clear. -] - -The proposal is that allocators are swapped if the allocator follows the -"Moves with Value" model and the allocator is swappable. Otherwise a slow swap -is used. Since containers currently only support the "Moves with Value" model -this is consistent with the committee's current recommendation (although it -suggests using a trait to detect if the allocator is swappable rather than a -concept). - -Since there is currently neither have a swappable trait or concept for -allocators this implementation always performs a slow swap. +Issue 431: Swapping containers with unequal allocators]. This has been resolved +with the new allocator specification, so this should be fixed when +support is added. [h3 Are insert and erase stable for unordered_multiset and unordered_multimap?] -It is not specified if `unordered_multiset` and `unordered_multimap` preserve the order +It wan't specified if `unordered_multiset` and `unordered_multimap` preserve the order of elements with equivalent keys (i.e. if they're stable under `insert` and `erase`). -This is [@http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#518 issue 581]. -The current proposal is that insert, erase and rehash are stable - so they are here. -(Update: during the release of this version, this requirement was added to -[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2691.pdf -the lastest working draft]). - -[h3 const_local_iterator cbegin, cend missing from TR1] - -[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2684.html#691 -Issue 691] is that `cbegin` and `cend` are missing for local iterators. -The current resolution is that they'll be added, so I've added them. +Since [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2691.pdf +n2691] it's been specified that they do and this implementation follows that. [endsect] diff --git a/doc/ref.xml b/doc/ref.xml index 67a2179b..4ca51abf 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -23,8 +23,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) An unordered associative container that stores unique values. - For the normative reference see chapter 23 of - the working draft of the C++ standard [n2691]. + Based on chapter 23 of + the working draft of the C++ standard [n2960]. + But without the updated rules for allocators. + Template Parameters @@ -93,7 +95,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) implementation-defined A constant iterator whose value type is value_type. - Any iterator category except output iterator. + The iterator category is at least a forward iterator. Convertible to const_iterator. @@ -101,7 +103,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) implementation-defined A constant iterator whose value type is value_type. - Any iterator category except output iterator. + The iterator category is at least a forward iterator. @@ -180,6 +182,26 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The copy constructor. Copies the contained elements, hash function, predicate, maximum load factor and allocator. + + value_type is copy constructible + + + + + unordered_set && + + + The move constructor. + + + This is emulated on compilers without rvalue references. + + + + value_type is move constructible. + (TODO: This is not actually required in this implementation). + + @@ -201,6 +223,9 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + The destructor is applied to every element, and all memory is deallocated + @@ -210,6 +235,38 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The assignment operator. Copies the contained elements, hash function, predicate and maximum load factor but not the allocator. + + + On compilers without rvalue references, there is a single assignment + operator with the signature operator=(unordered_set) + in order to emulate move semantics. + + + + value_type is copy constructible + + + + + unordered_set && + + unordered_set& + + The move assignment operator. + + + + On compilers without rvalue references, there is a single assignment + operator with the signature operator=(unordered_set) + in order to emulate move semantics. + + + + + value_type is move constructible. + (TODO: This is not actually required in this implementation). + + allocator_type @@ -761,8 +818,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) An unordered associative container that stores values. The same key can be stored multiple times. - For the normative reference see chapter 23 of - the working draft of the C++ standard [n2691]. + Based on chapter 23 of + the working draft of the C++ standard [n2960]. + But without the updated rules for allocators. + Template Parameters @@ -831,7 +890,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) implementation-defined A constant iterator whose value type is value_type. - Any iterator category except output iterator. + The iterator category is at least a forward iterator. Convertible to const_iterator. @@ -839,7 +898,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) implementation-defined A constant iterator whose value type is value_type. - Any iterator category except output iterator. + The iterator category is at least a forward iterator. @@ -918,6 +977,26 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The copy constructor. Copies the contained elements, hash function, predicate, maximum load factor and allocator. + + value_type is copy constructible + + + + + unordered_multiset && + + + The move constructor. + + + This is emulated on compilers without rvalue references. + + + + value_type is move constructible. + (TODO: This is not actually required in this implementation). + + @@ -939,6 +1018,9 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + The destructor is applied to every element, and all memory is deallocated + @@ -948,6 +1030,38 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The assignment operator. Copies the contained elements, hash function, predicate and maximum load factor but not the allocator. + + + On compilers without rvalue references, there is a single assignment + operator with the signature operator=(unordered_multiset) + in order to emulate move semantics. + + + + value_type is copy constructible + + + + + unordered_multiset && + + unordered_multiset& + + The move assignment operator. + + + + On compilers without rvalue references, there is a single assignment + operator with the signature operator=(unordered_multiset) + in order to emulate move semantics. + + + + + value_type is move constructible. + (TODO: This is not actually required in this implementation). + + allocator_type @@ -1503,8 +1617,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) An unordered associative container that associates unique keys with another value. - For the normative reference see chapter 23 of - the working draft of the C++ standard [n2691]. + Based on chapter 23 of + the working draft of the C++ standard [n2960]. + But without the updated rules for allocators. + Template Parameters @@ -1579,7 +1695,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) implementation-defined A iterator whose value type is value_type. - Any iterator category except output iterator. + The iterator category is at least a forward iterator. Convertible to const_iterator. @@ -1587,7 +1703,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) implementation-defined A constant iterator whose value type is value_type. - Any iterator category except output iterator. + The iterator category is at least a forward iterator. @@ -1666,6 +1782,26 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The copy constructor. Copies the contained elements, hash function, predicate, maximum load factor and allocator. + + value_type is copy constructible + + + + + unordered_map && + + + The move constructor. + + + This is emulated on compilers without rvalue references. + + + + value_type is move constructible. + (TODO: This is not actually required in this implementation). + + @@ -1687,6 +1823,9 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + The destructor is applied to every element, and all memory is deallocated + @@ -1696,6 +1835,38 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The assignment operator. Copies the contained elements, hash function, predicate and maximum load factor but not the allocator. + + + On compilers without rvalue references, there is a single assignment + operator with the signature operator=(unordered_map) + in order to emulate move semantics. + + + + value_type is copy constructible + + + + + unordered_map && + + unordered_map& + + The move assignment operator. + + + + On compilers without rvalue references, there is a single assignment + operator with the signature operator=(unordered_map) + in order to emulate move semantics. + + + + + value_type is move constructible. + (TODO: This is not actually required in this implementation). + + allocator_type @@ -2290,8 +2461,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) An unordered associative container that associates keys with another value. The same key can be stored multiple times. - For the normative reference see chapter 23 of - the working draft of the C++ standard [n2691]. + Based on chapter 23 of + the working draft of the C++ standard [n2960]. + But without the updated rules for allocators. + Template Parameters @@ -2366,7 +2539,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) implementation-defined A iterator whose value type is value_type. - Any iterator category except output iterator. + The iterator category is at least a forward iterator. Convertible to const_iterator. @@ -2374,7 +2547,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) implementation-defined A constant iterator whose value type is value_type. - Any iterator category except output iterator. + The iterator category is at least a forward iterator. @@ -2453,6 +2626,26 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The copy constructor. Copies the contained elements, hash function, predicate, maximum load factor and allocator. + + value_type is copy constructible + + + + + unordered_multimap && + + + The move constructor. + + + This is emulated on compilers without rvalue references. + + + + value_type is move constructible. + (TODO: This is not actually required in this implementation). + + @@ -2474,6 +2667,9 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + The destructor is applied to every element, and all memory is deallocated + @@ -2483,6 +2679,38 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The assignment operator. Copies the contained elements, hash function, predicate and maximum load factor but not the allocator. + + + On compilers without rvalue references, there is a single assignment + operator with the signature operator=(unordered_multimap) + in order to emulate move semantics. + + + + value_type is copy constructible + + + + + unordered_multimap && + + unordered_multimap& + + The move assignment operator. + + + + On compilers without rvalue references, there is a single assignment + operator with the signature operator=(unordered_multimap) + in order to emulate move semantics. + + + + + value_type is move constructible. + (TODO: This is not actually required in this implementation). + + allocator_type diff --git a/include/boost/unordered/detail/extract_key.hpp b/include/boost/unordered/detail/extract_key.hpp index cba889eb..d415d935 100644 --- a/include/boost/unordered/detail/extract_key.hpp +++ b/include/boost/unordered/detail/extract_key.hpp @@ -106,21 +106,6 @@ namespace unordered_detail { { return v.first; } -/* - template - static key_type const& extract( - std::pair const& v) - { - return v.first; - } - - template - static key_type const& extract( - std::pair const& v) - { - return v.first; - } -*/ #if defined(BOOST_UNORDERED_STD_FORWARD) template diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index b4a5157c..552a1d51 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -324,10 +324,9 @@ namespace boost { namespace unordered_detail { do { // No side effects in this initial code - // Note: can't use get_key as '*i' might not be value_type. - // TODO: Check if std::pair has an appropriate constructor. If not - // that might not be true. - // TODO: Test this line better. + // Note: can't use get_key as '*i' might not be value_type - it could + // be a pair with first_types as key_type without const or a + // different second_type. key_type const& k = extractor::extract(*i); std::size_t hash_value = this->hash_function()(k); bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index f4c052f5..36b17f78 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -343,6 +343,13 @@ namespace boost table_.insert_range(first, last); } +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + void insert(std::initializer_list list) + { + table_.insert_range(list.begin(), list.end()); + } +#endif + iterator erase(const_iterator position) { return iterator(table_.erase(get(position))); @@ -837,6 +844,13 @@ namespace boost table_.insert_range(first, last); } +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + void insert(std::initializer_list list) + { + table_.insert_range(list.begin(), list.end()); + } +#endif + iterator erase(const_iterator position) { return iterator(table_.erase(get(position))); diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 2b147b28..82446025 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -337,6 +337,13 @@ namespace boost table_.insert_range(first, last); } +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + void insert(std::initializer_list list) + { + table_.insert_range(list.begin(), list.end()); + } +#endif + iterator erase(const_iterator position) { return iterator(table_.erase(get(position))); @@ -793,6 +800,13 @@ namespace boost table_.insert_range(first, last); } +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + void insert(std::initializer_list list) + { + table_.insert_range(list.begin(), list.end()); + } +#endif + iterator erase(const_iterator position) { return iterator(table_.erase(get(position))); diff --git a/test/exception/insert_exception_tests.cpp b/test/exception/insert_exception_tests.cpp index acb47b48..cf7d04e0 100644 --- a/test/exception/insert_exception_tests.cpp +++ b/test/exception/insert_exception_tests.cpp @@ -31,7 +31,7 @@ struct insert_test_base : public test::exception_base std::string scope(test::scope); if(scope.find("hash::operator()") == std::string::npos) - strong.test(x); + strong.test(x, test::exception::detail::tracker.count_allocations); test::check_equivalent_keys(x); } }; @@ -47,7 +47,7 @@ struct emplace_test1 : public insert_test_base for(BOOST_DEDUCED_TYPENAME test::random_values::const_iterator it = this->values.begin(), end = this->values.end(); it != end; ++it) { - strong.store(x); + strong.store(x, test::exception::detail::tracker.count_allocations); x.emplace(*it); } } @@ -64,7 +64,7 @@ struct insert_test1 : public insert_test_base for(BOOST_DEDUCED_TYPENAME test::random_values::const_iterator it = this->values.begin(), end = this->values.end(); it != end; ++it) { - strong.store(x); + strong.store(x, test::exception::detail::tracker.count_allocations); x.insert(*it); } } @@ -79,7 +79,7 @@ struct insert_test2 : public insert_test_base for(BOOST_DEDUCED_TYPENAME test::random_values::const_iterator it = this->values.begin(), end = this->values.end(); it != end; ++it) { - strong.store(x); + strong.store(x, test::exception::detail::tracker.count_allocations); x.insert(x.begin(), *it); } } @@ -106,7 +106,7 @@ struct insert_test4 : public insert_test_base for(BOOST_DEDUCED_TYPENAME test::random_values::const_iterator it = this->values.begin(), end = this->values.end(); it != end; ++it) { - strong.store(x); + strong.store(x, test::exception::detail::tracker.count_allocations); x.insert(it, boost::next(it)); } } @@ -144,7 +144,7 @@ struct insert_test_rehash1 : public insert_test_base it = boost::next(this->values.begin(), x.size()), end = this->values.end(); it != end && count < 10; ++it, ++count) { - strong.store(x); + strong.store(x, test::exception::detail::tracker.count_allocations); pos = x.insert(pos, *it); } @@ -167,7 +167,7 @@ struct insert_test_rehash2 : public insert_test_rehash1 it = boost::next(this->values.begin(), x.size()), end = this->values.end(); it != end && count < 10; ++it, ++count) { - strong.store(x); + strong.store(x, test::exception::detail::tracker.count_allocations); x.insert(*it); } diff --git a/test/helpers/strong.hpp b/test/helpers/strong.hpp index 4ffcca2b..a297fe07 100644 --- a/test/helpers/strong.hpp +++ b/test/helpers/strong.hpp @@ -20,18 +20,22 @@ namespace test { typedef test::list values_type; values_type values_; + unsigned int allocations_; public: - void store(X const& x) { + void store(X const& x, unsigned int allocations = 0) { DISABLE_EXCEPTIONS; values_.clear(); values_.insert(x.cbegin(), x.cend()); + allocations_ = allocations; } - void test(X const& x) const { + void test(X const& x, unsigned int allocations = 0) const { if(!(x.size() == values_.size() && std::equal(x.cbegin(), x.cend(), values_.begin(), test::equivalent))) BOOST_ERROR("Strong exception safety failure."); + if(allocations != allocations_) + BOOST_ERROR("Strong exception failure: extra allocations."); } }; } diff --git a/test/objects/test.hpp b/test/objects/test.hpp index 63f7c91b..767dbb4a 100644 --- a/test/objects/test.hpp +++ b/test/objects/test.hpp @@ -93,6 +93,10 @@ namespace test return x1.type_ != x2.type_; } }; + + std::size_t hash_value(test::object const& x) { + return hash()(x); + } class less { diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 6a4f4d86..a277cbb7 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -313,10 +313,12 @@ void map_tests(X*, test::random_generator generator = test::default_generator) test::check_equivalent_keys(x); } +// Some tests for when the range's value type doesn't match the container's value type. + template -void associative_insert_range_test(X*, test::random_generator generator = test::default_generator) +void map_insert_range_test1(X*, test::random_generator generator = test::default_generator) { - std::cerr<<"associative_insert_range_test\n"; + std::cerr<<"map_insert_range_test1\n"; typedef test::list > list; test::random_values v(1000, generator); @@ -327,6 +329,20 @@ void associative_insert_range_test(X*, test::random_generator generator = test:: test::check_equivalent_keys(x); } +template +void map_insert_range_test2(X*, test::random_generator generator = test::default_generator) +{ + std::cerr<<"map_insert_range_test2\n"; + + typedef test::list > list; + test::random_values > v(1000, generator); + list l(v.begin(), v.end()); + + X x; x.insert(l.begin(), l.end()); + + test::check_equivalent_keys(x); +} + boost::unordered_set >* test_set; boost::unordered_multiset >* test_multiset; boost::unordered_map >* test_map; @@ -367,11 +383,64 @@ UNORDERED_TEST(map_tests, ((default_generator)(generate_collisions)) ) -UNORDERED_TEST(associative_insert_range_test, +UNORDERED_TEST(map_insert_range_test1, ((test_map)(test_multimap)) ((default_generator)(generate_collisions)) ) +UNORDERED_TEST(map_insert_range_test2, + ((test_map)(test_multimap)) + ((default_generator)(generate_collisions)) +) + +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + +UNORDERED_AUTO_TEST(insert_initializer_list_set) +{ + boost::unordered_set set; + set.insert({1,2,3,1}); + BOOST_TEST_EQ(set.size(), 3u); + BOOST_TEST(set.find(1) != set.end()); + BOOST_TEST(set.find(4) == set.end()); +} + +UNORDERED_AUTO_TEST(insert_initializer_list_multiset) +{ + boost::unordered_multiset multiset; + multiset.insert({}); + BOOST_TEST(multiset.empty()); + multiset.insert({"a"}); + BOOST_TEST_EQ(multiset.size(), 1u); + BOOST_TEST(multiset.find("a") != multiset.end()); + BOOST_TEST(multiset.find("b") == multiset.end()); + multiset.insert({"a","b"}); + BOOST_TEST(multiset.size() == 3); + BOOST_TEST_EQ(multiset.count("a"), 2u); + BOOST_TEST_EQ(multiset.count("b"), 1u); + BOOST_TEST_EQ(multiset.count("c"), 0u); +} + +UNORDERED_AUTO_TEST(insert_initializer_list_map) +{ + boost::unordered_map map; + map.insert({}); + BOOST_TEST(map.empty()); + map.insert({{"a", "b"},{"a", "b"},{"d", ""}}); + BOOST_TEST_EQ(map.size(), 2u); +} + +UNORDERED_AUTO_TEST(insert_initializer_list_multimap) +{ + boost::unordered_multimap multimap; + multimap.insert({}); + BOOST_TEST(multimap.empty()); + multimap.insert({{"a", "b"},{"a", "b"},{"d", ""}}); + BOOST_TEST_EQ(multimap.size(), 3u); + BOOST_TEST_EQ(multimap.count("a"), 2u); +} + +#endif + } RUN_TESTS() From 06b0b1d31c1dda4abe94400d75c8cf6858eee29a Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 10 Oct 2009 14:53:46 +0000 Subject: [PATCH 037/100] Merge some documentation changes and inspect fixes. Merged revisions 55370,55729,56440,56570-56571,56603,56697-56699 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r55370 | danieljames | 2009-08-02 19:18:14 +0100 (Sun, 02 Aug 2009) | 1 line Pass through more elements in doxygen2boostbook. Refs #3309. ........ r55729 | danieljames | 2009-08-23 11:07:25 +0100 (Sun, 23 Aug 2009) | 3 lines Add depencies on doxygen documentation to standalone documentation targets. This seems to be needed for building pdfs. ........ r56440 | danieljames | 2009-09-27 20:11:39 +0100 (Sun, 27 Sep 2009) | 1 line Fix silly error in doxygen test file. ........ r56570 | danieljames | 2009-10-04 11:37:36 +0100 (Sun, 04 Oct 2009) | 1 line Clean up some unordered TODOs. ........ r56571 | danieljames | 2009-10-04 11:37:56 +0100 (Sun, 04 Oct 2009) | 1 line Detab. ........ r56603 | danieljames | 2009-10-05 22:29:39 +0100 (Mon, 05 Oct 2009) | 1 line Various inspect fixes. ........ r56697 | danieljames | 2009-10-10 14:00:28 +0100 (Sat, 10 Oct 2009) | 1 line Add forwarding html file for accumulators. ........ r56698 | danieljames | 2009-10-10 14:01:14 +0100 (Sat, 10 Oct 2009) | 1 line Missing newline. ........ r56699 | danieljames | 2009-10-10 14:01:30 +0100 (Sat, 10 Oct 2009) | 1 line Add copyright to boostbook reference xml. ........ [SVN r56702] --- include/boost/unordered/detail/buckets.hpp | 7 ++- include/boost/unordered/detail/equivalent.hpp | 1 - include/boost/unordered/detail/table.hpp | 19 +++----- test/helpers/list.hpp | 4 +- test/unordered/rehash_tests.cpp | 43 +++++++++++++++++++ 5 files changed, 55 insertions(+), 19 deletions(-) diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index 8a2163c6..0f513e44 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -15,7 +15,6 @@ namespace boost { namespace unordered_detail { //////////////////////////////////////////////////////////////////////////// // Buckets - // TODO: Are these needed? template inline BOOST_DEDUCED_TYPENAME hash_buckets::bucket_ptr @@ -32,7 +31,7 @@ namespace boost { namespace unordered_detail { } template - inline std::size_t hash_buckets::bucket_size(std::size_t index) const + std::size_t hash_buckets::bucket_size(std::size_t index) const { if(!buckets_) return 0; bucket_ptr ptr = get_bucket(index)->next_; @@ -157,7 +156,7 @@ namespace boost { namespace unordered_detail { template inline void hash_buckets::move(hash_buckets& other) { - BOOST_ASSERT(node_alloc() == other.node_alloc()); + BOOST_ASSERT(node_alloc() == other.node_alloc()); if(this->buckets_) { this->delete_buckets(); } this->buckets_ = other.buckets_; this->bucket_count_ = other.bucket_count_; @@ -168,7 +167,7 @@ namespace boost { namespace unordered_detail { template inline void hash_buckets::swap(hash_buckets& other) { - BOOST_ASSERT(node_alloc() == other.node_alloc()); + BOOST_ASSERT(node_alloc() == other.node_alloc()); std::swap(buckets_, other.buckets_); std::swap(bucket_count_, other.bucket_count_); } diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index fa05019d..5f250d62 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -257,7 +257,6 @@ namespace boost { namespace unordered_detail { // if hash function throws, or inserting > 1 element, basic exception safety // strong otherwise - // TODO: Should I special case an empty container? template template void hash_equivalent_table::insert_range(I i, I j) diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 4e7a5811..bba3a07f 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -193,7 +193,7 @@ namespace boost { namespace unordered_detail { BOOST_ASSERT(this->bucket_count_ != 0); return static_cast(this->size_) / static_cast(this->bucket_count_); - } + } //////////////////////////////////////////////////////////////////////////// // Constructors @@ -431,23 +431,20 @@ namespace boost { namespace unordered_detail { // if hash function throws, basic exception safety // strong otherwise. - // TODO: Should this always create buckets? + template inline void hash_table::rehash(std::size_t min_buckets) { using namespace std; - if(!this->buckets_) { + if(!this->size_) { + if(this->buckets_) this->delete_buckets(); this->bucket_count_ = next_prime(min_buckets); - this->create_buckets(); - this->init_buckets(); } else { // no throw: - // TODO: Needlessly calling next_prime twice. - min_buckets = (std::max)( - next_prime(min_buckets), - this->min_buckets_for_size(this->size_)); + min_buckets = next_prime((std::max)(min_buckets, + double_to_size_t(floor(this->size_ / (double) mlf_)) + 1)); if(min_buckets != this->bucket_count_) rehash_impl(min_buckets); } } @@ -619,7 +616,6 @@ namespace boost { namespace unordered_detail { template void hash_table::clear() { - // TODO: Is this check needed when called internally? if(!this->size_) return; bucket_ptr end = this->get_bucket(this->bucket_count_); @@ -645,8 +641,7 @@ namespace boost { namespace unordered_detail { } template - std::size_t hash_table - ::erase_key(key_type const& k) + std::size_t hash_table::erase_key(key_type const& k) { if(!this->size_) return 0; diff --git a/test/helpers/list.hpp b/test/helpers/list.hpp index d5a8b170..128386e0 100644 --- a/test/helpers/list.hpp +++ b/test/helpers/list.hpp @@ -29,8 +29,8 @@ namespace test template class list_node { - list_node(list_node const&); - list_node& operator=(list_node const&); + list_node(list_node const&); + list_node& operator=(list_node const&); public: T value_; list_node* next_; diff --git a/test/unordered/rehash_tests.cpp b/test/unordered/rehash_tests.cpp index 64608cb9..0f1d7820 100644 --- a/test/unordered/rehash_tests.cpp +++ b/test/unordered/rehash_tests.cpp @@ -32,6 +32,43 @@ void rehash_empty_test1(X* = 0) BOOST_TEST(postcondition(x, 0)); } +template +void rehash_empty_test2(X* = 0, test::random_generator generator = test::default_generator) +{ + test::random_values v(1000, generator); + test::ordered tracker; + + X x; + + x.rehash(10000); + BOOST_TEST(postcondition(x, 10000)); + + tracker.insert_range(v.begin(), v.end()); + x.insert(v.begin(), v.end()); + tracker.compare(x); + + BOOST_TEST(postcondition(x, 10000)); +} + +template +void rehash_empty_test3(X* = 0, test::random_generator generator = test::default_generator) +{ + test::random_values v(1000, generator); + test::ordered tracker; + + X x; + + x.rehash(0); + BOOST_TEST(postcondition(x, 0)); + + tracker.insert_range(v.begin(), v.end()); + x.insert(v.begin(), v.end()); + tracker.compare(x); + + BOOST_TEST(postcondition(x, 0)); +} + + template void rehash_test1(X* = 0, test::random_generator generator = test::default_generator) { @@ -63,6 +100,12 @@ boost::unordered_multimap* int_multimap_ptr; UNORDERED_TEST(rehash_empty_test1, ((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr)) ) +UNORDERED_TEST(rehash_empty_test2, + ((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr)) +) +UNORDERED_TEST(rehash_empty_test3, + ((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr)) +) UNORDERED_TEST(rehash_test1, ((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr)) ) From 14e09a5456997eb66f6fa9971b70db51bd8ff81a Mon Sep 17 00:00:00 2001 From: "Troy D. Straszheim" Date: Sat, 17 Oct 2009 01:10:45 +0000 Subject: [PATCH 038/100] rm cmake from the release branch before it goes out broken. Policy dictates that you never commit to release, you commit to trunk and merge to release. [SVN r56941] --- CMakeLists.txt | 29 ----------------------- module.cmake | 1 - test/CMakeLists.txt | 24 ------------------- test/exception/CMakeLists.txt | 25 -------------------- test/unordered/CMakeLists.txt | 43 ----------------------------------- 5 files changed, 122 deletions(-) delete mode 100644 CMakeLists.txt delete mode 100644 module.cmake delete mode 100644 test/CMakeLists.txt delete mode 100644 test/exception/CMakeLists.txt delete mode 100644 test/unordered/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index b7dd577c..00000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -# -# Copyright Troy D. Straszheim -# -# Distributed under the Boost Software License, Version 1.0. -# See http://www.boost.org/LICENSE_1_0.txt -# -#---------------------------------------------------------------------------- -# This file was automatically generated from the original CMakeLists.txt file -# Add a variable to hold the headers for the library -set (lib_headers - unordered_map.hpp - unordered_set.hpp - unordered -) - -# Add a library target to the build system -boost_library_project( - unordered - # SRCDIRS - TESTDIRS test - HEADERS ${lib_headers} - # DOCDIRS - # DESCRIPTION - MODULARIZED - # AUTHORS - # MAINTAINERS -) - - diff --git a/module.cmake b/module.cmake deleted file mode 100644 index 30e27698..00000000 --- a/module.cmake +++ /dev/null @@ -1 +0,0 @@ -boost_module(unordered DEPENDS config functional) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt deleted file mode 100644 index a941b96f..00000000 --- a/test/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -# -# Copyright Troy D. Straszheim -# -# Distributed under the Boost Software License, Version 1.0. -# See http://www.boost.org/LICENSE_1_0.txt -# -boost_additional_test_dependencies(unordered BOOST_DEPENDS test) - -# GCC Compilers -IF(CMAKE_COMPILER_IS_GNUCC) - SET(test_compile_flags "-Wsign-promo -Wunused-parameter") -ENDIF(CMAKE_COMPILER_IS_GNUCC) - -# Intel Compiler flags -IF( ${CMAKE_CXX_COMPILER} MATCHES "icpc" ) - SET(test_compile_flags "${test_compile_flags} -strict_ansi -cxxlib-icc") -ENDIF( ${CMAKE_CXX_COMPILER} MATCHES "icpc" ) - -set (swap_compile_flags "${test_compile_flags} -DBOOST_UNORDERED_SWAP_METHOD=2") - - - -add_subdirectory(exception) -add_subdirectory(unordered) \ No newline at end of file diff --git a/test/exception/CMakeLists.txt b/test/exception/CMakeLists.txt deleted file mode 100644 index aacdf3d9..00000000 --- a/test/exception/CMakeLists.txt +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright Troy D. Straszheim -# -# Distributed under the Boost Software License, Version 1.0. -# See http://www.boost.org/LICENSE_1_0.txt -# - -foreach(test - constructor_exception_tests - copy_exception_tests - assign_exception_tests - insert_exception_tests - erase_exception_tests - rehash_exception_tests - ) - boost_test_run(${test} - COMPILE_FLAGS ${test_compile_flags} - DEPENDS boost_unit_test_framework) -endforeach(test ${unordered_tests}) - -#-- run the swap test -boost_test_run(swap_exception_tests - COMPILE_FLAGS ${swap_compile_flags} - DEPENDS boost_unit_test_framework) - diff --git a/test/unordered/CMakeLists.txt b/test/unordered/CMakeLists.txt deleted file mode 100644 index 68d92be8..00000000 --- a/test/unordered/CMakeLists.txt +++ /dev/null @@ -1,43 +0,0 @@ -# -# Copyright Troy D. Straszheim -# -# Distributed under the Boost Software License, Version 1.0. -# See http://www.boost.org/LICENSE_1_0.txt -# -#------------------------------------------------------------------------------- -# Unordered Tests -foreach(test - fwd_set_test - fwd_map_test - compile_set - compile_map - simple_tests - equivalent_keys_tests - constructor_tests - copy_tests - move_tests - assign_tests - insert_tests - insert_stable_tests - unnecessary_copy_tests - erase_tests - erase_equiv_tests - find_tests - at_tests - bucket_tests - load_factor_tests - rehash_tests - equality_tests - ) - boost_test_run(${test} - COMPILE_FLAGS ${test_compile_flags} - DEPENDS boost_unit_test_framework) -endforeach() - -boost_test_run(link_test link_test_1.cpp link_test_2.cpp) - -#-- run the swap test -boost_test_run(swap_tests - COMPILE_FLAGS ${swap_compile_flags} - DEPENDS boost_unit_test_framework) - From 584eaad67a2aefe277ac1a40dac8ef1077745656 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 20 Oct 2009 23:05:28 +0000 Subject: [PATCH 039/100] A couple of bug fixes for unordered containers. Merged revisions 57005-57006 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r57005 | danieljames | 2009-10-19 20:24:33 +0100 (Mon, 19 Oct 2009) | 6 lines Use normal emplace implementation for emplace_hint and insert with hint. There's a bug in the emplace_hint implementation for unordered containers with equivalent keys. Since my tests missed it, I'm just going to use the normal emplace implementation until I write better tests. ........ r57006 | danieljames | 2009-10-19 20:32:09 +0100 (Mon, 19 Oct 2009) | 1 line Fix allocator for construct from initializer list. ........ [SVN r57027] --- include/boost/unordered/detail/equivalent.hpp | 61 ------------------- include/boost/unordered/detail/fwd.hpp | 10 +-- include/boost/unordered/unordered_map.hpp | 25 ++++---- include/boost/unordered/unordered_set.hpp | 23 ++++--- test/unordered/constructor_tests.cpp | 53 ++++++++++++++++ 5 files changed, 77 insertions(+), 95 deletions(-) diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 5f250d62..7e52a609 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -96,36 +96,6 @@ namespace boost { namespace unordered_detail { } } - template - inline BOOST_DEDUCED_TYPENAME - hash_equivalent_table::iterator_base - hash_equivalent_table - ::emplace_hint_impl(iterator_base const& it, node_constructor& a) - { - // equal can throw, but with no effects - if (!it.node_ || !equal(get_key(a.value()), *it)) { - // 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 added at the end of the group. - - node_ptr start = node::first_in_group(it.node_); - - // reserve has basic exception safety if the hash function - // throws, strong otherwise. - bucket_ptr bucket = this->reserve_for_insert(this->size_ + 1) ? - get_bucket(this->bucket_index(get_key(a.value()))) : - it.bucket_; - - // Nothing after this point can throw - - return iterator_base(bucket, add_node(a, bucket, start)); - } - } - template inline void hash_equivalent_table ::emplace_impl_no_rehash(node_constructor& a) @@ -156,25 +126,6 @@ namespace boost { namespace unordered_detail { return emplace_impl(a); } - // Emplace (equivalent key containers) - // (I'm using an overloaded emplace for both 'insert' and 'emplace') - - // if hash function throws, basic exception safety - // strong otherwise - template - template - BOOST_DEDUCED_TYPENAME hash_equivalent_table::iterator_base - hash_equivalent_table - ::emplace_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(*this); - a.construct(std::forward(args)...); - - return emplace_hint_impl(it, a); - } - #else #define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \ @@ -187,18 +138,6 @@ namespace boost { namespace unordered_detail { node_constructor a(*this); \ a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ return emplace_impl(a); \ - } \ - \ - template \ - template \ - BOOST_DEDUCED_TYPENAME hash_equivalent_table::iterator_base \ - hash_equivalent_table \ - ::emplace_hint(iterator_base const& it, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ - { \ - node_constructor a(*this); \ - a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ - return emplace_hint_impl(it, a); \ } BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index 39f85427..3a5e3f73 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -710,8 +710,6 @@ namespace boost { namespace unordered_detail { // Insert methods iterator_base emplace_impl(node_constructor& a); - iterator_base emplace_hint_impl(iterator_base const& it, - node_constructor& a); void emplace_impl_no_rehash(node_constructor& a); // equals @@ -725,18 +723,12 @@ namespace boost { namespace unordered_detail { template iterator_base emplace(Args&&... args); - template - iterator_base emplace_hint(iterator_base const& it, Args&&... args); #else #define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ template \ - iterator_base emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \ - \ - template \ - iterator_base emplace_hint(iterator_base const& it, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); + iterator_base emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_INSERT_IMPL, _) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 36b17f78..8fab6e65 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -199,7 +199,7 @@ namespace boost const allocator_type &a = allocator_type()) : table_(boost::unordered_detail::initial_size( list.begin(), list.end(), n), - hf, eql, allocator_type()) + hf, eql, a) { table_.insert_range(list.begin(), list.end()); } @@ -311,7 +311,7 @@ namespace boost template < \ BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ > \ - iterator emplace_hint(const_iterator hint, \ + iterator emplace_hint(const_iterator, \ BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ ) \ { \ @@ -332,7 +332,7 @@ namespace boost table_.emplace(obj)); } - iterator insert(const_iterator hint, const value_type& obj) + iterator insert(const_iterator, const value_type& obj) { return iterator(table_.emplace(obj).first); } @@ -699,7 +699,7 @@ namespace boost const allocator_type &a = allocator_type()) : table_(boost::unordered_detail::initial_size( list.begin(), list.end(), n), - hf, eql, allocator_type()) + hf, eql, a) { table_.insert_range(list.begin(), list.end()); } @@ -776,10 +776,9 @@ namespace boost } template - iterator emplace_hint(const_iterator hint, Args&&... args) + iterator emplace_hint(const_iterator, Args&&... args) { - return iterator(table_.emplace_hint(get(hint), - std::forward(args)...)); + return iterator(table_.emplace(std::forward(args)...)); } #else @@ -788,10 +787,10 @@ namespace boost return iterator(table_.emplace(v)); } - iterator emplace_hint(const_iterator hint, + iterator emplace_hint(const_iterator, value_type const& v = value_type()) { - return iterator(table_.emplace_hint(get(hint), v)); + return iterator(table_.emplace(v)); } @@ -812,11 +811,11 @@ namespace boost template < \ BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ > \ - iterator emplace_hint(const_iterator hint, \ + iterator emplace_hint(const_iterator, \ BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ ) \ { \ - return iterator(table_.emplace_hint(get(hint), \ + return iterator(table_.emplace( \ BOOST_UNORDERED_CALL_PARAMS(z, n) \ )); \ } @@ -833,9 +832,9 @@ namespace boost return iterator(table_.emplace(obj)); } - iterator insert(const_iterator hint, const value_type& obj) + iterator insert(const_iterator, const value_type& obj) { - return iterator(table_.emplace_hint(get(hint), obj)); + return iterator(table_.emplace(obj)); } template diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 82446025..16418c11 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -192,7 +192,7 @@ namespace boost const allocator_type &a = allocator_type()) : table_(boost::unordered_detail::initial_size( list.begin(), list.end(), n), - hf, eql, allocator_type()) + hf, eql, a) { table_.insert_range(list.begin(), list.end()); } @@ -326,7 +326,7 @@ namespace boost table_.emplace(obj)); } - iterator insert(const_iterator hint, const value_type& obj) + iterator insert(const_iterator, const value_type& obj) { return iterator(table_.emplace(obj).first); } @@ -658,7 +658,7 @@ namespace boost const allocator_type &a = allocator_type()) : table_(boost::unordered_detail::initial_size( list.begin(), list.end(), n), - hf, eql, allocator_type()) + hf, eql, a) { table_.insert_range(list.begin(), list.end()); } @@ -735,10 +735,9 @@ namespace boost } template - iterator emplace_hint(const_iterator hint, Args&&... args) + iterator emplace_hint(const_iterator, Args&&... args) { - return iterator(table_.emplace_hint(get(hint), - std::forward(args)...)); + return iterator(table_.emplace(std::forward(args)...)); } #else @@ -747,10 +746,10 @@ namespace boost return iterator(table_.emplace(v)); } - iterator emplace_hint(const_iterator hint, + iterator emplace_hint(const_iterator, value_type const& v = value_type()) { - return iterator(table_.emplace_hint(get(hint), v)); + return iterator(table_.emplace(v)); } #define BOOST_UNORDERED_EMPLACE(z, n, _) \ @@ -768,11 +767,11 @@ namespace boost template < \ BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ > \ - iterator emplace_hint(const_iterator hint, \ + iterator emplace_hint(const_iterator, \ BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ ) \ { \ - return iterator(table_.emplace_hint(get(hint), \ + return iterator(table_.emplace( \ BOOST_UNORDERED_CALL_PARAMS(z, n) \ )); \ } @@ -789,9 +788,9 @@ namespace boost return iterator(table_.emplace(obj)); } - iterator insert(const_iterator hint, const value_type& obj) + iterator insert(const_iterator, const value_type& obj) { - return iterator(table_.emplace_hint(get(hint), obj)); + return iterator(table_.emplace(obj)); } template diff --git a/test/unordered/constructor_tests.cpp b/test/unordered/constructor_tests.cpp index 0702e4e6..8ddd005c 100644 --- a/test/unordered/constructor_tests.cpp +++ b/test/unordered/constructor_tests.cpp @@ -263,6 +263,59 @@ void constructor_tests2(T*, test::random_generator const& generator = test::defa test::check_container(x, v); test::check_equivalent_keys(x); } + +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + std::initializer_list list; + + std::cerr<<"Initializer list construct 1\n"; + { + T x(list); + BOOST_TEST(x.empty()); + BOOST_TEST(test::equivalent(x.hash_function(), hf)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + BOOST_TEST(test::equivalent(x.get_allocator(), al)); + } + + std::cerr<<"Initializer list construct 2\n"; + { + T x(list, 1000); + BOOST_TEST(x.empty()); + BOOST_TEST(x.bucket_count() >= 1000); + BOOST_TEST(test::equivalent(x.hash_function(), hf)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + BOOST_TEST(test::equivalent(x.get_allocator(), al)); + } + + std::cerr<<"Initializer list construct 3\n"; + { + T x(list, 10, hf1); + BOOST_TEST(x.empty()); + BOOST_TEST(x.bucket_count() >= 10); + BOOST_TEST(test::equivalent(x.hash_function(), hf1)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + BOOST_TEST(test::equivalent(x.get_allocator(), al)); + } + + std::cerr<<"Initializer list construct 4\n"; + { + T x(list, 10, hf1, eq1); + BOOST_TEST(x.empty()); + BOOST_TEST(x.bucket_count() >= 10); + BOOST_TEST(test::equivalent(x.hash_function(), hf1)); + BOOST_TEST(test::equivalent(x.key_eq(), eq1)); + BOOST_TEST(test::equivalent(x.get_allocator(), al)); + } + + std::cerr<<"Initializer list construct 5\n"; + { + T x(list, 10, hf1, eq1, al1); + BOOST_TEST(x.empty()); + BOOST_TEST(x.bucket_count() >= 10); + BOOST_TEST(test::equivalent(x.hash_function(), hf1)); + BOOST_TEST(test::equivalent(x.key_eq(), eq1)); + BOOST_TEST(test::equivalent(x.get_allocator(), al1)); + } +#endif } template From 2221c8334e876cb2f182f1a2ba6210cb7a1d9fd6 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 20 Oct 2009 23:13:33 +0000 Subject: [PATCH 040/100] Merge a couple of documentation changes. Merged revisions 56988-56989 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r56988 | danieljames | 2009-10-18 21:18:28 +0100 (Sun, 18 Oct 2009) | 1 line Add release notes for unordered. ........ r56989 | danieljames | 2009-10-18 21:18:43 +0100 (Sun, 18 Oct 2009) | 1 line Mention that image attributes are supported. ........ [SVN r57028] --- doc/changes.qbk | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/doc/changes.qbk b/doc/changes.qbk index 418f1d90..6d0f0260 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -88,4 +88,19 @@ First official release. * Better configuration for C++0x features when the headers aren't available. * Create less buckets by default. +[h2 Boost 1.41.0 - Major update] + +* The original version made heavy use of macros to sidestep some of the older + compilers' poor template support. But since I no longer support those + compilers and the macro use was starting to become a maintenance burden it + has been rewritten to use templates instead of macros for the implementation + classes. + +* The container objcet is now smaller thanks to using `boost::compressed_pair` + for EBO and a slightly different function buffer - now using a bool instead + of a member pointer. + +* Buckets are allocated lazily which means that constructing an empty container + will not allocate any memory. + [endsect] From a3e57838ed7b8b8477aee063472c71fa7d1c636d Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 27 Oct 2009 19:39:33 +0000 Subject: [PATCH 041/100] Merged revisions 57126,57139,57150-57153 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r57126 | danieljames | 2009-10-24 12:56:30 +0100 (Sat, 24 Oct 2009) | 1 line Update the intel compile flags. ........ r57139 | danieljames | 2009-10-24 18:53:03 +0100 (Sat, 24 Oct 2009) | 1 line Fix unordered for intel strict. ........ r57150 | danieljames | 2009-10-25 10:54:28 +0000 (Sun, 25 Oct 2009) | 1 line Fix the intel strict flag. ........ r57151 | danieljames | 2009-10-25 10:54:53 +0000 (Sun, 25 Oct 2009) | 1 line Remove insert empty initializer lists, as there's a bug in gcc. ........ r57152 | danieljames | 2009-10-25 10:55:08 +0000 (Sun, 25 Oct 2009) | 1 line Slightly rearrange the unordered container headers so that prev_prime is defined before it's used. ........ r57153 | danieljames | 2009-10-25 10:55:27 +0000 (Sun, 25 Oct 2009) | 1 line Remove 'grouped' from hash_table as it isn't used and is a bit confusing. ........ [SVN r57179] --- include/boost/unordered/detail/buckets.hpp | 7 +++++++ include/boost/unordered/detail/equivalent.hpp | 10 +++++----- include/boost/unordered/detail/fwd.hpp | 15 +++++---------- include/boost/unordered/detail/table.hpp | 1 - include/boost/unordered/detail/unique.hpp | 17 ++++++++--------- test/exception/Jamfile.v2 | 6 +----- test/unordered/Jamfile.v2 | 7 ++++--- test/unordered/insert_tests.cpp | 6 +++--- 8 files changed, 33 insertions(+), 36 deletions(-) diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index 0f513e44..c4b8a898 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -10,12 +10,19 @@ #include #include #include +#include namespace boost { namespace unordered_detail { //////////////////////////////////////////////////////////////////////////// // Buckets + template + inline std::size_t hash_buckets::max_bucket_count() const { + // -1 to account for the sentinel. + return prev_prime(this->bucket_alloc().max_size() - 1); + } + template inline BOOST_DEDUCED_TYPENAME hash_buckets::bucket_ptr hash_buckets::get_bucket(std::size_t num) const diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 7e52a609..970c18bc 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -28,7 +28,7 @@ namespace boost { namespace unordered_detail { node_ptr it1 = i->next_; while(BOOST_UNORDERED_BORLAND_BOOL(it1)) { - node_ptr it2 = other.find_iterator(get_key_from_ptr(it1)); + node_ptr it2 = other.find_iterator(this->get_key_from_ptr(it1)); if(!BOOST_UNORDERED_BORLAND_BOOL(it2)) return false; node_ptr end1 = node::next_group(it1); @@ -77,7 +77,7 @@ namespace boost { namespace unordered_detail { hash_equivalent_table::iterator_base hash_equivalent_table::emplace_impl(node_constructor& a) { - key_type const& k = get_key(a.value()); + key_type const& k = this->get_key(a.value()); std::size_t hash_value = this->hash_function()(k); if(!this->size_) { @@ -85,7 +85,7 @@ namespace boost { namespace unordered_detail { } else { bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); - node_ptr position = find_iterator(bucket, k); + node_ptr position = this->find_iterator(bucket, k); // reserve has basic exception safety if the hash function // throws, strong otherwise. @@ -100,9 +100,9 @@ namespace boost { namespace unordered_detail { inline void hash_equivalent_table ::emplace_impl_no_rehash(node_constructor& a) { - key_type const& k = get_key(a.value()); + key_type const& k = this->get_key(a.value()); bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); - add_node(a, bucket, find_iterator(bucket, k)); + add_node(a, bucket, this->find_iterator(bucket, k)); } #if defined(BOOST_UNORDERED_STD_FORWARD) diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index 3a5e3f73..5696cbca 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -298,10 +298,7 @@ namespace boost { namespace unordered_detail { return allocators_.first(); } node_allocator& node_alloc() { return allocators_.second(); } - std::size_t max_bucket_count() const { - // -1 to account for the sentinel. - return prev_prime(this->bucket_alloc().max_size() - 1); - } + std::size_t max_bucket_count() const; // Constructors @@ -443,7 +440,6 @@ namespace boost { namespace unordered_detail { typedef H hasher; typedef P key_equal; typedef A value_allocator; - typedef G grouped; typedef K key_extractor; typedef hash_buffered_functions base; typedef hash_buckets buckets; @@ -575,7 +571,7 @@ namespace boost { namespace unordered_detail { template class hash_unique_table : - public hash_table + public hash_table { public: @@ -669,7 +665,7 @@ namespace boost { namespace unordered_detail { template class hash_equivalent_table : - public hash_table + public hash_table { public: @@ -678,9 +674,8 @@ namespace boost { namespace unordered_detail { typedef A value_allocator; typedef K key_extractor; - typedef hash_table table; - typedef hash_node_constructor - node_constructor; + typedef hash_table table; + typedef hash_node_constructor node_constructor; typedef hash_iterator_base iterator_base; typedef BOOST_DEDUCED_TYPENAME table::key_type key_type; diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index bba3a07f..66c9d744 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -14,7 +14,6 @@ #include #include -#include namespace boost { namespace unordered_detail { diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index 552a1d51..b696e1a0 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -28,7 +28,7 @@ namespace boost { namespace unordered_detail { node_ptr it1 = i->next_; while(BOOST_UNORDERED_BORLAND_BOOL(it1)) { - node_ptr it2 = other.find_iterator(get_key_from_ptr(it1)); + node_ptr it2 = other.find_iterator(this->get_key_from_ptr(it1)); if(!BOOST_UNORDERED_BORLAND_BOOL(it2)) return false; if(!extractor::compare_mapped( node::get_value(it1), node::get_value(it2))) @@ -76,7 +76,7 @@ namespace boost { namespace unordered_detail { return *this->emplace_empty_impl_with_node(a, 1); } - node_ptr pos = find_iterator(bucket, k); + node_ptr pos = this->find_iterator(bucket, k); if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { return node::get_value(pos); @@ -102,14 +102,13 @@ namespace boost { namespace unordered_detail { template inline BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return - hash_unique_table - ::emplace_impl_with_node(node_constructor& a) + hash_unique_table::emplace_impl_with_node(node_constructor& a) { // No side effects in this initial code - key_type const& k = get_key(a.value()); + key_type const& k = this->get_key(a.value()); std::size_t hash_value = this->hash_function()(k); bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); - node_ptr pos = find_iterator(bucket, k); + node_ptr pos = this->find_iterator(bucket, k); if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { // Found an existing key, return it (no throw). @@ -139,7 +138,7 @@ namespace boost { namespace unordered_detail { // No side effects in this initial code std::size_t hash_value = this->hash_function()(k); bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); - node_ptr pos = find_iterator(bucket, k); + node_ptr pos = this->find_iterator(bucket, k); if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { // Found an existing key, return it (no throw). @@ -203,7 +202,7 @@ namespace boost { namespace unordered_detail { std::size_t hash_value = this->hash_function()(k); \ bucket_ptr bucket \ = this->bucket_ptr_from_hash(hash_value); \ - node_ptr pos = find_iterator(bucket, k); \ + node_ptr pos = this->find_iterator(bucket, k); \ \ if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { \ return emplace_return(iterator_base(bucket, pos), false); \ @@ -330,7 +329,7 @@ namespace boost { namespace unordered_detail { key_type const& k = extractor::extract(*i); std::size_t hash_value = this->hash_function()(k); bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); - node_ptr pos = find_iterator(bucket, k); + node_ptr pos = this->find_iterator(bucket, k); if (!BOOST_UNORDERED_BORLAND_BOOL(pos)) { // Doesn't already exist, add to bucket. diff --git a/test/exception/Jamfile.v2 b/test/exception/Jamfile.v2 index 92e25055..a8508588 100644 --- a/test/exception/Jamfile.v2 +++ b/test/exception/Jamfile.v2 @@ -8,11 +8,7 @@ import testing ; #alias framework : /boost/test//boost_unit_test_framework ; alias framework : ; -project unordered-test/exception-tests - : requirements - intel-linux:"-strict_ansi -cxxlib-icc" - gcc:"-Wsign-promo -Wunused-parameter" - ; +project unordered-test/exception-tests ; test-suite unordered-exception : diff --git a/test/unordered/Jamfile.v2 b/test/unordered/Jamfile.v2 index ee1505f7..882ec132 100644 --- a/test/unordered/Jamfile.v2 +++ b/test/unordered/Jamfile.v2 @@ -7,10 +7,11 @@ import testing ; project unordered-test/unordered : requirements - intel-linux:"-strict_ansi -cxxlib-icc" - gcc:"-Wsign-promo -Wunused-parameter" - #msvc:/W4 all + intel:on + intel:-strict-ansi + msvc:/W4 + gcc:"-Wsign-promo -Wunused-parameter -pedantic" ; test-suite unordered diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index a277cbb7..b116acc0 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -407,7 +407,7 @@ UNORDERED_AUTO_TEST(insert_initializer_list_set) UNORDERED_AUTO_TEST(insert_initializer_list_multiset) { boost::unordered_multiset multiset; - multiset.insert({}); + //multiset.insert({}); BOOST_TEST(multiset.empty()); multiset.insert({"a"}); BOOST_TEST_EQ(multiset.size(), 1u); @@ -423,7 +423,7 @@ UNORDERED_AUTO_TEST(insert_initializer_list_multiset) UNORDERED_AUTO_TEST(insert_initializer_list_map) { boost::unordered_map map; - map.insert({}); + //map.insert({}); BOOST_TEST(map.empty()); map.insert({{"a", "b"},{"a", "b"},{"d", ""}}); BOOST_TEST_EQ(map.size(), 2u); @@ -432,7 +432,7 @@ UNORDERED_AUTO_TEST(insert_initializer_list_map) UNORDERED_AUTO_TEST(insert_initializer_list_multimap) { boost::unordered_multimap multimap; - multimap.insert({}); + //multimap.insert({}); BOOST_TEST(multimap.empty()); multimap.insert({{"a", "b"},{"a", "b"},{"d", ""}}); BOOST_TEST_EQ(multimap.size(), 3u); From f709c16d708a9228f7b25988a7a6795d5b45bf2b Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 20 Nov 2009 09:16:36 +0000 Subject: [PATCH 042/100] Merge [56844]: Correct macro checks for initializer lists. [SVN r57801] --- test/unordered/assign_tests.cpp | 3 ++- test/unordered/constructor_tests.cpp | 3 ++- test/unordered/insert_tests.cpp | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/test/unordered/assign_tests.cpp b/test/unordered/assign_tests.cpp index 56df1b20..2bfb39fe 100644 --- a/test/unordered/assign_tests.cpp +++ b/test/unordered/assign_tests.cpp @@ -118,7 +118,8 @@ UNORDERED_AUTO_TEST(assign_default_initializer_list) { #endif -#if !defined(BOOST_NO_INITIALIZER_LISTS) +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) && \ + !defined(BOOST_NO_INITIALIZER_LISTS) UNORDERED_AUTO_TEST(assign_initializer_list) { diff --git a/test/unordered/constructor_tests.cpp b/test/unordered/constructor_tests.cpp index 8ddd005c..5a719e2a 100644 --- a/test/unordered/constructor_tests.cpp +++ b/test/unordered/constructor_tests.cpp @@ -365,7 +365,8 @@ UNORDERED_AUTO_TEST(test_default_initializer_list) { #endif -#if !defined(BOOST_NO_INITIALIZER_LISTS) +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) && \ + !defined(BOOST_NO_INITIALIZER_LISTS) UNORDERED_AUTO_TEST(test_initializer_list) { std::cerr<<"Initializer List Tests\n"; diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index b116acc0..69d1c67c 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -393,7 +393,8 @@ UNORDERED_TEST(map_insert_range_test2, ((default_generator)(generate_collisions)) ) -#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) && \ + !defined(BOOST_NO_INITIALIZER_LISTS) UNORDERED_AUTO_TEST(insert_initializer_list_set) { From 144d8963a37600ff7db7e94b3a0520aa8c3d4f20 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 28 Nov 2009 11:40:08 +0000 Subject: [PATCH 043/100] Merge unordered. Warning fixes, support for incomplete types and tweak some test. [SVN r57998] --- include/boost/unordered/detail/equivalent.hpp | 46 ++-- .../boost/unordered/detail/extract_key.hpp | 214 +++++++++--------- include/boost/unordered/detail/fwd.hpp | 209 ++++++++++------- include/boost/unordered/detail/table.hpp | 182 +++++++-------- include/boost/unordered/detail/unique.hpp | 92 ++++---- include/boost/unordered/unordered_map.hpp | 20 +- include/boost/unordered/unordered_set.hpp | 21 +- test/exception/Jamfile.v2 | 13 +- test/exception/assign_exception_tests.cpp | 12 +- .../exception/constructor_exception_tests.cpp | 2 + test/exception/copy_exception_tests.cpp | 2 + test/exception/erase_exception_tests.cpp | 4 +- test/exception/insert_exception_tests.cpp | 8 +- test/exception/rehash_exception_tests.cpp | 6 +- test/exception/swap_exception_tests.cpp | 10 +- test/helpers/allocator.hpp | 4 +- test/helpers/exception_test.hpp | 5 +- test/helpers/input_iterator.hpp | 2 + test/helpers/invariants.hpp | 1 + test/helpers/list.hpp | 19 +- test/helpers/prefix.hpp | 10 + test/helpers/strong.hpp | 2 +- test/helpers/tracker.hpp | 4 +- test/unordered/Jamfile.v2 | 11 +- test/unordered/assign_tests.cpp | 2 + test/unordered/at_tests.cpp | 2 + test/unordered/bucket_tests.cpp | 7 + test/unordered/compile_map.cpp | 2 + test/unordered/compile_set.cpp | 2 + test/unordered/compile_tests.hpp | 2 + test/unordered/constructor_tests.cpp | 2 + test/unordered/copy_tests.cpp | 2 + test/unordered/equality_tests.cpp | 54 ++--- test/unordered/equivalent_keys_tests.cpp | 2 + test/unordered/erase_equiv_tests.cpp | 7 + test/unordered/erase_tests.cpp | 4 +- test/unordered/find_tests.cpp | 2 + test/unordered/fwd_map_test.cpp | 2 + test/unordered/fwd_set_test.cpp | 2 + test/unordered/incomplete_test.cpp | 42 ++++ test/unordered/insert_stable_tests.cpp | 2 + test/unordered/insert_tests.cpp | 2 + test/unordered/link_test_1.cpp | 2 + test/unordered/link_test_2.cpp | 2 + test/unordered/load_factor_tests.cpp | 2 + test/unordered/move_tests.cpp | 8 + test/unordered/rehash_tests.cpp | 2 + test/unordered/simple_tests.cpp | 2 + test/unordered/swap_tests.cpp | 2 + test/unordered/unnecessary_copy_tests.cpp | 2 + 50 files changed, 651 insertions(+), 410 deletions(-) create mode 100644 test/helpers/prefix.hpp create mode 100644 test/unordered/incomplete_test.cpp diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 970c18bc..639dd5ef 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -15,9 +15,9 @@ namespace boost { namespace unordered_detail { //////////////////////////////////////////////////////////////////////////// // Equality - template - bool hash_equivalent_table - ::equals(hash_equivalent_table const& other) const + template + bool hash_equivalent_table + ::equals(hash_equivalent_table const& other) const { if(this->size_ != other.size_) return false; if(!this->size_) return true; @@ -51,9 +51,9 @@ namespace boost { namespace unordered_detail { //////////////////////////////////////////////////////////////////////////// // A convenience method for adding nodes. - template - inline BOOST_DEDUCED_TYPENAME hash_equivalent_table::node_ptr - hash_equivalent_table + template + inline BOOST_DEDUCED_TYPENAME hash_equivalent_table::node_ptr + hash_equivalent_table ::add_node(node_constructor& a, bucket_ptr bucket, node_ptr pos) { node_ptr n = a.release(); @@ -72,10 +72,10 @@ namespace boost { namespace unordered_detail { //////////////////////////////////////////////////////////////////////////// // Insert methods - template + template inline BOOST_DEDUCED_TYPENAME - hash_equivalent_table::iterator_base - hash_equivalent_table::emplace_impl(node_constructor& a) + hash_equivalent_table::iterator_base + hash_equivalent_table::emplace_impl(node_constructor& a) { key_type const& k = this->get_key(a.value()); std::size_t hash_value = this->hash_function()(k); @@ -96,8 +96,8 @@ namespace boost { namespace unordered_detail { } } - template - inline void hash_equivalent_table + template + inline void hash_equivalent_table ::emplace_impl_no_rehash(node_constructor& a) { key_type const& k = this->get_key(a.value()); @@ -112,10 +112,10 @@ namespace boost { namespace unordered_detail { // if hash function throws, basic exception safety // strong otherwise - template + template template - BOOST_DEDUCED_TYPENAME hash_equivalent_table::iterator_base - hash_equivalent_table + BOOST_DEDUCED_TYPENAME hash_equivalent_table::iterator_base + hash_equivalent_table ::emplace(Args&&... args) { // Create the node before rehashing in case it throws an @@ -129,10 +129,10 @@ namespace boost { namespace unordered_detail { #else #define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \ - template \ + template \ template \ - BOOST_DEDUCED_TYPENAME hash_equivalent_table::iterator_base \ - hash_equivalent_table \ + BOOST_DEDUCED_TYPENAME hash_equivalent_table::iterator_base \ + hash_equivalent_table \ ::emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ { \ node_constructor a(*this); \ @@ -151,9 +151,9 @@ namespace boost { namespace unordered_detail { // if hash function throws, or inserting > 1 element, basic exception safety // strong otherwise - template + template template - inline void hash_equivalent_table + inline void hash_equivalent_table ::insert_for_range(I i, I j, forward_traversal_tag) { if(i == j) return; @@ -182,9 +182,9 @@ namespace boost { namespace unordered_detail { // if hash function throws, or inserting > 1 element, basic exception safety // strong otherwise - template + template template - inline void hash_equivalent_table + inline void hash_equivalent_table ::insert_for_range(I i, I j, boost::incrementable_traversal_tag) { node_constructor a(*this); @@ -196,9 +196,9 @@ namespace boost { namespace unordered_detail { // if hash function throws, or inserting > 1 element, basic exception safety // strong otherwise - template + template template - void hash_equivalent_table::insert_range(I i, I j) + void hash_equivalent_table::insert_range(I i, I j) { BOOST_DEDUCED_TYPENAME boost::iterator_traversal::type iterator_traversal_tag; diff --git a/include/boost/unordered/detail/extract_key.hpp b/include/boost/unordered/detail/extract_key.hpp index d415d935..bedb175f 100644 --- a/include/boost/unordered/detail/extract_key.hpp +++ b/include/boost/unordered/detail/extract_key.hpp @@ -28,128 +28,120 @@ namespace unordered_detail { template no_key(T const&) {} }; + template struct set_extractor { - template - struct apply + typedef ValueType value_type; + typedef ValueType key_type; + + static key_type const& extract(key_type const& v) { - typedef ValueType value_type; - typedef ValueType key_type; + return v; + } - static key_type const& extract(key_type const& v) - { - return v; - } - - static no_key extract() - { - return no_key(); - } - - #if defined(BOOST_UNORDERED_STD_FORWARD) - template - static no_key extract(Args const&...) - { - return no_key(); - } - - #else - template - static no_key extract(Arg const&) - { - return no_key(); - } - - template - static no_key extract(Arg const&, Arg const&) - { - return no_key(); - } - #endif - - static bool compare_mapped(value_type const&, value_type const&) - { - return true; - } - }; - }; - - struct map_extractor - { - template - struct apply + static no_key extract() { - typedef ValueType value_type; - typedef BOOST_DEDUCED_TYPENAME - remove_const::type - key_type; - - static key_type const& extract(value_type const& v) - { - return v.first; - } - - static key_type const& extract(key_type const& v) - { - return v; - } - - template - static key_type const& extract(std::pair const& v) - { - return v.first; - } - - template - static key_type const& extract( - std::pair const& v) - { - return v.first; - } - + return no_key(); + } + #if defined(BOOST_UNORDERED_STD_FORWARD) - template - static key_type const& extract(key_type const& k, - Arg1 const&, Args const&...) - { - return k; - } + template + static no_key extract(Args const&...) + { + return no_key(); + } - template - static no_key extract(Args const&...) - { - return no_key(); - } #else - template - static key_type const& extract(key_type const& k, Arg1 const&) - { - return k; - } + template + static no_key extract(Arg const&) + { + return no_key(); + } - static no_key extract() - { - return no_key(); - } - - template - static no_key extract(Arg const&) - { - return no_key(); - } - - template - static no_key extract(Arg const&, Arg1 const&) - { - return no_key(); - } + template + static no_key extract(Arg const&, Arg const&) + { + return no_key(); + } #endif - static bool compare_mapped(value_type const& x, value_type const& y) - { - return x.second == y.second; - } - }; + static bool compare_mapped(value_type const&, value_type const&) + { + return true; + } + }; + + template + struct map_extractor + { + typedef ValueType value_type; + typedef BOOST_DEDUCED_TYPENAME boost::remove_const::type key_type; + + static key_type const& extract(value_type const& v) + { + return v.first; + } + + static key_type const& extract(key_type const& v) + { + return v; + } + + template + static key_type const& extract(std::pair const& v) + { + return v.first; + } + + template + static key_type const& extract( + std::pair const& v) + { + return v.first; + } + +#if defined(BOOST_UNORDERED_STD_FORWARD) + template + static key_type const& extract(key_type const& k, + Arg1 const&, Args const&...) + { + return k; + } + + template + static no_key extract(Args const&...) + { + return no_key(); + } +#else + template + static key_type const& extract(key_type const& k, Arg1 const&) + { + return k; + } + + static no_key extract() + { + return no_key(); + } + + template + static no_key extract(Arg const&) + { + return no_key(); + } + + template + static no_key extract(Arg const&, Arg1 const&) + { + return no_key(); + } +#endif + + static bool compare_mapped(value_type const& x, value_type const& y) + { + return x.second == y.second; + } }; }} diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index 5696cbca..ff3d63e9 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -12,7 +12,6 @@ #define BOOST_UNORDERED_DETAIL_FWD_HPP_INCLUDED #include -#include #include #include #include @@ -30,7 +29,7 @@ // P = Predicate // A = Value Allocator // G = Grouped/Ungrouped -// K = Key Extractor +// E = Key Extractor #if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) # if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION) @@ -67,7 +66,9 @@ namespace boost { namespace unordered_detail { template class hash_node_constructor; + template struct set_extractor; + template struct map_extractor; struct no_key; @@ -75,9 +76,7 @@ namespace boost { namespace unordered_detail { #if defined(BOOST_MSVC) #pragma warning(push) -#if BOOST_MSVC >= 1400 #pragma warning(disable:4100) // unreferenced formal parameter -#endif #endif template @@ -106,13 +105,6 @@ namespace boost { namespace unordered_detail { node_ptr next_; hash_bucket() : next_() {} - - // Only copy construct when allocating. - hash_bucket(hash_bucket const& x) - : next_() - { - BOOST_ASSERT(!x.next_); - } }; template @@ -187,6 +179,8 @@ namespace boost { namespace unordered_detail { value_type& value() { return *(ValueType*) this; } + private: + value_base& operator=(value_base const&); }; // Node @@ -203,6 +197,8 @@ namespace boost { namespace unordered_detail { static value_type& get_value(node_ptr p) { return static_cast(*p).value(); } + private: + hash_node& operator=(hash_node const&); }; // Iterator Base @@ -214,9 +210,9 @@ namespace boost { namespace unordered_detail { typedef A value_allocator; typedef hash_bucket bucket; typedef hash_node node; - typedef BOOST_DEDUCED_TYPENAME node::value_type value_type; - typedef BOOST_DEDUCED_TYPENAME node::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME node::node_ptr node_ptr; + typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; + typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr; + typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr; bucket_ptr bucket_; node_ptr node_; @@ -274,9 +270,9 @@ namespace boost { namespace unordered_detail { typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; typedef BOOST_DEDUCED_TYPENAME iterator_base::node node; - typedef BOOST_DEDUCED_TYPENAME node::bucket_allocator bucket_allocator; - typedef BOOST_DEDUCED_TYPENAME node::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME node::node_ptr node_ptr; + typedef BOOST_DEDUCED_TYPENAME bucket::bucket_allocator bucket_allocator; + typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr; + typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr; typedef BOOST_DEDUCED_TYPENAME rebind_wrap::type node_allocator; @@ -430,33 +426,28 @@ namespace boost { namespace unordered_detail { } }; - template - class hash_table : - public hash_buckets, - public hash_buffered_functions + template + class hash_table : public T::buckets, public T::buffered_functions { hash_table(hash_table const&); public: - typedef H hasher; - typedef P key_equal; - typedef A value_allocator; - typedef K key_extractor; - typedef hash_buffered_functions base; - typedef hash_buckets buckets; - - typedef BOOST_DEDUCED_TYPENAME value_allocator::value_type value_type; - typedef BOOST_DEDUCED_TYPENAME key_extractor::BOOST_NESTED_TEMPLATE - apply extractor; - typedef BOOST_DEDUCED_TYPENAME extractor::key_type key_type; + typedef BOOST_DEDUCED_TYPENAME T::hasher hasher; + typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal; + typedef BOOST_DEDUCED_TYPENAME T::value_allocator value_allocator; + typedef BOOST_DEDUCED_TYPENAME T::key_type key_type; + typedef BOOST_DEDUCED_TYPENAME T::value_type value_type; + typedef BOOST_DEDUCED_TYPENAME T::buffered_functions base; + typedef BOOST_DEDUCED_TYPENAME T::buckets buckets; + typedef BOOST_DEDUCED_TYPENAME T::extractor extractor; + typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor; - typedef BOOST_DEDUCED_TYPENAME buckets::node node; - typedef BOOST_DEDUCED_TYPENAME buckets::bucket bucket; - typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr; - typedef BOOST_DEDUCED_TYPENAME buckets::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME buckets::iterator_base iterator_base; - typedef BOOST_DEDUCED_TYPENAME buckets::node_allocator node_allocator; - typedef hash_node_constructor node_constructor; - typedef std::pair iterator_pair; + typedef BOOST_DEDUCED_TYPENAME T::node node; + typedef BOOST_DEDUCED_TYPENAME T::bucket bucket; + typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr; + typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr; + typedef BOOST_DEDUCED_TYPENAME T::iterator_base iterator_base; + typedef BOOST_DEDUCED_TYPENAME T::node_allocator node_allocator; + typedef BOOST_DEDUCED_TYPENAME T::iterator_pair iterator_pair; // Members @@ -569,27 +560,23 @@ namespace boost { namespace unordered_detail { node_constructor&, std::size_t); }; - template - class hash_unique_table : - public hash_table - + template + class hash_unique_table : public T::table { public: - typedef H hasher; - typedef P key_equal; - typedef A value_allocator; - typedef K key_extractor; + typedef BOOST_DEDUCED_TYPENAME T::hasher hasher; + typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal; + typedef BOOST_DEDUCED_TYPENAME T::value_allocator value_allocator; + typedef BOOST_DEDUCED_TYPENAME T::key_type key_type; + typedef BOOST_DEDUCED_TYPENAME T::value_type value_type; + typedef BOOST_DEDUCED_TYPENAME T::table table; + typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor; - typedef hash_table table; - typedef hash_node_constructor node_constructor; - - typedef BOOST_DEDUCED_TYPENAME table::key_type key_type; - typedef BOOST_DEDUCED_TYPENAME table::value_type value_type; - typedef BOOST_DEDUCED_TYPENAME table::node node; - typedef BOOST_DEDUCED_TYPENAME table::node_ptr node_ptr; - typedef BOOST_DEDUCED_TYPENAME table::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME table::iterator_base iterator_base; - typedef BOOST_DEDUCED_TYPENAME table::extractor extractor; + typedef BOOST_DEDUCED_TYPENAME T::node node; + typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr; + typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr; + typedef BOOST_DEDUCED_TYPENAME T::iterator_base iterator_base; + typedef BOOST_DEDUCED_TYPENAME T::extractor extractor; typedef std::pair emplace_return; @@ -663,27 +650,23 @@ namespace boost { namespace unordered_detail { void insert_range_impl(no_key, InputIt i, InputIt j); }; - template - class hash_equivalent_table : - public hash_table - + template + class hash_equivalent_table : public T::table { public: - typedef H hasher; - typedef P key_equal; - typedef A value_allocator; - typedef K key_extractor; + typedef BOOST_DEDUCED_TYPENAME T::hasher hasher; + typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal; + typedef BOOST_DEDUCED_TYPENAME T::value_allocator value_allocator; + typedef BOOST_DEDUCED_TYPENAME T::key_type key_type; + typedef BOOST_DEDUCED_TYPENAME T::value_type value_type; + typedef BOOST_DEDUCED_TYPENAME T::table table; + typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor; - typedef hash_table table; - typedef hash_node_constructor node_constructor; - typedef hash_iterator_base iterator_base; - - typedef BOOST_DEDUCED_TYPENAME table::key_type key_type; - typedef BOOST_DEDUCED_TYPENAME table::value_type value_type; - typedef BOOST_DEDUCED_TYPENAME table::node node; - typedef BOOST_DEDUCED_TYPENAME table::node_ptr node_ptr; - typedef BOOST_DEDUCED_TYPENAME table::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME table::extractor extractor; + typedef BOOST_DEDUCED_TYPENAME T::node node; + typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr; + typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr; + typedef BOOST_DEDUCED_TYPENAME T::iterator_base iterator_base; + typedef BOOST_DEDUCED_TYPENAME T::extractor extractor; // Constructors @@ -969,6 +952,80 @@ namespace boost { namespace unordered_detail { return base_ != x.base_; } }; + + // types + + template + struct types + { + public: + typedef K key_type; + typedef V value_type; + typedef H hasher; + typedef P key_equal; + typedef A value_allocator; + typedef E extractor; + typedef G group_type; + + typedef hash_node_constructor node_constructor; + typedef hash_buckets buckets; + typedef hash_buffered_functions buffered_functions; + + typedef BOOST_DEDUCED_TYPENAME buckets::node node; + typedef BOOST_DEDUCED_TYPENAME buckets::bucket bucket; + typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr; + typedef BOOST_DEDUCED_TYPENAME buckets::bucket_ptr bucket_ptr; + typedef BOOST_DEDUCED_TYPENAME buckets::iterator_base iterator_base; + typedef BOOST_DEDUCED_TYPENAME buckets::node_allocator node_allocator; + + typedef std::pair iterator_pair; + }; + + template + struct set : public types< + BOOST_DEDUCED_TYPENAME A::value_type, + BOOST_DEDUCED_TYPENAME A::value_type, + H, P, A, + set_extractor, + ungrouped> + { + typedef hash_unique_table > impl; + typedef hash_table > table; + }; + + template + struct multiset : public types< + BOOST_DEDUCED_TYPENAME A::value_type, + BOOST_DEDUCED_TYPENAME A::value_type, + H, P, A, + set_extractor, + grouped> + { + typedef hash_equivalent_table > impl; + typedef hash_table > table; + }; + + template + struct map : public types< + K, BOOST_DEDUCED_TYPENAME A::value_type, + H, P, A, + map_extractor, + ungrouped> + { + typedef hash_unique_table > impl; + typedef hash_table > table; + }; + + template + struct multimap : public types< + K, BOOST_DEDUCED_TYPENAME A::value_type, + H, P, A, + map_extractor, + grouped> + { + typedef hash_equivalent_table > impl; + typedef hash_table > table; + }; }} #endif diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 66c9d744..2f4e5ebd 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -21,17 +21,17 @@ namespace boost { namespace unordered_detail { // Helper methods // strong exception safety, no side effects - template - inline bool hash_table::equal( + template + inline bool hash_table::equal( key_type const& k, value_type const& v) const { return this->key_eq()(k, get_key(v)); } // strong exception safety, no side effects - template - inline BOOST_DEDUCED_TYPENAME hash_table::node_ptr - hash_table::find_iterator( + template + inline BOOST_DEDUCED_TYPENAME T::node_ptr + hash_table::find_iterator( bucket_ptr bucket, key_type const& k) const { node_ptr it = bucket->next_; @@ -46,17 +46,17 @@ namespace boost { namespace unordered_detail { // strong exception safety, no side effects // pre: this->buckets_ - template - inline BOOST_DEDUCED_TYPENAME hash_table::node_ptr - hash_table::find_iterator(key_type const& k) const + template + inline BOOST_DEDUCED_TYPENAME T::node_ptr + hash_table::find_iterator(key_type const& k) const { return find_iterator(this->get_bucket(this->bucket_index(k)), k); } // strong exception safety, no side effects - template - inline BOOST_DEDUCED_TYPENAME hash_table::node_ptr* - hash_table::find_for_erase( + template + inline BOOST_DEDUCED_TYPENAME T::node_ptr* + hash_table::find_for_erase( bucket_ptr bucket, key_type const& k) const { node_ptr* it = &bucket->next_; @@ -73,8 +73,8 @@ namespace boost { namespace unordered_detail { // Load methods // no throw - template - std::size_t hash_table::max_size() const + template + std::size_t hash_table::max_size() const { using namespace std; @@ -84,8 +84,8 @@ namespace boost { namespace unordered_detail { } // strong safety - template - inline std::size_t hash_table::bucket_index( + template + inline std::size_t hash_table::bucket_index( key_type const& k) const { // hash_function can throw: @@ -94,8 +94,8 @@ namespace boost { namespace unordered_detail { // no throw - template - inline std::size_t hash_table::calculate_max_load() + template + inline std::size_t hash_table::calculate_max_load() { using namespace std; @@ -104,8 +104,8 @@ namespace boost { namespace unordered_detail { return double_to_size_t(ceil((double) mlf_ * this->bucket_count_)); } - template - void hash_table::max_load_factor(float z) + template + void hash_table::max_load_factor(float z) { BOOST_ASSERT(z > 0); mlf_ = (std::max)(z, minimum_max_load_factor); @@ -113,8 +113,8 @@ namespace boost { namespace unordered_detail { } // no throw - template - inline std::size_t hash_table::min_buckets_for_size( + template + inline std::size_t hash_table::min_buckets_for_size( std::size_t size) const { BOOST_ASSERT(this->mlf_ != 0); @@ -135,8 +135,8 @@ namespace boost { namespace unordered_detail { // init_buckets - template - inline void hash_table::init_buckets() + template + inline void hash_table::init_buckets() { if (this->size_) { this->cached_begin_bucket_ = this->buckets_; @@ -153,8 +153,8 @@ namespace boost { namespace unordered_detail { // // no throw - template - inline void hash_table::recompute_begin_bucket(bucket_ptr b) + template + inline void hash_table::recompute_begin_bucket(bucket_ptr b) { BOOST_ASSERT(!(b < this->cached_begin_bucket_)); @@ -174,8 +174,8 @@ namespace boost { namespace unordered_detail { // // no throw - template - inline void hash_table::recompute_begin_bucket( + template + inline void hash_table::recompute_begin_bucket( bucket_ptr b1, bucket_ptr b2) { BOOST_ASSERT(!(b1 < this->cached_begin_bucket_) && !(b2 < b1)); @@ -186,8 +186,8 @@ namespace boost { namespace unordered_detail { } // no throw - template - inline float hash_table::load_factor() const + template + inline float hash_table::load_factor() const { BOOST_ASSERT(this->bucket_count_ != 0); return static_cast(this->size_) @@ -197,8 +197,8 @@ namespace boost { namespace unordered_detail { //////////////////////////////////////////////////////////////////////////// // Constructors - template - hash_table::hash_table(std::size_t num_buckets, + template + hash_table::hash_table(std::size_t num_buckets, hasher const& hf, key_equal const& eq, node_allocator const& a) : buckets(a, next_prime(num_buckets)), base(hf, eq), @@ -211,8 +211,8 @@ namespace boost { namespace unordered_detail { // Copy Construct with allocator - template - hash_table::hash_table(hash_table const& x, + template + hash_table::hash_table(hash_table const& x, node_allocator const& a) : buckets(a, x.min_buckets_for_size(x.size_)), base(x), @@ -229,8 +229,8 @@ namespace boost { namespace unordered_detail { // Move Construct - template - hash_table::hash_table(hash_table& x, move_tag) + template + hash_table::hash_table(hash_table& x, move_tag) : buckets(x.node_alloc(), x.bucket_count_), base(x), size_(0), @@ -241,8 +241,8 @@ namespace boost { namespace unordered_detail { this->partial_swap(x); } - template - hash_table::hash_table(hash_table& x, + template + hash_table::hash_table(hash_table& x, node_allocator const& a, move_tag) : buckets(a, x.bucket_count_), base(x), @@ -261,8 +261,8 @@ namespace boost { namespace unordered_detail { } } - template - hash_table& hash_table::operator=( + template + hash_table& hash_table::operator=( hash_table const& x) { hash_table tmp(x, this->node_alloc()); @@ -280,8 +280,8 @@ namespace boost { namespace unordered_detail { // Can throw if hash or predicate object's copy constructor throws // or if allocators are unequal. - template - inline void hash_table::partial_swap(hash_table& x) + template + inline void hash_table::partial_swap(hash_table& x) { this->buckets::swap(x); // No throw std::swap(this->size_, x.size_); @@ -290,15 +290,15 @@ namespace boost { namespace unordered_detail { std::swap(this->max_load_, x.max_load_); } - template - inline void hash_table::fast_swap(hash_table& x) + template + inline void hash_table::fast_swap(hash_table& x) { // These can throw, but they only affect the function objects // that aren't in use so it is strongly exception safe, via. // double buffering. { - set_hash_functions op1(*this, x); - set_hash_functions op2(x, *this); + set_hash_functions op1(*this, x); + set_hash_functions op2(x, *this); op1.commit(); op2.commit(); } @@ -309,8 +309,8 @@ namespace boost { namespace unordered_detail { std::swap(this->max_load_, x.max_load_); } - template - inline void hash_table::slow_swap(hash_table& x) + template + inline void hash_table::slow_swap(hash_table& x) { if(this == &x) return; @@ -318,8 +318,8 @@ namespace boost { namespace unordered_detail { // These can throw, but they only affect the function objects // that aren't in use so it is strongly exception safe, via. // double buffering. - set_hash_functions op1(*this, x); - set_hash_functions op2(x, *this); + set_hash_functions op1(*this, x); + set_hash_functions op2(x, *this); // Create new buckets in separate hash_buckets objects // which will clean up if anything throws an exception. @@ -345,8 +345,8 @@ namespace boost { namespace unordered_detail { if(x.buckets_) x.init_buckets(); } - template - void hash_table::swap(hash_table& x) + template + void hash_table::swap(hash_table& x) { if(this->node_alloc() == x.node_alloc()) { if(this != &x) this->fast_swap(x); @@ -364,13 +364,13 @@ namespace boost { namespace unordered_detail { // Can throw if hash or predicate object's copy constructor throws // or if allocators are unequal. - template - void hash_table::move(hash_table& x) + template + void hash_table::move(hash_table& x) { // This can throw, but it only affects the function objects // that aren't in use so it is strongly exception safe, via. // double buffering. - set_hash_functions new_func_this(*this, x); + set_hash_functions new_func_this(*this, x); if(this->node_alloc() == x.node_alloc()) { this->buckets::move(x); // no throw @@ -402,8 +402,8 @@ namespace boost { namespace unordered_detail { // Reserve & Rehash // basic exception safety - template - inline void hash_table::create_for_insert(std::size_t size) + template + inline void hash_table::create_for_insert(std::size_t size) { this->bucket_count_ = (std::max)(this->bucket_count_, this->min_buckets_for_size(size)); @@ -412,8 +412,8 @@ namespace boost { namespace unordered_detail { } // basic exception safety - template - inline bool hash_table::reserve_for_insert(std::size_t size) + template + inline bool hash_table::reserve_for_insert(std::size_t size) { if(size >= max_load_) { std::size_t num_buckets @@ -431,8 +431,8 @@ namespace boost { namespace unordered_detail { // if hash function throws, basic exception safety // strong otherwise. - template - inline void hash_table::rehash(std::size_t min_buckets) + template + inline void hash_table::rehash(std::size_t min_buckets) { using namespace std; @@ -451,8 +451,8 @@ namespace boost { namespace unordered_detail { // if hash function throws, basic exception safety // strong otherwise - template - void hash_table + template + void hash_table ::rehash_impl(std::size_t num_buckets) { hasher const& hf = this->hash_function(); @@ -500,8 +500,8 @@ namespace boost { namespace unordered_detail { // basic excpetion safety. If an exception is thrown this will // leave dst partially filled. - template - void hash_table + template + void hash_table ::copy_buckets_to(buckets& dst) const { BOOST_ASSERT(this->buckets_ && !dst.buckets_); @@ -509,7 +509,7 @@ namespace boost { namespace unordered_detail { hasher const& hf = this->hash_function(); bucket_ptr end = this->get_bucket(this->bucket_count_); - hash_node_constructor a(dst); + node_constructor a(dst); dst.create_buckets(); // no throw: @@ -544,8 +544,8 @@ namespace boost { namespace unordered_detail { // // strong exception safety, no side effects - template - std::size_t hash_table::count(key_type const& k) const + template + std::size_t hash_table::count(key_type const& k) const { if(!this->size_) return 0; node_ptr it = find_iterator(k); // throws, strong @@ -555,9 +555,9 @@ namespace boost { namespace unordered_detail { // find // // strong exception safety, no side effects - template - BOOST_DEDUCED_TYPENAME hash_table::iterator_base - hash_table::find(key_type const& k) const + template + BOOST_DEDUCED_TYPENAME T::iterator_base + hash_table::find(key_type const& k) const { if(!this->size_) return this->end(); @@ -570,9 +570,9 @@ namespace boost { namespace unordered_detail { return this->end(); } - template - BOOST_DEDUCED_TYPENAME A::value_type& - hash_table::at(key_type const& k) const + template + BOOST_DEDUCED_TYPENAME T::value_type& + hash_table::at(key_type const& k) const { if(!this->size_) throw std::out_of_range("Unable to find key in unordered_map."); @@ -589,9 +589,9 @@ namespace boost { namespace unordered_detail { // equal_range // // strong exception safety, no side effects - template - BOOST_DEDUCED_TYPENAME hash_table::iterator_pair - hash_table::equal_range(key_type const& k) const + template + BOOST_DEDUCED_TYPENAME T::iterator_pair + hash_table::equal_range(key_type const& k) const { if(!this->size_) return iterator_pair(this->end(), this->end()); @@ -612,8 +612,8 @@ namespace boost { namespace unordered_detail { //////////////////////////////////////////////////////////////////////////// // Erase methods - template - void hash_table::clear() + template + void hash_table::clear() { if(!this->size_) return; @@ -626,8 +626,8 @@ namespace boost { namespace unordered_detail { this->cached_begin_bucket_ = end; } - template - inline std::size_t hash_table::erase_group( + template + inline std::size_t hash_table::erase_group( node_ptr* it, bucket_ptr bucket) { node_ptr pos = *it; @@ -639,8 +639,8 @@ namespace boost { namespace unordered_detail { return count; } - template - std::size_t hash_table::erase_key(key_type const& k) + template + std::size_t hash_table::erase_key(key_type const& k) { if(!this->size_) return 0; @@ -653,9 +653,9 @@ namespace boost { namespace unordered_detail { } - template - BOOST_DEDUCED_TYPENAME hash_table::iterator_base - hash_table::erase(iterator_base r) + template + BOOST_DEDUCED_TYPENAME T::iterator_base + hash_table::erase(iterator_base r) { BOOST_ASSERT(r.node_); iterator_base next = r; @@ -668,9 +668,9 @@ namespace boost { namespace unordered_detail { return next; } - template - BOOST_DEDUCED_TYPENAME hash_table::iterator_base - hash_table::erase_range( + template + BOOST_DEDUCED_TYPENAME T::iterator_base + hash_table::erase_range( iterator_base r1, iterator_base r2) { if(r1 != r2) @@ -713,9 +713,9 @@ namespace boost { namespace unordered_detail { return r2; } - template - BOOST_DEDUCED_TYPENAME hash_table::iterator_base - hash_table::emplace_empty_impl_with_node( + template + BOOST_DEDUCED_TYPENAME hash_table::iterator_base + hash_table::emplace_empty_impl_with_node( node_constructor& a, std::size_t size) { key_type const& k = get_key(a.value()); diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index b696e1a0..79ba28e6 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -15,9 +15,9 @@ namespace boost { namespace unordered_detail { //////////////////////////////////////////////////////////////////////////// // Equality - template - bool hash_unique_table - ::equals(hash_unique_table const& other) const + template + bool hash_unique_table + ::equals(hash_unique_table const& other) const { if(this->size_ != other.size_) return false; if(!this->size_) return true; @@ -43,9 +43,9 @@ namespace boost { namespace unordered_detail { //////////////////////////////////////////////////////////////////////////// // A convenience method for adding nodes. - template - inline BOOST_DEDUCED_TYPENAME hash_unique_table::node_ptr - hash_unique_table::add_node(node_constructor& a, + template + inline BOOST_DEDUCED_TYPENAME hash_unique_table::node_ptr + hash_unique_table::add_node(node_constructor& a, bucket_ptr bucket) { node_ptr n = a.release(); @@ -61,9 +61,9 @@ namespace boost { namespace unordered_detail { // if hash function throws, basic exception safety // strong otherwise - template - BOOST_DEDUCED_TYPENAME hash_unique_table::value_type& - hash_unique_table::operator[](key_type const& k) + template + BOOST_DEDUCED_TYPENAME hash_unique_table::value_type& + hash_unique_table::operator[](key_type const& k) { typedef BOOST_DEDUCED_TYPENAME value_type::second_type mapped_type; @@ -100,9 +100,9 @@ namespace boost { namespace unordered_detail { } } - template - inline BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return - hash_unique_table::emplace_impl_with_node(node_constructor& a) + template + inline BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return + hash_unique_table::emplace_impl_with_node(node_constructor& a) { // No side effects in this initial code key_type const& k = this->get_key(a.value()); @@ -129,10 +129,10 @@ namespace boost { namespace unordered_detail { #if defined(BOOST_UNORDERED_STD_FORWARD) - template + template template - inline BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return - hash_unique_table::emplace_impl(key_type const& k, + inline BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return + hash_unique_table::emplace_impl(key_type const& k, Args&&... args) { // No side effects in this initial code @@ -166,10 +166,10 @@ namespace boost { namespace unordered_detail { } } - template + template template - inline BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return - hash_unique_table::emplace_impl(no_key, Args&&... args) + inline BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return + hash_unique_table::emplace_impl(no_key, Args&&... args) { // Construct the node regardless - in order to get the key. // It will be discarded if it isn't used @@ -178,10 +178,10 @@ namespace boost { namespace unordered_detail { return emplace_impl_with_node(a); } - template + template template - inline BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return - hash_unique_table::emplace_empty_impl(Args&&... args) + inline BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return + hash_unique_table::emplace_empty_impl(Args&&... args) { node_constructor a(*this); a.construct(std::forward(args)...); @@ -191,11 +191,11 @@ namespace boost { namespace unordered_detail { #else #define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \ - template \ + template \ template \ inline BOOST_DEDUCED_TYPENAME \ - hash_unique_table::emplace_return \ - hash_unique_table::emplace_impl( \ + hash_unique_table::emplace_return \ + hash_unique_table::emplace_impl( \ key_type const& k, \ BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ { \ @@ -218,11 +218,11 @@ namespace boost { namespace unordered_detail { } \ } \ \ - template \ + template \ template \ inline BOOST_DEDUCED_TYPENAME \ - hash_unique_table::emplace_return \ - hash_unique_table:: \ + hash_unique_table::emplace_return \ + hash_unique_table:: \ emplace_impl(no_key, \ BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ { \ @@ -231,17 +231,17 @@ namespace boost { namespace unordered_detail { return emplace_impl_with_node(a); \ } \ \ - template \ + template \ template \ inline BOOST_DEDUCED_TYPENAME \ - hash_unique_table::emplace_return \ - hash_unique_table:: \ + hash_unique_table::emplace_return \ + hash_unique_table:: \ emplace_empty_impl( \ BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ { \ node_constructor a(*this); \ a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ - return emplace_return(this->emplace_empty_impl_with_node(a, 1), true); \ + return emplace_return(this->emplace_empty_impl_with_node(a, 1), true); \ } BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, @@ -259,10 +259,10 @@ namespace boost { namespace unordered_detail { // if hash function throws, basic exception safety // strong otherwise - template + template template - BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return - hash_unique_table::emplace(Args&&... args) + BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return + hash_unique_table::emplace(Args&&... args) { return this->size_ ? emplace_impl( @@ -273,10 +273,10 @@ namespace boost { namespace unordered_detail { #else - template + template template - BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return - hash_unique_table::emplace(Arg0 const& arg0) + BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return + hash_unique_table::emplace(Arg0 const& arg0) { return this->size_ ? emplace_impl(extractor::extract(arg0), arg0) : @@ -284,10 +284,10 @@ namespace boost { namespace unordered_detail { } #define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \ - template \ + template \ template \ - BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return \ - hash_unique_table::emplace( \ + BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return \ + hash_unique_table::emplace( \ BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ { \ return this->size_ ? \ @@ -307,9 +307,9 @@ namespace boost { namespace unordered_detail { //////////////////////////////////////////////////////////////////////////// // Insert range methods - template + template template - inline void hash_unique_table::insert_range_impl( + inline void hash_unique_table::insert_range_impl( key_type const&, InputIt i, InputIt j) { node_constructor a(*this); @@ -352,9 +352,9 @@ namespace boost { namespace unordered_detail { } while(++i != j); } - template + template template - inline void hash_unique_table::insert_range_impl( + inline void hash_unique_table::insert_range_impl( no_key, InputIt i, InputIt j) { node_constructor a(*this); @@ -375,9 +375,9 @@ namespace boost { namespace unordered_detail { // if hash function throws, or inserting > 1 element, basic exception safety // strong otherwise - template + template template - void hash_unique_table::insert_range(InputIt i, InputIt j) + void hash_unique_table::insert_range(InputIt i, InputIt j) { if(i != j) return insert_range_impl(extractor::extract(*i), i, j); diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 8fab6e65..b0034116 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -58,10 +58,11 @@ namespace boost allocator_type, value_type>::type value_allocator; - typedef boost::unordered_detail::hash_unique_table table; + typedef boost::unordered_detail::map types; + typedef BOOST_DEDUCED_TYPENAME types::impl table; - typedef BOOST_DEDUCED_TYPENAME table::iterator_base iterator_base; + typedef BOOST_DEDUCED_TYPENAME types::iterator_base iterator_base; public: @@ -96,7 +97,7 @@ namespace boost table table_; - BOOST_DEDUCED_TYPENAME table::iterator_base const& + BOOST_DEDUCED_TYPENAME types::iterator_base const& get(const_iterator const& it) { return boost::unordered_detail::iterator_access::get(it); @@ -553,14 +554,17 @@ namespace boost #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) private: #endif + typedef BOOST_DEDUCED_TYPENAME boost::unordered_detail::rebind_wrap< allocator_type, value_type>::type value_allocator; - typedef boost::unordered_detail::hash_equivalent_table table; - typedef BOOST_DEDUCED_TYPENAME table::iterator_base iterator_base; + typedef boost::unordered_detail::multimap types; + typedef BOOST_DEDUCED_TYPENAME types::impl table; + + typedef BOOST_DEDUCED_TYPENAME types::iterator_base iterator_base; public: @@ -595,7 +599,7 @@ namespace boost table table_; - BOOST_DEDUCED_TYPENAME table::iterator_base const& + BOOST_DEDUCED_TYPENAME types::iterator_base const& get(const_iterator const& it) { return boost::unordered_detail::iterator_access::get(it); diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 16418c11..26c5090a 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -58,9 +58,11 @@ namespace boost allocator_type, value_type>::type value_allocator; - typedef boost::unordered_detail::hash_unique_table table; - typedef BOOST_DEDUCED_TYPENAME table::iterator_base iterator_base; + typedef boost::unordered_detail::set types; + typedef BOOST_DEDUCED_TYPENAME types::impl table; + + typedef BOOST_DEDUCED_TYPENAME types::iterator_base iterator_base; public: @@ -91,7 +93,7 @@ namespace boost table table_; - BOOST_DEDUCED_TYPENAME table::iterator_base const& + BOOST_DEDUCED_TYPENAME types::iterator_base const& get(const_iterator const& it) { return boost::unordered_detail::iterator_access::get(it); @@ -518,14 +520,17 @@ namespace boost #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) private: #endif + typedef BOOST_DEDUCED_TYPENAME boost::unordered_detail::rebind_wrap< allocator_type, value_type>::type value_allocator; - typedef boost::unordered_detail::hash_equivalent_table table; - typedef BOOST_DEDUCED_TYPENAME table::iterator_base iterator_base; + typedef boost::unordered_detail::multiset types; + typedef BOOST_DEDUCED_TYPENAME types::impl table; + + typedef BOOST_DEDUCED_TYPENAME types::iterator_base iterator_base; public: @@ -556,7 +561,7 @@ namespace boost table table_; - BOOST_DEDUCED_TYPENAME table::iterator_base const& + BOOST_DEDUCED_TYPENAME types::iterator_base const& get(const_iterator const& it) { return boost::unordered_detail::iterator_access::get(it); diff --git a/test/exception/Jamfile.v2 b/test/exception/Jamfile.v2 index a8508588..3fc78437 100644 --- a/test/exception/Jamfile.v2 +++ b/test/exception/Jamfile.v2 @@ -8,7 +8,18 @@ import testing ; #alias framework : /boost/test//boost_unit_test_framework ; alias framework : ; -project unordered-test/exception-tests ; +project unordered-test/exception-tests + : requirements + all + intel:on + gcc:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter" + darwin:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter" + gcc:_GLIBCXX_DEBUG + darwin:_GLIBCXX_DEBUG + msvc:on + gcc:on + darwin:on + ; test-suite unordered-exception : diff --git a/test/exception/assign_exception_tests.cpp b/test/exception/assign_exception_tests.cpp index ebf7ac0e..bdb99c15 100644 --- a/test/exception/assign_exception_tests.cpp +++ b/test/exception/assign_exception_tests.cpp @@ -3,10 +3,16 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include "../helpers/prefix.hpp" + #include "./containers.hpp" #include "../helpers/random_values.hpp" #include "../helpers/invariants.hpp" +#if defined(BOOST_MSVC) +#pragma warning(disable:4512) // assignment operator could not be generated +#endif + test::seed_t seed(12847); template @@ -18,7 +24,8 @@ struct self_assign_base : public test::exception_base typedef T data_type; T init() const { return T(values.begin(), values.end()); } void run(T& x) const { x = x; } - void check(T const& x) const { test::check_equivalent_keys(x); } + void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const + { test::check_equivalent_keys(x); } }; template @@ -48,7 +55,8 @@ struct assign_base : public test::exception_base typedef T data_type; T init() const { return T(x); } void run(T& x1) const { x1 = y; } - void check(T const& x1) const { test::check_equivalent_keys(x1); } + void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x1) const + { test::check_equivalent_keys(x1); } }; template diff --git a/test/exception/constructor_exception_tests.cpp b/test/exception/constructor_exception_tests.cpp index bda812af..15ab68e4 100644 --- a/test/exception/constructor_exception_tests.cpp +++ b/test/exception/constructor_exception_tests.cpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include "../helpers/prefix.hpp" + #include "./containers.hpp" #include "../helpers/random_values.hpp" #include "../helpers/input_iterator.hpp" diff --git a/test/exception/copy_exception_tests.cpp b/test/exception/copy_exception_tests.cpp index 01bbbdaa..36a0d798 100644 --- a/test/exception/copy_exception_tests.cpp +++ b/test/exception/copy_exception_tests.cpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include "../helpers/prefix.hpp" + #include "./containers.hpp" #include "../helpers/random_values.hpp" diff --git a/test/exception/erase_exception_tests.cpp b/test/exception/erase_exception_tests.cpp index 6746d628..9718e9d3 100644 --- a/test/exception/erase_exception_tests.cpp +++ b/test/exception/erase_exception_tests.cpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include "../helpers/prefix.hpp" + #include "./containers.hpp" #include "../helpers/random_values.hpp" #include "../helpers/invariants.hpp" @@ -22,7 +24,7 @@ struct erase_test_base : public test::exception_base return T(values.begin(), values.end()); } - void check(T const& x) const { + void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const { std::string scope(test::scope); BOOST_TEST(scope.find("hash::") != std::string::npos || diff --git a/test/exception/insert_exception_tests.cpp b/test/exception/insert_exception_tests.cpp index cf7d04e0..69651d61 100644 --- a/test/exception/insert_exception_tests.cpp +++ b/test/exception/insert_exception_tests.cpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include "../helpers/prefix.hpp" + #include "./containers.hpp" #include #include "../helpers/random_values.hpp" @@ -27,7 +29,7 @@ struct insert_test_base : public test::exception_base return T(); } - void check(T const& x, strong_type const& strong) const { + void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x, strong_type const& strong) const { std::string scope(test::scope); if(scope.find("hash::operator()") == std::string::npos) @@ -92,7 +94,7 @@ struct insert_test3 : public insert_test_base x.insert(this->values.begin(), this->values.end()); } - void check(T const& x) const { + void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const { test::check_equivalent_keys(x); } }; @@ -215,7 +217,7 @@ struct insert_test_rehash3 : public insert_test_base BOOST_TEST(x.bucket_count() != bucket_count); } - void check(T const& x) const { + void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const { if(x.size() < rehash_bucket_count) { //BOOST_TEST(x.bucket_count() == original_bucket_count); } diff --git a/test/exception/rehash_exception_tests.cpp b/test/exception/rehash_exception_tests.cpp index 7e69e748..03f49ce8 100644 --- a/test/exception/rehash_exception_tests.cpp +++ b/test/exception/rehash_exception_tests.cpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include "../helpers/prefix.hpp" + #include "./containers.hpp" #include #include "../helpers/random_values.hpp" @@ -28,7 +30,9 @@ struct rehash_test_base : public test::exception_base return x; } - void check(T const& x, strong_type const& strong) const { + void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x, + strong_type const& strong) const + { std::string scope(test::scope); if(scope.find("hash::operator()") == std::string::npos && diff --git a/test/exception/swap_exception_tests.cpp b/test/exception/swap_exception_tests.cpp index 2025b8bd..a3cfe823 100644 --- a/test/exception/swap_exception_tests.cpp +++ b/test/exception/swap_exception_tests.cpp @@ -3,10 +3,16 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include "../helpers/prefix.hpp" + #include "./containers.hpp" #include "../helpers/random_values.hpp" #include "../helpers/invariants.hpp" +#if defined(BOOST_MSVC) +#pragma warning(disable:4512) // assignment operator could not be generated +#endif + test::seed_t seed(9387); template @@ -18,7 +24,7 @@ struct self_swap_base : public test::exception_base typedef T data_type; T init() const { return T(values.begin(), values.end()); } void run(T& x) const { x.swap(x); } - void check(T const& x) const { + void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const { std::string scope(test::scope); #if BOOST_UNORDERED_SWAP_METHOD != 2 @@ -73,7 +79,7 @@ struct swap_base : public test::exception_base d.x.swap(d.y); } catch (std::runtime_error) {} } - void check(data_type const& d) const { + void check BOOST_PREVENT_MACRO_SUBSTITUTION(data_type const& d) const { std::string scope(test::scope); #if BOOST_UNORDERED_SWAP_METHOD != 2 diff --git a/test/helpers/allocator.hpp b/test/helpers/allocator.hpp index e41259b0..5482baa0 100644 --- a/test/helpers/allocator.hpp +++ b/test/helpers/allocator.hpp @@ -58,8 +58,8 @@ namespace test return (std::numeric_limits::max)(); } - bool operator==(malloc_allocator const& x) const { return true; } - bool operator!=(malloc_allocator const& x) const { return false; } + bool operator==(malloc_allocator const&) const { return true; } + bool operator!=(malloc_allocator const&) const { return false; } #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) template void deallocate(T* p, size_type) { diff --git a/test/helpers/exception_test.hpp b/test/helpers/exception_test.hpp index a235526c..a66c30aa 100644 --- a/test/helpers/exception_test.hpp +++ b/test/helpers/exception_test.hpp @@ -110,7 +110,7 @@ namespace test { template void test(T const&) const {} }; data_type init() const { return data_type(); } - void check() const {} + void check BOOST_PREVENT_MACRO_SUBSTITUTION() const {} }; template @@ -143,6 +143,9 @@ namespace test { class test_runner { Test const& test_; + + test_runner(test_runner const&); + test_runner& operator=(test_runner const&); public: test_runner(Test const& t) : test_(t) {} void operator()() const { diff --git a/test/helpers/input_iterator.hpp b/test/helpers/input_iterator.hpp index d81d9fec..9e962baa 100644 --- a/test/helpers/input_iterator.hpp +++ b/test/helpers/input_iterator.hpp @@ -21,6 +21,8 @@ namespace test operator value_type const&() const { return v_; } value_type v_; + private: + proxy& operator=(proxy const&); }; template diff --git a/test/helpers/invariants.hpp b/test/helpers/invariants.hpp index 199eb46b..1e14d685 100644 --- a/test/helpers/invariants.hpp +++ b/test/helpers/invariants.hpp @@ -18,6 +18,7 @@ #if defined(BOOST_MSVC) #pragma warning(push) #pragma warning(disable:4127) // conditional expression is constant +#pragma warning(disable:4267) // conversion from 'size_t' to 'unsigned int', possible loss of data #endif namespace test diff --git a/test/helpers/list.hpp b/test/helpers/list.hpp index 128386e0..3b59ce3e 100644 --- a/test/helpers/list.hpp +++ b/test/helpers/list.hpp @@ -17,6 +17,23 @@ namespace test { + template + bool equal(It1 begin, It1 end, It2 compare) + { + for(;begin != end; ++begin, ++compare) + if(*begin != *compare) return false; + return true; + } + + template + bool equal(It1 begin, It1 end, It2 compare, Pred predicate) + { + for(;begin != end; ++begin, ++compare) + if(!predicate(*begin, *compare)) return false; + return true; + } + + template class list; namespace test_detail @@ -222,7 +239,7 @@ namespace test bool operator==(list const& y) const { return size() == y.size() && - std::equal(begin(), end(), y.begin()); + test::equal(begin(), end(), y.begin()); } bool operator!=(list const& y) const { diff --git a/test/helpers/prefix.hpp b/test/helpers/prefix.hpp new file mode 100644 index 00000000..36080e46 --- /dev/null +++ b/test/helpers/prefix.hpp @@ -0,0 +1,10 @@ + +// Copyright 2009 Daniel James. +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#if defined(_WIN32_WCE) +// The standard windows mobile headers trigger this warning so I disable it +// before doing anything else. +#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union +#endif diff --git a/test/helpers/strong.hpp b/test/helpers/strong.hpp index a297fe07..f525faf7 100644 --- a/test/helpers/strong.hpp +++ b/test/helpers/strong.hpp @@ -31,7 +31,7 @@ namespace test void test(X const& x, unsigned int allocations = 0) const { if(!(x.size() == values_.size() && - std::equal(x.cbegin(), x.cend(), values_.begin(), + test::equal(x.cbegin(), x.cend(), values_.begin(), test::equivalent))) BOOST_ERROR("Strong exception safety failure."); if(allocations != allocations_) diff --git a/test/helpers/tracker.hpp b/test/helpers/tracker.hpp index bf6417aa..b5bf3c22 100644 --- a/test/helpers/tracker.hpp +++ b/test/helpers/tracker.hpp @@ -50,7 +50,7 @@ namespace test values1.sort(); values2.sort(); BOOST_TEST(values1.size() == values2.size() && - std::equal(values1.begin(), values1.end(), values2.begin(), + test::equal(values1.begin(), values1.end(), values2.begin(), test::equivalent)); } @@ -62,7 +62,7 @@ namespace test values1.sort(); values2.sort(); BOOST_TEST(values1.size() == values2.size() && - std::equal(values1.begin(), values1.end(), values2.begin(), test::equivalent)); + test::equal(values1.begin(), values1.end(), values2.begin(), test::equivalent)); } template diff --git a/test/unordered/Jamfile.v2 b/test/unordered/Jamfile.v2 index 882ec132..2fdfd357 100644 --- a/test/unordered/Jamfile.v2 +++ b/test/unordered/Jamfile.v2 @@ -9,9 +9,13 @@ project unordered-test/unordered : requirements all intel:on - intel:-strict-ansi - msvc:/W4 - gcc:"-Wsign-promo -Wunused-parameter -pedantic" + gcc:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter" + darwin:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter" + gcc:_GLIBCXX_DEBUG + darwin:_GLIBCXX_DEBUG + msvc:on + gcc:on + darwin:on ; test-suite unordered @@ -21,6 +25,7 @@ test-suite unordered [ run compile_set.cpp ] [ run compile_map.cpp ] [ run link_test_1.cpp link_test_2.cpp ] + [ run incomplete_test.cpp ] [ run simple_tests.cpp ] [ run equivalent_keys_tests.cpp ] [ run constructor_tests.cpp ] diff --git a/test/unordered/assign_tests.cpp b/test/unordered/assign_tests.cpp index 2bfb39fe..72a73fe7 100644 --- a/test/unordered/assign_tests.cpp +++ b/test/unordered/assign_tests.cpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include "../helpers/prefix.hpp" + #include #include #include "../helpers/test.hpp" diff --git a/test/unordered/at_tests.cpp b/test/unordered/at_tests.cpp index ff9fdc81..b67900f3 100644 --- a/test/unordered/at_tests.cpp +++ b/test/unordered/at_tests.cpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include "../helpers/prefix.hpp" + #include #include "../helpers/test.hpp" #include diff --git a/test/unordered/bucket_tests.cpp b/test/unordered/bucket_tests.cpp index eeaa625a..7126b8bb 100644 --- a/test/unordered/bucket_tests.cpp +++ b/test/unordered/bucket_tests.cpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include "../helpers/prefix.hpp" + #include #include #include "../helpers/test.hpp" @@ -11,6 +13,11 @@ #include "../helpers/random_values.hpp" #include "../helpers/helpers.hpp" +#if BOOST_WORKAROUND(BOOST_MSVC, < 1400) +#pragma warning(disable:4267) // conversion from 'size_t' to 'unsigned int', + // possible loss of data. +#endif + namespace bucket_tests { test::seed_t seed(54635); diff --git a/test/unordered/compile_map.cpp b/test/unordered/compile_map.cpp index 378d7c67..79eb8425 100644 --- a/test/unordered/compile_map.cpp +++ b/test/unordered/compile_map.cpp @@ -6,6 +6,8 @@ // This test creates the containers with members that meet their minimum // requirements. Makes sure everything compiles and is defined correctly. +#include "../helpers/prefix.hpp" + #include #include diff --git a/test/unordered/compile_set.cpp b/test/unordered/compile_set.cpp index e0de7bd9..95df1abf 100644 --- a/test/unordered/compile_set.cpp +++ b/test/unordered/compile_set.cpp @@ -6,6 +6,8 @@ // This test creates the containers with members that meet their minimum // requirements. Makes sure everything compiles and is defined correctly. +#include "../helpers/prefix.hpp" + #include #include diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index b657629b..aa33ee35 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -6,6 +6,8 @@ #if defined(BOOST_MSVC) #pragma warning(push) #pragma warning(disable:4100) // unreferenced formal parameter +#pragma warning(disable:4610) // class can never be instantiated +#pragma warning(disable:4510) // default constructor could not be generated #endif #include diff --git a/test/unordered/constructor_tests.cpp b/test/unordered/constructor_tests.cpp index 5a719e2a..2e866b1d 100644 --- a/test/unordered/constructor_tests.cpp +++ b/test/unordered/constructor_tests.cpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include "../helpers/prefix.hpp" + #include #include #include "../helpers/test.hpp" diff --git a/test/unordered/copy_tests.cpp b/test/unordered/copy_tests.cpp index a4eea801..8ddfb782 100644 --- a/test/unordered/copy_tests.cpp +++ b/test/unordered/copy_tests.cpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include "../helpers/prefix.hpp" + #include #include #include "../helpers/test.hpp" diff --git a/test/unordered/equality_tests.cpp b/test/unordered/equality_tests.cpp index bfc78f1b..45c4c9d3 100644 --- a/test/unordered/equality_tests.cpp +++ b/test/unordered/equality_tests.cpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include "../helpers/prefix.hpp" + #include #include #include @@ -29,36 +31,36 @@ namespace equality_tests }; #define UNORDERED_EQUALITY_SET_TEST(seq1, op, seq2) \ - do { \ + { \ boost::unordered_set set1, set2; \ BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \ BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \ BOOST_TEST(set1 op set2); \ - } while(false) + } #define UNORDERED_EQUALITY_MULTISET_TEST(seq1, op, seq2) \ - do { \ + { \ boost::unordered_multiset set1, set2; \ BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \ BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \ BOOST_TEST(set1 op set2); \ - } while(false) + } #define UNORDERED_EQUALITY_MAP_TEST(seq1, op, seq2) \ - do { \ + { \ boost::unordered_map map1, map2; \ BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \ BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \ BOOST_TEST(map1 op map2); \ - } while(false) + } #define UNORDERED_EQUALITY_MULTIMAP_TEST(seq1, op, seq2) \ - do { \ + { \ boost::unordered_multimap map1, map2; \ BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \ BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \ BOOST_TEST(map1 op map2); \ - } while(false) + } #define UNORDERED_SET_INSERT(r, set, item) set.insert(item); #define UNORDERED_MAP_INSERT(r, map, item) \ @@ -89,57 +91,57 @@ namespace equality_tests UNORDERED_AUTO_TEST(equality_key_value_tests) { - UNORDERED_EQUALITY_MULTISET_TEST((1), !=, (2)); - UNORDERED_EQUALITY_SET_TEST((2), ==, (2)); - UNORDERED_EQUALITY_MAP_TEST(((1)(1))((2)(1)), !=, ((1)(1))((3)(1))); + UNORDERED_EQUALITY_MULTISET_TEST((1), !=, (2)) + UNORDERED_EQUALITY_SET_TEST((2), ==, (2)) + UNORDERED_EQUALITY_MAP_TEST(((1)(1))((2)(1)), !=, ((1)(1))((3)(1))) } UNORDERED_AUTO_TEST(equality_collision_test) { UNORDERED_EQUALITY_MULTISET_TEST( - (1), !=, (501)); + (1), !=, (501)) UNORDERED_EQUALITY_MULTISET_TEST( - (1)(251), !=, (1)(501)); + (1)(251), !=, (1)(501)) UNORDERED_EQUALITY_MULTIMAP_TEST( - ((251)(1))((1)(1)), !=, ((501)(1))((1)(1))); + ((251)(1))((1)(1)), !=, ((501)(1))((1)(1))) UNORDERED_EQUALITY_MULTISET_TEST( - (1)(501), ==, (1)(501)); + (1)(501), ==, (1)(501)) UNORDERED_EQUALITY_SET_TEST( - (1)(501), ==, (501)(1)); + (1)(501), ==, (501)(1)) } UNORDERED_AUTO_TEST(equality_group_size_test) { UNORDERED_EQUALITY_MULTISET_TEST( - (10)(20)(20), !=, (10)(10)(20)); + (10)(20)(20), !=, (10)(10)(20)) UNORDERED_EQUALITY_MULTIMAP_TEST( ((10)(1))((20)(1))((20)(1)), !=, - ((10)(1))((20)(1))((10)(1))); + ((10)(1))((20)(1))((10)(1))) UNORDERED_EQUALITY_MULTIMAP_TEST( ((20)(1))((10)(1))((10)(1)), ==, - ((10)(1))((20)(1))((10)(1))); + ((10)(1))((20)(1))((10)(1))) } UNORDERED_AUTO_TEST(equality_map_value_test) { UNORDERED_EQUALITY_MAP_TEST( - ((1)(1)), !=, ((1)(2))); + ((1)(1)), !=, ((1)(2))) UNORDERED_EQUALITY_MAP_TEST( - ((1)(1)), ==, ((1)(1))); + ((1)(1)), ==, ((1)(1))) UNORDERED_EQUALITY_MULTIMAP_TEST( - ((1)(1)), !=, ((1)(2))); + ((1)(1)), !=, ((1)(2))) UNORDERED_EQUALITY_MULTIMAP_TEST( - ((1)(1))((1)(1)), !=, ((1)(1))((1)(2))); + ((1)(1))((1)(1)), !=, ((1)(1))((1)(2))) UNORDERED_EQUALITY_MULTIMAP_TEST( - ((1)(2))((1)(1)), !=, ((1)(1))((1)(2))); + ((1)(2))((1)(1)), !=, ((1)(1))((1)(2))) } UNORDERED_AUTO_TEST(equality_predicate_test) { UNORDERED_EQUALITY_SET_TEST( - (1), ==, (1001)); + (1), ==, (1001)) UNORDERED_EQUALITY_MAP_TEST( - ((1)(2))((1001)(1)), ==, ((1001)(2))((1)(1))); + ((1)(2))((1001)(1)), ==, ((1001)(2))((1)(1))) } // Test that equality still works when the two containers have diff --git a/test/unordered/equivalent_keys_tests.cpp b/test/unordered/equivalent_keys_tests.cpp index 295ec721..10f3ac1c 100644 --- a/test/unordered/equivalent_keys_tests.cpp +++ b/test/unordered/equivalent_keys_tests.cpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include "../helpers/prefix.hpp" + #include #include #include "../helpers/test.hpp" diff --git a/test/unordered/erase_equiv_tests.cpp b/test/unordered/erase_equiv_tests.cpp index a1bebf45..010414be 100644 --- a/test/unordered/erase_equiv_tests.cpp +++ b/test/unordered/erase_equiv_tests.cpp @@ -6,6 +6,8 @@ // The code for erasing elements from containers with equivalent keys is very // hairy with several tricky edge cases - so explicitly test each one. +#include "../helpers/prefix.hpp" + #include #include "../helpers/test.hpp" #include "../helpers/list.hpp" @@ -15,6 +17,11 @@ #include #include "../objects/test.hpp" +#if BOOST_WORKAROUND(BOOST_MSVC, < 1400) +#pragma warning(disable:4267) // conversion from 'size_t' to 'unsigned int', + // possible loss of data. +#endif + struct write_pair_type { template diff --git a/test/unordered/erase_tests.cpp b/test/unordered/erase_tests.cpp index 74fc6d1f..eab22f4c 100644 --- a/test/unordered/erase_tests.cpp +++ b/test/unordered/erase_tests.cpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include "../helpers/prefix.hpp" + #include #include #include "../helpers/test.hpp" @@ -65,7 +67,7 @@ void erase_tests1(Container*, test::random_generator generator = test::default_g while(size > 0 && !x.empty()) { using namespace std; - int index = rand() % x.size(); + int index = rand() % (int) x.size(); BOOST_DEDUCED_TYPENAME Container::const_iterator prev, pos, next; if(index == 0) { prev = pos = x.begin(); diff --git a/test/unordered/find_tests.cpp b/test/unordered/find_tests.cpp index ad170a44..24523fd3 100644 --- a/test/unordered/find_tests.cpp +++ b/test/unordered/find_tests.cpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include "../helpers/prefix.hpp" + #include #include #include "../helpers/test.hpp" diff --git a/test/unordered/fwd_map_test.cpp b/test/unordered/fwd_map_test.cpp index 831e54d4..531d573c 100644 --- a/test/unordered/fwd_map_test.cpp +++ b/test/unordered/fwd_map_test.cpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include "../helpers/prefix.hpp" + #include typedef boost::unordered_map int_map; diff --git a/test/unordered/fwd_set_test.cpp b/test/unordered/fwd_set_test.cpp index 3db151a7..866ffc4f 100644 --- a/test/unordered/fwd_set_test.cpp +++ b/test/unordered/fwd_set_test.cpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include "../helpers/prefix.hpp" + #include struct true_type { char x[100]; }; diff --git a/test/unordered/incomplete_test.cpp b/test/unordered/incomplete_test.cpp new file mode 100644 index 00000000..b1666c9e --- /dev/null +++ b/test/unordered/incomplete_test.cpp @@ -0,0 +1,42 @@ + +// Copyright 2009 Daniel James. +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include "../helpers/prefix.hpp" + +#include +#include + +namespace test +{ + struct value; + struct hash; + struct equals; + template + struct malloc_allocator; + + typedef boost::unordered_map > > map; + typedef boost::unordered_multimap > > multimap; + typedef boost::unordered_set > set; + typedef boost::unordered_multiset > multiset; + + struct value {}; + struct hash { std::size_t operator()(value const&) const { return 0; } }; + struct equals { bool operator()(value const&, value const&) const { return true; } }; +} + +#include "../helpers/allocator.hpp" + +int main() { + test::map m1; + test::multimap m2; + test::set s1; + test::multiset s2; + + test::value x; + m1[x] = x; + m2.insert(std::make_pair(x, x)); + s1.insert(x); + s2.insert(x); +} diff --git a/test/unordered/insert_stable_tests.cpp b/test/unordered/insert_stable_tests.cpp index df38743e..4fd44f3f 100644 --- a/test/unordered/insert_stable_tests.cpp +++ b/test/unordered/insert_stable_tests.cpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include "../helpers/prefix.hpp" + #include #include #include "../helpers/test.hpp" diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 69d1c67c..69d0e86d 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include "../helpers/prefix.hpp" + #include #include #include "../helpers/test.hpp" diff --git a/test/unordered/link_test_1.cpp b/test/unordered/link_test_1.cpp index 33f709ff..563f87ff 100644 --- a/test/unordered/link_test_1.cpp +++ b/test/unordered/link_test_1.cpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include "../helpers/prefix.hpp" + #include #include diff --git a/test/unordered/link_test_2.cpp b/test/unordered/link_test_2.cpp index 4735abdf..abcf2130 100644 --- a/test/unordered/link_test_2.cpp +++ b/test/unordered/link_test_2.cpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include "../helpers/prefix.hpp" + #include #include diff --git a/test/unordered/load_factor_tests.cpp b/test/unordered/load_factor_tests.cpp index 8a2297c7..10baf1f5 100644 --- a/test/unordered/load_factor_tests.cpp +++ b/test/unordered/load_factor_tests.cpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include "../helpers/prefix.hpp" + #include #include #include "../helpers/test.hpp" diff --git a/test/unordered/move_tests.cpp b/test/unordered/move_tests.cpp index 3d06686b..47e77bb9 100644 --- a/test/unordered/move_tests.cpp +++ b/test/unordered/move_tests.cpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or move at http://www.boost.org/LICENSE_1_0.txt) +#include "../helpers/prefix.hpp" + #include #include #include "../helpers/test.hpp" @@ -64,7 +66,9 @@ namespace move_tests test::random_values v(1000, generator); test::object_count count; T y(create(v, count)); +#if defined(BOOST_HAS_NRVO) BOOST_TEST(count == test::global_object_count); +#endif test::check_container(y, v); test::check_equivalent_keys(y); } @@ -78,7 +82,9 @@ namespace move_tests test::object_count count; T y; y = create(v, count); +#if defined(BOOST_HAS_NRVO) BOOST_TEST(count == test::global_object_count); +#endif test::check_container(y, v); test::check_equivalent_keys(y); } @@ -98,7 +104,9 @@ namespace move_tests { test::random_values v(500, generator); T y(create(v, count, hf, eq, al, 0.5)); +#if defined(BOOST_HAS_NRVO) BOOST_TEST(count == test::global_object_count); +#endif test::check_container(y, v); BOOST_TEST(test::equivalent(y.hash_function(), hf)); BOOST_TEST(test::equivalent(y.key_eq(), eq)); diff --git a/test/unordered/rehash_tests.cpp b/test/unordered/rehash_tests.cpp index 0f1d7820..7f66edc1 100644 --- a/test/unordered/rehash_tests.cpp +++ b/test/unordered/rehash_tests.cpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include "../helpers/prefix.hpp" + #include #include #include "../helpers/test.hpp" diff --git a/test/unordered/simple_tests.cpp b/test/unordered/simple_tests.cpp index 1e8063f5..e7b9539e 100644 --- a/test/unordered/simple_tests.cpp +++ b/test/unordered/simple_tests.cpp @@ -5,6 +5,8 @@ // This test checks the runtime requirements of containers. +#include "../helpers/prefix.hpp" + #include #include #include "../helpers/test.hpp" diff --git a/test/unordered/swap_tests.cpp b/test/unordered/swap_tests.cpp index f7b02769..5fe8be91 100644 --- a/test/unordered/swap_tests.cpp +++ b/test/unordered/swap_tests.cpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include "../helpers/prefix.hpp" + #include #include #include diff --git a/test/unordered/unnecessary_copy_tests.cpp b/test/unordered/unnecessary_copy_tests.cpp index 3cf707ef..40df82f6 100644 --- a/test/unordered/unnecessary_copy_tests.cpp +++ b/test/unordered/unnecessary_copy_tests.cpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#include "../helpers/prefix.hpp" + #include #include #include "../helpers/test.hpp" From 02bf8f288e64627e26772e74cc5dae84c51011fa Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 7 Dec 2009 19:26:26 +0000 Subject: [PATCH 044/100] Merge unordered and hash. Improved Codegear support in unordered. Another warning suppression in hash. [SVN r58223] --- doc/changes.qbk | 5 + include/boost/unordered/detail/util.hpp | 3 + include/boost/unordered/unordered_map.hpp | 63 ++++++---- include/boost/unordered/unordered_map_fwd.hpp | 16 +-- include/boost/unordered/unordered_set.hpp | 58 +++++---- include/boost/unordered/unordered_set_fwd.hpp | 16 +-- .../exception/constructor_exception_tests.cpp | 5 +- test/exception/insert_exception_tests.cpp | 1 - test/helpers/input_iterator.hpp | 51 +++++--- test/unordered/constructor_tests.cpp | 8 +- test/unordered/incomplete_test.cpp | 112 ++++++++++++++++-- test/unordered/insert_tests.cpp | 4 +- test/unordered/link_test_2.cpp | 9 ++ 13 files changed, 265 insertions(+), 86 deletions(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index 6d0f0260..d1b26254 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -102,5 +102,10 @@ First official release. * Buckets are allocated lazily which means that constructing an empty container will not allocate any memory. + +[h2 Boost 1.42.0] + +* Support instantiating the containers with incomplete value types. +* Reduced the number of warnings (mostly in tests). [endsect] diff --git a/include/boost/unordered/detail/util.hpp b/include/boost/unordered/detail/util.hpp index 1f592dd3..22b41583 100644 --- a/include/boost/unordered/detail/util.hpp +++ b/include/boost/unordered/detail/util.hpp @@ -288,6 +288,9 @@ namespace boost { namespace unordered_detail { { if (node_) { if (value_constructed_) { +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { hash_node x; }; +#endif boost::unordered_detail::destroy(&node_->value()); } diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index b0034116..ef649897 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -38,16 +38,16 @@ namespace boost { - template + template class unordered_map { public: - typedef Key key_type; - typedef std::pair value_type; + typedef K key_type; + typedef std::pair value_type; typedef T mapped_type; - typedef Hash hasher; - typedef Pred key_equal; - typedef Alloc allocator_type; + typedef H hasher; + typedef P key_equal; + typedef A allocator_type; #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) private: @@ -58,7 +58,7 @@ namespace boost allocator_type, value_type>::type value_allocator; - typedef boost::unordered_detail::map types; typedef BOOST_DEDUCED_TYPENAME types::impl table; @@ -177,7 +177,7 @@ namespace boost } #else unordered_map(boost::unordered_detail::move_from< - unordered_map + unordered_map > other) : table_(other.source.table_, boost::unordered_detail::move_tag()) { @@ -284,6 +284,7 @@ namespace boost } #else + #if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) std::pair emplace(value_type const& v = value_type()) { return boost::unordered_detail::pair_cast( @@ -294,6 +295,7 @@ namespace boost { return iterator(table_.emplace(v).first); } + #endif #define BOOST_UNORDERED_EMPLACE(z, n, _) \ template < \ @@ -511,9 +513,9 @@ namespace boost } #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) - friend bool operator==( + friend bool operator==( unordered_map const&, unordered_map const&); - friend bool operator!=( + friend bool operator!=( unordered_map const&, unordered_map const&); #endif }; // class template unordered_map @@ -522,6 +524,9 @@ namespace boost inline bool operator==(unordered_map const& m1, unordered_map const& m2) { +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { unordered_map x; }; +#endif return m1.table_.equals(m2.table_); } @@ -529,6 +534,9 @@ namespace boost inline bool operator!=(unordered_map const& m1, unordered_map const& m2) { +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { unordered_map x; }; +#endif return !m1.table_.equals(m2.table_); } @@ -536,20 +544,23 @@ namespace boost inline void swap(unordered_map &m1, unordered_map &m2) { +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { unordered_map x; }; +#endif m1.swap(m2); } - template + template class unordered_multimap { public: - typedef Key key_type; - typedef std::pair value_type; + typedef K key_type; + typedef std::pair value_type; typedef T mapped_type; - typedef Hash hasher; - typedef Pred key_equal; - typedef Alloc allocator_type; + typedef H hasher; + typedef P key_equal; + typedef A allocator_type; #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) private: @@ -560,7 +571,7 @@ namespace boost allocator_type, value_type>::type value_allocator; - typedef boost::unordered_detail::multimap types; typedef BOOST_DEDUCED_TYPENAME types::impl table; @@ -680,7 +691,7 @@ namespace boost } #else unordered_multimap(boost::unordered_detail::move_from< - unordered_multimap + unordered_multimap > other) : table_(other.source.table_, boost::unordered_detail::move_tag()) { @@ -786,6 +797,7 @@ namespace boost } #else + #if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) iterator emplace(value_type const& v = value_type()) { return iterator(table_.emplace(v)); @@ -796,7 +808,7 @@ namespace boost { return iterator(table_.emplace(v)); } - + #endif #define BOOST_UNORDERED_EMPLACE(z, n, _) \ template < \ @@ -999,9 +1011,9 @@ namespace boost } #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) - friend bool operator==( + friend bool operator==( unordered_multimap const&, unordered_multimap const&); - friend bool operator!=( + friend bool operator!=( unordered_multimap const&, unordered_multimap const&); #endif }; // class template unordered_multimap @@ -1010,6 +1022,9 @@ namespace boost inline bool operator==(unordered_multimap const& m1, unordered_multimap const& m2) { +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { unordered_multimap x; }; +#endif return m1.table_.equals(m2.table_); } @@ -1017,6 +1032,9 @@ namespace boost inline bool operator!=(unordered_multimap const& m1, unordered_multimap const& m2) { +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { unordered_multimap x; }; +#endif return !m1.table_.equals(m2.table_); } @@ -1024,6 +1042,9 @@ namespace boost inline void swap(unordered_multimap &m1, unordered_multimap &m2) { +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { unordered_multimap x; }; +#endif m1.swap(m2); } diff --git a/include/boost/unordered/unordered_map_fwd.hpp b/include/boost/unordered/unordered_map_fwd.hpp index bbd81627..5e9bb076 100644 --- a/include/boost/unordered/unordered_map_fwd.hpp +++ b/include/boost/unordered/unordered_map_fwd.hpp @@ -17,11 +17,11 @@ namespace boost { - template , - class Pred = std::equal_to, - class Alloc = std::allocator > > + class H = hash, + class P = std::equal_to, + class A = std::allocator > > class unordered_map; template bool operator==(unordered_map const&, @@ -33,11 +33,11 @@ namespace boost void swap(unordered_map&, unordered_map&); - template , - class Pred = std::equal_to, - class Alloc = std::allocator > > + class H = hash, + class P = std::equal_to, + class A = std::allocator > > class unordered_multimap; template bool operator==(unordered_multimap const&, diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 26c5090a..59843fd6 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -38,16 +38,16 @@ namespace boost { - template + template class unordered_set { public: - typedef Value key_type; - typedef Value value_type; - typedef Hash hasher; - typedef Pred key_equal; - typedef Alloc allocator_type; + typedef T key_type; + typedef T value_type; + typedef H hasher; + typedef P key_equal; + typedef A allocator_type; #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) private: @@ -58,7 +58,7 @@ namespace boost allocator_type, value_type>::type value_allocator; - typedef boost::unordered_detail::set types; typedef BOOST_DEDUCED_TYPENAME types::impl table; @@ -171,7 +171,7 @@ namespace boost } #else unordered_set(boost::unordered_detail::move_from< - unordered_set + unordered_set > other) : table_(other.source.table_, boost::unordered_detail::move_tag()) { @@ -478,9 +478,9 @@ namespace boost } #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) - friend bool operator==( + friend bool operator==( unordered_set const&, unordered_set const&); - friend bool operator!=( + friend bool operator!=( unordered_set const&, unordered_set const&); #endif }; // class template unordered_set @@ -489,6 +489,9 @@ namespace boost inline bool operator==(unordered_set const& m1, unordered_set const& m2) { +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { unordered_set x; }; +#endif return m1.table_.equals(m2.table_); } @@ -496,6 +499,9 @@ namespace boost inline bool operator!=(unordered_set const& m1, unordered_set const& m2) { +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { unordered_set x; }; +#endif return !m1.table_.equals(m2.table_); } @@ -503,19 +509,22 @@ namespace boost inline void swap(unordered_set &m1, unordered_set &m2) { +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { unordered_set x; }; +#endif m1.swap(m2); } - template + template class unordered_multiset { public: - typedef Value key_type; - typedef Value value_type; - typedef Hash hasher; - typedef Pred key_equal; - typedef Alloc allocator_type; + typedef T key_type; + typedef T value_type; + typedef H hasher; + typedef P key_equal; + typedef A allocator_type; #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) private: @@ -526,7 +535,7 @@ namespace boost allocator_type, value_type>::type value_allocator; - typedef boost::unordered_detail::multiset types; typedef BOOST_DEDUCED_TYPENAME types::impl table; @@ -640,7 +649,7 @@ namespace boost } #else unordered_multiset(boost::unordered_detail::move_from< - unordered_multiset + unordered_multiset > other) : table_(other.source.table_, boost::unordered_detail::move_tag()) { @@ -943,9 +952,9 @@ namespace boost } #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) - friend bool operator==( + friend bool operator==( unordered_multiset const&, unordered_multiset const&); - friend bool operator!=( + friend bool operator!=( unordered_multiset const&, unordered_multiset const&); #endif }; // class template unordered_multiset @@ -954,6 +963,9 @@ namespace boost inline bool operator==(unordered_multiset const& m1, unordered_multiset const& m2) { +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { unordered_multiset x; }; +#endif return m1.table_.equals(m2.table_); } @@ -961,6 +973,9 @@ namespace boost inline bool operator!=(unordered_multiset const& m1, unordered_multiset const& m2) { +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { unordered_multiset x; }; +#endif return !m1.table_.equals(m2.table_); } @@ -968,6 +983,9 @@ namespace boost inline void swap(unordered_multiset &m1, unordered_multiset &m2) { +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { unordered_multiset x; }; +#endif m1.swap(m2); } diff --git a/include/boost/unordered/unordered_set_fwd.hpp b/include/boost/unordered/unordered_set_fwd.hpp index 6b3f74e7..8000eb14 100644 --- a/include/boost/unordered/unordered_set_fwd.hpp +++ b/include/boost/unordered/unordered_set_fwd.hpp @@ -17,10 +17,10 @@ namespace boost { - template , - class Pred = std::equal_to, - class Alloc = std::allocator > + template , + class P = std::equal_to, + class A = std::allocator > class unordered_set; template bool operator==(unordered_set const&, @@ -32,10 +32,10 @@ namespace boost void swap(unordered_set &m1, unordered_set &m2); - template , - class Pred = std::equal_to, - class Alloc = std::allocator > + template , + class P = std::equal_to, + class A = std::allocator > class unordered_multiset; template bool operator==(unordered_multiset const&, diff --git a/test/exception/constructor_exception_tests.cpp b/test/exception/constructor_exception_tests.cpp index 15ab68e4..1b95af7d 100644 --- a/test/exception/constructor_exception_tests.cpp +++ b/test/exception/constructor_exception_tests.cpp @@ -126,8 +126,9 @@ struct input_range_construct_test : public range, objects input_range_construct_test() : range(60) {} void run() const { - T x(test::input_iterator(this->values.begin()), - test::input_iterator(this->values.end()), + BOOST_DEDUCED_TYPENAME test::random_values::const_iterator + begin = this->values.begin(), end = this->values.end(); + T x(test::input_iterator(begin), test::input_iterator(end), 0, hash, equal_to, allocator); } }; diff --git a/test/exception/insert_exception_tests.cpp b/test/exception/insert_exception_tests.cpp index 69651d61..946fe036 100644 --- a/test/exception/insert_exception_tests.cpp +++ b/test/exception/insert_exception_tests.cpp @@ -10,7 +10,6 @@ #include "../helpers/random_values.hpp" #include "../helpers/invariants.hpp" #include "../helpers/strong.hpp" -#include "../helpers/input_iterator.hpp" #include #include diff --git a/test/helpers/input_iterator.hpp b/test/helpers/input_iterator.hpp index 9e962baa..873120cd 100644 --- a/test/helpers/input_iterator.hpp +++ b/test/helpers/input_iterator.hpp @@ -7,7 +7,8 @@ #define BOOST_UNORDERED_TEST_HELPERS_INPUT_ITERATOR_HEADER #include -#include +#include +#include namespace test { @@ -16,7 +17,7 @@ namespace test { typedef BOOST_DEDUCED_TYPENAME Iterator::value_type value_type; - proxy(value_type const& v) : v_(v) {} + explicit proxy(value_type const& v) : v_(v) {} proxy(proxy const& x) : v_(x.v_) {} operator value_type const&() const { return v_; } @@ -27,22 +28,44 @@ namespace test template struct input_iterator_adaptor - : boost::iterator_adaptor< - input_iterator_adaptor, Iterator, - boost::use_default, std::input_iterator_tag, - proxy > + : public boost::iterator< + std::input_iterator_tag, + BOOST_DEDUCED_TYPENAME boost::iterator_value::type, + std::ptrdiff_t, + BOOST_DEDUCED_TYPENAME boost::iterator_pointer::type, + proxy + > { - typedef boost::iterator_adaptor< - input_iterator_adaptor, Iterator, - boost::use_default, std::input_iterator_tag, - proxy > base; - - explicit input_iterator_adaptor(Iterator it = Iterator()) - : base(it) {} + typedef BOOST_DEDUCED_TYPENAME boost::iterator_value::type + value_type; + + input_iterator_adaptor() + : base_() {} + explicit input_iterator_adaptor(Iterator& it) + : base_(&it) {} + proxy operator*() const { + return proxy(**base_); + } + value_type* operator->() const { + return &**base_; + } + input_iterator_adaptor& operator++() { + ++*base_; return *this; + } + //input_iterator_adaptor operator++(int) { + //} + bool operator==(input_iterator_adaptor const& x) const { + return *base_ == *x.base_; + } + bool operator!=(input_iterator_adaptor const& x) const { + return *base_ != *x.base_; + } + private: + Iterator* base_; }; template - input_iterator_adaptor input_iterator(Iterator it) + input_iterator_adaptor input_iterator(Iterator& it) { return input_iterator_adaptor(it); } diff --git a/test/unordered/constructor_tests.cpp b/test/unordered/constructor_tests.cpp index 2e866b1d..5ad411f0 100644 --- a/test/unordered/constructor_tests.cpp +++ b/test/unordered/constructor_tests.cpp @@ -245,8 +245,12 @@ void constructor_tests2(T*, test::random_generator const& generator = test::defa std::cerr<<"Construct 8 - from input iterator\n"; { test::random_values v(100, generator); - T x(test::input_iterator(v.begin()), test::input_iterator(v.end()), 0, hf1, eq1); - T y(test::input_iterator(x.begin()), test::input_iterator(x.end()), 0, hf2, eq2); + BOOST_DEDUCED_TYPENAME test::random_values::const_iterator + v_begin = v.begin(), v_end = v.end(); + T x(test::input_iterator(v_begin), test::input_iterator(v_end), 0, hf1, eq1); + BOOST_DEDUCED_TYPENAME T::const_iterator + x_begin = x.begin(), x_end = x.end(); + T y(test::input_iterator(x_begin), test::input_iterator(x_end), 0, hf2, eq2); test::check_container(x, v); test::check_container(y, x); test::check_equivalent_keys(x); diff --git a/test/unordered/incomplete_test.cpp b/test/unordered/incomplete_test.cpp index b1666c9e..a8bf784a 100644 --- a/test/unordered/incomplete_test.cpp +++ b/test/unordered/incomplete_test.cpp @@ -8,35 +8,129 @@ #include #include +namespace x +{ + struct D { boost::unordered_map x; }; +} + namespace test { + // Declare, but don't define some types. + struct value; struct hash; struct equals; template struct malloc_allocator; + + // Declare some instances typedef boost::unordered_map > > map; typedef boost::unordered_multimap > > multimap; typedef boost::unordered_set > set; typedef boost::unordered_multiset > multiset; - struct value {}; - struct hash { std::size_t operator()(value const&) const { return 0; } }; - struct equals { bool operator()(value const&, value const&) const { return true; } }; + // Now define the types which are stored as members, as they are needed for + // declaring struct members. + + struct hash { + template + std::size_t operator()(T const&) const { return 0; } + }; + + struct equals { + template + bool operator()(T const&, T const&) const { return true; } + }; + } #include "../helpers/allocator.hpp" -int main() { +namespace test +{ + // Declare some members of a structs. + // + // Incomplete hash, equals and allocator aren't here supported at the moment. + + struct struct1 { + boost::unordered_map > > x; + }; + struct struct2 { + boost::unordered_multimap > > x; + }; + struct struct3 { + boost::unordered_set > x; + }; + struct struct4 { + boost::unordered_multiset > x; + }; + + // Now define the value type. + + struct value {}; + + // Create some instances. + test::map m1; test::multimap m2; test::set s1; test::multiset s2; + + test::struct1 c1; + test::struct2 c2; + test::struct3 c3; + test::struct4 c4; + // Now declare, but don't define, the operators required for comparing elements. + + std::size_t hash_value(value const&); + bool operator==(value const&, value const&); + + std::size_t hash_value(struct1 const&); + std::size_t hash_value(struct2 const&); + std::size_t hash_value(struct3 const&); + std::size_t hash_value(struct4 const&); - test::value x; - m1[x] = x; - m2.insert(std::make_pair(x, x)); - s1.insert(x); - s2.insert(x); + bool operator==(struct1 const&, struct1 const&); + bool operator==(struct2 const&, struct2 const&); + bool operator==(struct3 const&, struct3 const&); + bool operator==(struct4 const&, struct4 const&); + + // And finally use these + + void use_types() + { + test::value x; + m1[x] = x; + m2.insert(std::make_pair(x, x)); + s1.insert(x); + s2.insert(x); + + c1.x.insert(std::make_pair(c1, c1)); + c2.x.insert(std::make_pair(c2, c2)); + c3.x.insert(c3); + c4.x.insert(c4); + } + + // And finally define the operators required for comparing elements. + + std::size_t hash_value(value const&) { return 0; } + bool operator==(value const&, value const&) { return true; } + + std::size_t hash_value(struct1 const&) { return 0; } + std::size_t hash_value(struct2 const&) { return 0; } + std::size_t hash_value(struct3 const&) { return 0; } + std::size_t hash_value(struct4 const&) { return 0; } + + bool operator==(struct1 const&, struct1 const&) { return true; } + bool operator==(struct2 const&, struct2 const&) { return true; } + bool operator==(struct3 const&, struct3 const&) { return true; } + bool operator==(struct4 const&, struct4 const&) { return true; } +} + +int main() { + // This could just be a compile test, but I like to be able to run these + // things. It's probably irrational, but I find it reassuring. + + test::use_types(); } diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 69d0e86d..49f133f2 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -213,7 +213,9 @@ void insert_tests2(X*, test::random_generator generator = test::default_generato X x; test::random_values v(1000, generator); - x.insert(test::input_iterator(v.begin()), test::input_iterator(v.end())); + BOOST_DEDUCED_TYPENAME test::random_values::const_iterator + begin = v.begin(), end = v.end(); + x.insert(test::input_iterator(begin), test::input_iterator(end)); test::check_container(x, v); test::check_equivalent_keys(x); diff --git a/test/unordered/link_test_2.cpp b/test/unordered/link_test_2.cpp index abcf2130..ff6432de 100644 --- a/test/unordered/link_test_2.cpp +++ b/test/unordered/link_test_2.cpp @@ -13,6 +13,15 @@ void foo(boost::unordered_set& x1, boost::unordered_multiset& x3, boost::unordered_multimap& x4) { +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { + boost::unordered_set x1; + boost::unordered_map x2; + boost::unordered_multiset x3; + boost::unordered_multimap x4; + }; +#endif + x1.insert(1); x2[2] = 2; x3.insert(3); From f962857e6846548524945554c79681bef9560e7b Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 30 Dec 2009 22:17:48 +0000 Subject: [PATCH 045/100] Merge unordered. [SVN r58605] --- doc/changes.qbk | 8 + doc/ref.xml | 256 +++++++++++++++++++++ include/boost/unordered/detail/buckets.hpp | 2 +- include/boost/unordered/detail/fwd.hpp | 8 +- include/boost/unordered/detail/table.hpp | 45 +++- include/boost/unordered/unordered_map.hpp | 54 ++++- include/boost/unordered/unordered_set.hpp | 33 ++- test/exception/Jamfile.v2 | 4 +- test/unordered/Jamfile.v2 | 4 +- test/unordered/erase_tests.cpp | 49 ++++ test/unordered/find_tests.cpp | 53 +++++ 11 files changed, 505 insertions(+), 11 deletions(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index d1b26254..fa454d4b 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -107,5 +107,13 @@ First official release. * Support instantiating the containers with incomplete value types. * Reduced the number of warnings (mostly in tests). +* Improved codegear compatibility. +* [@http://svn.boost.org/trac/boost/ticket/3693 Ticket 3693]: + Add `erase_return_void` as a temporary workaround for the current + `erase` which can be inefficient because it has to find the next + element to return an iterator. +* Add templated find overload for compatible keys. +* [@http://svn.boost.org/trac/boost/ticket/3773 Ticket 3773]: + Add missing `std` qualifier to `ptrdiff_t`. [endsect] diff --git a/doc/ref.xml b/doc/ref.xml index 4ca51abf..76d15a1a 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -459,6 +459,15 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Only throws an exception if it is thrown by hasher or key_equal. In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + + + When the number of elements is a lot smaller than the number of buckets + this function can be very inefficient as it has to search through empty + buckets for the next element, in order to return the iterator. + As a temporary workaround, the container has the method + erase_return_void which will be faster. + + @@ -494,6 +503,27 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + + + const_iterator + + iterator + + Erase the element pointed to by position. + + + Only throws an exception if it is thrown by hasher or key_equal. + In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + + + + This is a temporary workaround for the inefficient + erase method. Hopefully, in a future + version the signature of erase will + be changed and this will be deprecated. + + + void @@ -544,8 +574,42 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) key_type const& + const_iterator + + + + + CompatibleKey const& + + + CompatibleHash const& + + + CompatiblePredicate const& + iterator + + + + CompatibleKey const& + + + CompatibleHash const& + + + CompatiblePredicate const& + + const_iterator + An iterator pointing to an element with key equivalent to k, or b.end() if no such element exists. @@ -1252,6 +1316,15 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Only throws an exception if it is thrown by hasher or key_equal. In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + + + When the number of elements is a lot smaller than the number of buckets + this function can be very inefficient as it has to search through empty + buckets for the next element, in order to return the iterator. + As a temporary workaround, the container has the method + erase_return_void which will be faster. + + @@ -1287,6 +1360,27 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + + + const_iterator + + iterator + + Erase the element pointed to by position. + + + Only throws an exception if it is thrown by hasher or key_equal. + In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + + + + This is a temporary workaround for the inefficient + erase method. Hopefully, in a future + version the signature of erase will + be changed and this will be deprecated. + + + void @@ -1337,8 +1431,42 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) key_type const& + const_iterator + + + + + CompatibleKey const& + + + CompatibleHash const& + + + CompatiblePredicate const& + iterator + + + + CompatibleKey const& + + + CompatibleHash const& + + + CompatiblePredicate const& + + const_iterator + An iterator pointing to an element with key equivalent to k, or b.end() if no such element exists. @@ -2059,6 +2187,15 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Only throws an exception if it is thrown by hasher or key_equal. In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + + + When the number of elements is a lot smaller than the number of buckets + this function can be very inefficient as it has to search through empty + buckets for the next element, in order to return the iterator. + As a temporary workaround, the container has the method + erase_return_void which will be faster. + + @@ -2094,6 +2231,27 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + + + const_iterator + + iterator + + Erase the element pointed to by position. + + + Only throws an exception if it is thrown by hasher or key_equal. + In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + + + + This is a temporary workaround for the inefficient + erase method. Hopefully, in a future + version the signature of erase will + be changed and this will be deprecated. + + + void @@ -2144,8 +2302,42 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) key_type const& + const_iterator + + + + + CompatibleKey const& + + + CompatibleHash const& + + + CompatiblePredicate const& + iterator + + + + CompatibleKey const& + + + CompatibleHash const& + + + CompatiblePredicate const& + + const_iterator + An iterator pointing to an element with key equivalent to k, or b.end() if no such element exists. @@ -2901,6 +3093,15 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Only throws an exception if it is thrown by hasher or key_equal. In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + + + When the number of elements is a lot smaller than the number of buckets + this function can be very inefficient as it has to search through empty + buckets for the next element, in order to return the iterator. + As a temporary workaround, the container has the method + erase_return_void which will be faster. + + @@ -2936,6 +3137,27 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + + + const_iterator + + iterator + + Erase the element pointed to by position. + + + Only throws an exception if it is thrown by hasher or key_equal. + In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + + + + This is a temporary workaround for the inefficient + erase method. Hopefully, in a future + version the signature of erase will + be changed and this will be deprecated. + + + void @@ -2986,8 +3208,42 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) key_type const& + const_iterator + + + + + CompatibleKey const& + + + CompatibleHash const& + + + CompatiblePredicate const& + iterator + + + + CompatibleKey const& + + + CompatibleHash const& + + + CompatiblePredicate const& + + const_iterator + An iterator pointing to an element with key equivalent to k, or b.end() if no such element exists. diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index c4b8a898..b1dee5cf 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -148,7 +148,7 @@ namespace boost { namespace unordered_detail { // Set up the sentinel (node_ptr cast) bucket_ptr sentinel = constructor.get() + - static_cast(this->bucket_count_); + static_cast(this->bucket_count_); sentinel->next_ = sentinel; // Only release the buckets once everything is successfully diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index ff3d63e9..ab028710 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -466,6 +466,9 @@ namespace boost { namespace unordered_detail { return extractor::extract(node::get_value(n)); } bool equal(key_type const& k, value_type const& v) const; + template + node_ptr find_iterator(bucket_ptr bucket, Key const& k, + Pred const&) const; node_ptr find_iterator(bucket_ptr bucket, key_type const& k) const; node_ptr find_iterator(key_type const& k) const; node_ptr* find_for_erase(bucket_ptr bucket, key_type const& k) const; @@ -523,6 +526,8 @@ namespace boost { namespace unordered_detail { std::size_t count(key_type const& k) const; iterator_base find(key_type const& k) const; + template + iterator_base find(Key const& k, Hash const& h, Pred const& eq) const; value_type& at(key_type const& k) const; iterator_pair equal_range(key_type const& k) const; @@ -532,7 +537,8 @@ namespace boost { namespace unordered_detail { void clear(); std::size_t erase_key(key_type const& k); - iterator_base erase(iterator_base r); + iterator_base erase_return_iterator(iterator_base r); + void erase(iterator_base r); std::size_t erase_group(node_ptr* it, bucket_ptr bucket); iterator_base erase_range(iterator_base r1, iterator_base r2); diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 2f4e5ebd..198548d3 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -28,6 +28,23 @@ namespace boost { namespace unordered_detail { return this->key_eq()(k, get_key(v)); } + // strong exception safety, no side effects + template + template + inline BOOST_DEDUCED_TYPENAME T::node_ptr + hash_table::find_iterator(bucket_ptr bucket, Key const& k, + Pred const& eq) const + { + node_ptr it = bucket->next_; + while (BOOST_UNORDERED_BORLAND_BOOL(it) && + !eq(k, get_key(node::get_value(it)))) + { + it = node::next_group(it); + } + + return it; + } + // strong exception safety, no side effects template inline BOOST_DEDUCED_TYPENAME T::node_ptr @@ -570,6 +587,22 @@ namespace boost { namespace unordered_detail { return this->end(); } + template + template + BOOST_DEDUCED_TYPENAME T::iterator_base hash_table::find(Key const& k, + Hash const& h, Pred const& eq) const + { + if(!this->size_) return this->end(); + + bucket_ptr bucket = this->get_bucket(h(k) % this->bucket_count_); + node_ptr it = find_iterator(bucket, k, eq); + + if (BOOST_UNORDERED_BORLAND_BOOL(it)) + return iterator_base(bucket, it); + else + return this->end(); + } + template BOOST_DEDUCED_TYPENAME T::value_type& hash_table::at(key_type const& k) const @@ -652,10 +685,20 @@ namespace boost { namespace unordered_detail { return *it ? this->erase_group(it, bucket) : 0; } + template + void hash_table::erase(iterator_base r) + { + BOOST_ASSERT(r.node_); + --this->size_; + node::unlink_node(*r.bucket_, r.node_); + this->delete_node(r.node_); + // r has been invalidated but its bucket is still valid + this->recompute_begin_bucket(r.bucket_); + } template BOOST_DEDUCED_TYPENAME T::iterator_base - hash_table::erase(iterator_base r) + hash_table::erase_return_iterator(iterator_base r) { BOOST_ASSERT(r.node_); iterator_base next = r; diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index ef649897..58ca3014 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -355,7 +355,7 @@ namespace boost iterator erase(const_iterator position) { - return iterator(table_.erase(get(position))); + return iterator(table_.erase_return_iterator(get(position))); } size_type erase(const key_type& k) @@ -368,6 +368,11 @@ namespace boost return iterator(table_.erase_range(get(first), get(last))); } + void erase_return_void(const_iterator position) + { + table_.erase(get(position)); + } + void clear() { table_.clear(); @@ -417,6 +422,26 @@ namespace boost return const_iterator(table_.find(k)); } + template + iterator find( + CompatibleKey const& k, + CompatibleHash const& hash, + CompatiblePredicate const& eq) + { + return iterator(table_.find(k, hash, eq)); + } + + template + const_iterator find( + CompatibleKey const& k, + CompatibleHash const& hash, + CompatiblePredicate const& eq) const + { + return iterator(table_.find(k, hash, eq)); + } + size_type count(const key_type& k) const { return table_.count(k); @@ -868,7 +893,7 @@ namespace boost iterator erase(const_iterator position) { - return iterator(table_.erase(get(position))); + return iterator(table_.erase_return_iterator(get(position))); } size_type erase(const key_type& k) @@ -881,6 +906,11 @@ namespace boost return iterator(table_.erase_range(get(first), get(last))); } + void erase_return_void(const_iterator position) + { + table_.erase(get(position)); + } + void clear() { table_.clear(); @@ -915,6 +945,26 @@ namespace boost return const_iterator(table_.find(k)); } + template + iterator find( + CompatibleKey const& k, + CompatibleHash const& hash, + CompatiblePredicate const& eq) + { + return iterator(table_.find(k, hash, eq)); + } + + template + const_iterator find( + CompatibleKey const& k, + CompatibleHash const& hash, + CompatiblePredicate const& eq) const + { + return iterator(table_.find(k, hash, eq)); + } + size_type count(const key_type& k) const { return table_.count(k); diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 59843fd6..87c1011b 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -348,7 +348,7 @@ namespace boost iterator erase(const_iterator position) { - return iterator(table_.erase(get(position))); + return iterator(table_.erase_return_iterator(get(position))); } size_type erase(const key_type& k) @@ -361,6 +361,11 @@ namespace boost return iterator(table_.erase_range(get(first), get(last))); } + void erase_return_void(const_iterator position) + { + table_.erase(get(position)); + } + void clear() { table_.clear(); @@ -390,6 +395,15 @@ namespace boost return const_iterator(table_.find(k)); } + template + const_iterator find( + CompatibleKey const& k, + CompatibleHash const& hash, + CompatiblePredicate const& eq) const + { + return iterator(table_.find(k, hash, eq)); + } size_type count(const key_type& k) const { return table_.count(k); @@ -822,7 +836,7 @@ namespace boost iterator erase(const_iterator position) { - return iterator(table_.erase(get(position))); + return iterator(table_.erase_return_iterator(get(position))); } size_type erase(const key_type& k) @@ -835,6 +849,11 @@ namespace boost return iterator(table_.erase_range(get(first), get(last))); } + void erase_return_void(const_iterator position) + { + table_.erase(get(position)); + } + void clear() { table_.clear(); @@ -864,6 +883,16 @@ namespace boost return const_iterator(table_.find(k)); } + template + const_iterator find( + CompatibleKey const& k, + CompatibleHash const& hash, + CompatiblePredicate const& eq) const + { + return iterator(table_.find(k, hash, eq)); + } + size_type count(const key_type& k) const { return table_.count(k); diff --git a/test/exception/Jamfile.v2 b/test/exception/Jamfile.v2 index 3fc78437..cc0ec8e8 100644 --- a/test/exception/Jamfile.v2 +++ b/test/exception/Jamfile.v2 @@ -17,8 +17,8 @@ project unordered-test/exception-tests gcc:_GLIBCXX_DEBUG darwin:_GLIBCXX_DEBUG msvc:on - gcc:on - darwin:on + #gcc:on + #darwin:on ; test-suite unordered-exception diff --git a/test/unordered/Jamfile.v2 b/test/unordered/Jamfile.v2 index 2fdfd357..9454d206 100644 --- a/test/unordered/Jamfile.v2 +++ b/test/unordered/Jamfile.v2 @@ -14,8 +14,8 @@ project unordered-test/unordered gcc:_GLIBCXX_DEBUG darwin:_GLIBCXX_DEBUG msvc:on - gcc:on - darwin:on + #gcc:on + #darwin:on ; test-suite unordered diff --git a/test/unordered/erase_tests.cpp b/test/unordered/erase_tests.cpp index eab22f4c..1bc6e4c6 100644 --- a/test/unordered/erase_tests.cpp +++ b/test/unordered/erase_tests.cpp @@ -112,6 +112,55 @@ void erase_tests1(Container*, test::random_generator generator = test::default_g BOOST_TEST(x.erase(x.begin(), x.end()) == x.begin()); } + std::cerr<<"erase_return_void(begin()).\n"; + { + test::random_values v(1000, generator); + Container x(v.begin(), v.end()); + std::size_t size = x.size(); + while(size > 0 && !x.empty()) + { + BOOST_DEDUCED_TYPENAME Container::key_type key = test::get_key(*x.begin()); + std::size_t count = x.count(key); + x.erase_return_void(x.begin()); + --size; + BOOST_TEST(x.count(key) == count - 1); + BOOST_TEST(x.size() == size); + } + BOOST_TEST(x.empty()); + } + + std::cerr<<"erase_return_void(random position).\n"; + { + test::random_values v(1000, generator); + Container x(v.begin(), v.end()); + std::size_t size = x.size(); + while(size > 0 && !x.empty()) + { + using namespace std; + int index = rand() % (int) x.size(); + BOOST_DEDUCED_TYPENAME Container::const_iterator prev, pos, next; + if(index == 0) { + prev = pos = x.begin(); + } + else { + prev = boost::next(x.begin(), index - 1); + pos = boost::next(prev); + } + next = boost::next(pos); + BOOST_DEDUCED_TYPENAME Container::key_type key = test::get_key(*pos); + std::size_t count = x.count(key); + x.erase_return_void(pos); + --size; + if(size > 0) + BOOST_TEST(index == 0 ? next == x.begin() : + next == boost::next(prev)); + BOOST_TEST(x.count(key) == count - 1); + BOOST_TEST(x.size() == size); + } + BOOST_TEST(x.empty()); + } + + std::cerr<<"clear().\n"; { test::random_values v(500, generator); diff --git a/test/unordered/find_tests.cpp b/test/unordered/find_tests.cpp index 24523fd3..e823a04d 100644 --- a/test/unordered/find_tests.cpp +++ b/test/unordered/find_tests.cpp @@ -83,6 +83,55 @@ void find_tests1(X*, test::random_generator generator = test::default_generator) } } +struct compatible_key +{ + test::object o_; + + compatible_key(test::object const& o) : o_(o) {} +}; + +struct compatible_hash +{ + test::hash hash_; + + std::size_t operator()(compatible_key const& k) const { + return hash_(k.o_); + } +}; + +struct compatible_predicate +{ + test::equal_to equal_; + + bool operator()(compatible_key const& k1, compatible_key const& k2) const { + return equal_(k1.o_, k2.o_); + } +}; + +template +void find_compatible_keys_test(X*, test::random_generator generator = test::default_generator) +{ + typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; + typedef BOOST_DEDUCED_TYPENAME test::random_values::iterator value_iterator; + test::random_values v(500, generator); + X x(v.begin(), v.end()); + + compatible_hash h; + compatible_predicate eq; + + for(value_iterator it = v.begin(), end = v.end(); it != end; ++it) { + BOOST_DEDUCED_TYPENAME X::key_type key = test::get_key(*it); + BOOST_TEST(x.find(key) == x.find(compatible_key(key), h, eq)); + } + + test::random_values v2(20, generator); + + for(value_iterator it = v2.begin(), end = v2.end(); it != end; ++it) { + BOOST_DEDUCED_TYPENAME X::key_type key = test::get_key(*it); + BOOST_TEST(x.find(key) == x.find(compatible_key(key), h, eq)); + } +} + boost::unordered_set >* test_set; boost::unordered_multiset >* test_multiset; boost::unordered_map >* test_map; @@ -95,6 +144,10 @@ UNORDERED_TEST(find_tests1, ((test_set)(test_multiset)(test_map)(test_multimap)) ((default_generator)(generate_collisions)) ) +UNORDERED_TEST(find_compatible_keys_test, + ((test_set)(test_multiset)(test_map)(test_multimap)) + ((default_generator)(generate_collisions)) +) } From aa0e8eedd2addca08385c8870f778e5c58227004 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 8 Jan 2010 05:39:54 +0000 Subject: [PATCH 046/100] Merge unordered changes. [SVN r58802] --- examples/fnv1.hpp | 9 +- include/boost/unordered/detail/fwd.hpp | 6 +- include/boost/unordered/detail/unique.hpp | 4 +- include/boost/unordered/unordered_map.hpp | 3 +- test/exception/assign_exception_tests.cpp | 12 +- .../exception/constructor_exception_tests.cpp | 16 ++- test/exception/erase_exception_tests.cpp | 3 +- test/exception/insert_exception_tests.cpp | 28 +++-- test/exception/rehash_exception_tests.cpp | 4 +- test/helpers/count.hpp | 11 +- test/helpers/equivalent.hpp | 8 +- test/helpers/exception_test.hpp | 88 ++++++++------ test/helpers/helpers.hpp | 6 +- test/helpers/invariants.hpp | 20 ++-- test/helpers/list.hpp | 29 ++++- test/helpers/memory.hpp | 26 +++-- test/helpers/prefix.hpp | 3 +- test/helpers/random_values.hpp | 4 +- test/helpers/test.hpp | 53 +++++---- test/helpers/tracker.hpp | 67 +++++++---- test/objects/minimal.hpp | 65 ++++++++--- test/objects/test.hpp | 40 +++++-- test/unordered/assign_tests.cpp | 22 +++- test/unordered/bucket_tests.cpp | 34 ++++-- test/unordered/compile_tests.hpp | 107 +++++++++++++----- test/unordered/constructor_tests.cpp | 38 +++++-- test/unordered/copy_tests.cpp | 22 +++- test/unordered/equality_tests.cpp | 51 +++++---- test/unordered/equivalent_keys_tests.cpp | 23 ++-- test/unordered/erase_equiv_tests.cpp | 3 +- test/unordered/erase_tests.cpp | 38 +++++-- test/unordered/find_tests.cpp | 25 ++-- test/unordered/fwd_set_test.cpp | 3 +- test/unordered/incomplete_test.cpp | 31 +++-- test/unordered/insert_stable_tests.cpp | 10 +- test/unordered/insert_tests.cpp | 95 +++++++++++----- test/unordered/load_factor_tests.cpp | 3 +- test/unordered/move_tests.cpp | 28 +++-- test/unordered/rehash_tests.cpp | 12 +- test/unordered/simple_tests.cpp | 3 +- test/unordered/swap_tests.cpp | 28 +++-- test/unordered/unnecessary_copy_tests.cpp | 40 ++++--- 42 files changed, 761 insertions(+), 360 deletions(-) diff --git a/examples/fnv1.hpp b/examples/fnv1.hpp index 03afc292..3337d136 100644 --- a/examples/fnv1.hpp +++ b/examples/fnv1.hpp @@ -55,11 +55,14 @@ namespace hash // For 128 bit machines: // const std::size_t fnv_prime = 309485009821345068724781401u; - // const std::size_t fnv_offset_basis = 275519064689413815358837431229664493455u; + // const std::size_t fnv_offset_basis = + // 275519064689413815358837431229664493455u; // For 256 bit machines: - // const std::size_t fnv_prime = 374144419156711147060143317175368453031918731002211u; - // const std::size_t fnv_offset_basis = 100029257958052580907070968620625704837092796014241193945225284501741471925557u; + // const std::size_t fnv_prime = + // 374144419156711147060143317175368453031918731002211u; + // const std::size_t fnv_offset_basis = + // 100029257958052580907070968620625704837092796014241193945225284501741471925557u; typedef basic_fnv_1 fnv_1; typedef basic_fnv_1a fnv_1a; diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index ab028710..1598cdb0 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -270,7 +270,8 @@ namespace boost { namespace unordered_detail { typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; typedef BOOST_DEDUCED_TYPENAME iterator_base::node node; - typedef BOOST_DEDUCED_TYPENAME bucket::bucket_allocator bucket_allocator; + typedef BOOST_DEDUCED_TYPENAME bucket::bucket_allocator + bucket_allocator; typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr; typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr; @@ -973,7 +974,8 @@ namespace boost { namespace unordered_detail { typedef E extractor; typedef G group_type; - typedef hash_node_constructor node_constructor; + typedef hash_node_constructor + node_constructor; typedef hash_buckets buckets; typedef hash_buffered_functions buffered_functions; diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index 79ba28e6..59920d00 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -323,8 +323,8 @@ namespace boost { namespace unordered_detail { do { // No side effects in this initial code - // Note: can't use get_key as '*i' might not be value_type - it could - // be a pair with first_types as key_type without const or a + // Note: can't use get_key as '*i' might not be value_type - it + // could be a pair with first_types as key_type without const or a // different second_type. key_type const& k = extractor::extract(*i); std::size_t hash_value = this->hash_function()(k); diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 58ca3014..93e19789 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -291,7 +291,8 @@ namespace boost table_.emplace(v)); } - iterator emplace_hint(const_iterator, value_type const& v = value_type()) + iterator emplace_hint(const_iterator, + value_type const& v = value_type()) { return iterator(table_.emplace(v).first); } diff --git a/test/exception/assign_exception_tests.cpp b/test/exception/assign_exception_tests.cpp index bdb99c15..8e64efeb 100644 --- a/test/exception/assign_exception_tests.cpp +++ b/test/exception/assign_exception_tests.cpp @@ -47,10 +47,14 @@ struct assign_base : public test::exception_base typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal; typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type; - assign_base(unsigned int count1, unsigned int count2, int tag1, int tag2) - : x_values(count1), y_values(count2), - x(x_values.begin(), x_values.end(), 0, hasher(tag1), key_equal(tag1), allocator_type(tag1)), - y(y_values.begin(), y_values.end(), 0, hasher(tag2), key_equal(tag2), allocator_type(tag2)) {} + assign_base(unsigned int count1, unsigned int count2, int tag1, int tag2) : + x_values(count1), + y_values(count2), + x(x_values.begin(), x_values.end(), 0, hasher(tag1), key_equal(tag1), + allocator_type(tag1)), + y(y_values.begin(), y_values.end(), 0, hasher(tag2), key_equal(tag2), + allocator_type(tag2)) + {} typedef T data_type; T init() const { return T(x); } diff --git a/test/exception/constructor_exception_tests.cpp b/test/exception/constructor_exception_tests.cpp index 1b95af7d..ef3119e4 100644 --- a/test/exception/constructor_exception_tests.cpp +++ b/test/exception/constructor_exception_tests.cpp @@ -116,7 +116,8 @@ struct range_construct_test5 : public range, objects range_construct_test5() : range(60) {} void run() const { - T x(this->values.begin(), this->values.end(), 0, hash, equal_to, allocator); + T x(this->values.begin(), this->values.end(), 0, + hash, equal_to, allocator); } }; @@ -134,7 +135,16 @@ struct input_range_construct_test : public range, objects }; RUN_EXCEPTION_TESTS( - (construct_test1)(construct_test2)(construct_test3)(construct_test4)(construct_test5)(construct_test6) - (range_construct_test1)(range_construct_test2)(range_construct_test3)(range_construct_test4)(range_construct_test5) + (construct_test1) + (construct_test2) + (construct_test3) + (construct_test4) + (construct_test5) + (construct_test6) + (range_construct_test1) + (range_construct_test2) + (range_construct_test3) + (range_construct_test4) + (range_construct_test5) (input_range_construct_test), CONTAINER_SEQ) diff --git a/test/exception/erase_exception_tests.cpp b/test/exception/erase_exception_tests.cpp index 9718e9d3..f6eb5b42 100644 --- a/test/exception/erase_exception_tests.cpp +++ b/test/exception/erase_exception_tests.cpp @@ -40,7 +40,8 @@ struct erase_by_key_test1 : public erase_test_base { void run(T& x) const { - typedef BOOST_DEDUCED_TYPENAME test::random_values::const_iterator iterator; + typedef BOOST_DEDUCED_TYPENAME + test::random_values::const_iterator iterator; for(iterator it = this->values.begin(), end = this->values.end(); it != end; ++it) diff --git a/test/exception/insert_exception_tests.cpp b/test/exception/insert_exception_tests.cpp index 946fe036..85776241 100644 --- a/test/exception/insert_exception_tests.cpp +++ b/test/exception/insert_exception_tests.cpp @@ -28,7 +28,9 @@ struct insert_test_base : public test::exception_base return T(); } - void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x, strong_type const& strong) const { + void check BOOST_PREVENT_MACRO_SUBSTITUTION( + T const& x, strong_type const& strong) const + { std::string scope(test::scope); if(scope.find("hash::operator()") == std::string::npos) @@ -46,7 +48,8 @@ struct emplace_test1 : public insert_test_base void run(T& x, strong_type& strong) const { for(BOOST_DEDUCED_TYPENAME test::random_values::const_iterator - it = this->values.begin(), end = this->values.end(); it != end; ++it) + it = this->values.begin(), end = this->values.end(); + it != end; ++it) { strong.store(x, test::exception::detail::tracker.count_allocations); x.emplace(*it); @@ -63,7 +66,8 @@ struct insert_test1 : public insert_test_base void run(T& x, strong_type& strong) const { for(BOOST_DEDUCED_TYPENAME test::random_values::const_iterator - it = this->values.begin(), end = this->values.end(); it != end; ++it) + it = this->values.begin(), end = this->values.end(); + it != end; ++it) { strong.store(x, test::exception::detail::tracker.count_allocations); x.insert(*it); @@ -78,7 +82,8 @@ struct insert_test2 : public insert_test_base void run(T& x, strong_type& strong) const { for(BOOST_DEDUCED_TYPENAME test::random_values::const_iterator - it = this->values.begin(), end = this->values.end(); it != end; ++it) + it = this->values.begin(), end = this->values.end(); + it != end; ++it) { strong.store(x, test::exception::detail::tracker.count_allocations); x.insert(x.begin(), *it); @@ -105,7 +110,8 @@ struct insert_test4 : public insert_test_base void run(T& x, strong_type& strong) const { for(BOOST_DEDUCED_TYPENAME test::random_values::const_iterator - it = this->values.begin(), end = this->values.end(); it != end; ++it) + it = this->values.begin(), end = this->values.end(); + it != end; ++it) { strong.store(x, test::exception::detail::tracker.count_allocations); x.insert(it, boost::next(it)); @@ -142,7 +148,8 @@ struct insert_test_rehash1 : public insert_test_base BOOST_DEDUCED_TYPENAME T::const_iterator pos = x.cbegin(); for(BOOST_DEDUCED_TYPENAME test::random_values::const_iterator - it = boost::next(this->values.begin(), x.size()), end = this->values.end(); + it = boost::next(this->values.begin(), x.size()), + end = this->values.end(); it != end && count < 10; ++it, ++count) { strong.store(x, test::exception::detail::tracker.count_allocations); @@ -165,7 +172,8 @@ struct insert_test_rehash2 : public insert_test_rehash1 int count = 0; for(BOOST_DEDUCED_TYPENAME test::random_values::const_iterator - it = boost::next(this->values.begin(), x.size()), end = this->values.end(); + it = boost::next(this->values.begin(), x.size()), + end = this->values.end(); it != end && count < 10; ++it, ++count) { strong.store(x, test::exception::detail::tracker.count_allocations); @@ -181,7 +189,8 @@ struct insert_test_rehash2 : public insert_test_rehash1 template struct insert_test_rehash3 : public insert_test_base { - BOOST_DEDUCED_TYPENAME T::size_type mutable rehash_bucket_count, original_bucket_count; + BOOST_DEDUCED_TYPENAME T::size_type mutable + rehash_bucket_count, original_bucket_count; insert_test_rehash3() : insert_test_base(1000) {} @@ -196,7 +205,8 @@ struct insert_test_rehash3 : public insert_test_base rehash_bucket_count = static_cast( ceil(original_bucket_count * (double) x.max_load_factor())) - 1; - size_type initial_elements = rehash_bucket_count > 5 ? rehash_bucket_count - 5 : 1; + size_type initial_elements = + rehash_bucket_count > 5 ? rehash_bucket_count - 5 : 1; BOOST_TEST(initial_elements < this->values.size()); x.insert(this->values.begin(), diff --git a/test/exception/rehash_exception_tests.cpp b/test/exception/rehash_exception_tests.cpp index 03f49ce8..2de210f5 100644 --- a/test/exception/rehash_exception_tests.cpp +++ b/test/exception/rehash_exception_tests.cpp @@ -20,7 +20,9 @@ struct rehash_test_base : public test::exception_base { test::random_values values; unsigned int n; - rehash_test_base(unsigned int count = 100, unsigned int n = 0) : values(count), n(n) {} + rehash_test_base(unsigned int count = 100, unsigned int n = 0) + : values(count), n(n) + {} typedef T data_type; typedef test::strong strong_type; diff --git a/test/helpers/count.hpp b/test/helpers/count.hpp index 0589586e..ff2bb830 100644 --- a/test/helpers/count.hpp +++ b/test/helpers/count.hpp @@ -39,8 +39,15 @@ namespace test { return !(*this == x); } - friend std::ostream& operator<<(std::ostream& out, object_count const& c) { - out<<"[instances: "< - bool equivalent_impl(boost::hash const&, boost::hash const&, derived_type) { + bool equivalent_impl(boost::hash const&, boost::hash const&, + derived_type) + { return true; } template - bool equivalent_impl(std::equal_to const&, std::equal_to const&, derived_type) { + bool equivalent_impl(std::equal_to const&, std::equal_to const&, + derived_type) + { return true; } diff --git a/test/helpers/exception_test.hpp b/test/helpers/exception_test.hpp index a66c30aa..1e7ae248 100644 --- a/test/helpers/exception_test.hpp +++ b/test/helpers/exception_test.hpp @@ -12,44 +12,50 @@ #include #include -# define UNORDERED_EXCEPTION_TEST_CASE(name, test_func, type) \ - UNORDERED_AUTO_TEST(name) \ - { \ - test_func< type > fixture; \ - ::test::lightweight::exception_safety(fixture, BOOST_STRINGIZE(test_func)); \ - } +# define UNORDERED_EXCEPTION_TEST_CASE(name, test_func, type) \ + UNORDERED_AUTO_TEST(name) \ + { \ + test_func< type > fixture; \ + ::test::lightweight::exception_safety( \ + fixture, BOOST_STRINGIZE(test_func)); \ + } \ + # define UNORDERED_EPOINT_IMPL ::test::lightweight::epoint #define UNORDERED_EXCEPTION_TEST_POSTFIX RUN_TESTS() -#define RUN_EXCEPTION_TESTS(test_seq, param_seq) \ - BOOST_PP_SEQ_FOR_EACH_PRODUCT(RUN_EXCEPTION_TESTS_OP, (test_seq)(param_seq)) \ - RUN_TESTS() +#define RUN_EXCEPTION_TESTS(test_seq, param_seq) \ + BOOST_PP_SEQ_FOR_EACH_PRODUCT(RUN_EXCEPTION_TESTS_OP, \ + (test_seq)(param_seq)) \ + RUN_TESTS() \ -#define RUN_EXCEPTION_TESTS_OP(r, product) \ - UNORDERED_EXCEPTION_TEST_CASE( \ - BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(0, product), \ - BOOST_PP_CAT(_, BOOST_PP_SEQ_ELEM(1, product)) \ - ), \ - BOOST_PP_SEQ_ELEM(0, product), \ - BOOST_PP_SEQ_ELEM(1, product) \ - ) +#define RUN_EXCEPTION_TESTS_OP(r, product) \ + UNORDERED_EXCEPTION_TEST_CASE( \ + BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(0, product), \ + BOOST_PP_CAT(_, BOOST_PP_SEQ_ELEM(1, product)) \ + ), \ + BOOST_PP_SEQ_ELEM(0, product), \ + BOOST_PP_SEQ_ELEM(1, product) \ + ) \ -#define UNORDERED_SCOPE(scope_name) \ - for(::test::scope_guard unordered_test_guard( \ - BOOST_STRINGIZE(scope_name)); \ - !unordered_test_guard.dismissed(); \ - unordered_test_guard.dismiss()) +#define UNORDERED_SCOPE(scope_name) \ + for(::test::scope_guard unordered_test_guard( \ + BOOST_STRINGIZE(scope_name)); \ + !unordered_test_guard.dismissed(); \ + unordered_test_guard.dismiss()) \ -#define UNORDERED_EPOINT(name) \ - if(::test::exceptions_enabled) { \ - UNORDERED_EPOINT_IMPL(name); \ - } +#define UNORDERED_EPOINT(name) \ + if(::test::exceptions_enabled) { \ + UNORDERED_EPOINT_IMPL(name); \ + } \ -#define ENABLE_EXCEPTIONS \ - ::test::exceptions_enable BOOST_PP_CAT(ENABLE_EXCEPTIONS_, __LINE__)(true) -#define DISABLE_EXCEPTIONS \ - ::test::exceptions_enable BOOST_PP_CAT(ENABLE_EXCEPTIONS_, __LINE__)(false) +#define ENABLE_EXCEPTIONS \ + ::test::exceptions_enable BOOST_PP_CAT( \ + ENABLE_EXCEPTIONS_, __LINE__)(true) \ + +#define DISABLE_EXCEPTIONS \ + ::test::exceptions_enable BOOST_PP_CAT( \ + ENABLE_EXCEPTIONS_, __LINE__)(false) \ namespace test { static char const* scope = ""; @@ -114,21 +120,24 @@ namespace test { }; template - inline void call_ignore_extra_parameters(void (T::*fn)() const, T2 const& obj, + inline void call_ignore_extra_parameters( + void (T::*fn)() const, T2 const& obj, P1&, P2&) { (obj.*fn)(); } template - inline void call_ignore_extra_parameters(void (T::*fn)(P1&) const, T2 const& obj, + inline void call_ignore_extra_parameters( + void (T::*fn)(P1&) const, T2 const& obj, P1& p1, P2&) { (obj.*fn)(p1); } template - inline void call_ignore_extra_parameters(void (T::*fn)(P1&, P2&) const, T2 const& obj, + inline void call_ignore_extra_parameters( + void (T::*fn)(P1&, P2&) const, T2 const& obj, P1& p1, P2& p2) { (obj.*fn)(p1, p2); @@ -156,11 +165,18 @@ namespace test { strong.store(x); try { ENABLE_EXCEPTIONS; - call_ignore_extra_parameters(&Test::run, test_, x, strong); + call_ignore_extra_parameters< + Test, + BOOST_DEDUCED_TYPENAME Test::data_type, + BOOST_DEDUCED_TYPENAME Test::strong_type + >(&Test::run, test_, x, strong); } catch(...) { - call_ignore_extra_parameters(&Test::check, test_, - constant(x), constant(strong)); + call_ignore_extra_parameters< + Test, + BOOST_DEDUCED_TYPENAME Test::data_type const, + BOOST_DEDUCED_TYPENAME Test::strong_type const + >(&Test::check, test_, constant(x), constant(strong)); throw; } } diff --git a/test/helpers/helpers.hpp b/test/helpers/helpers.hpp index 79132c4d..2293f23f 100644 --- a/test/helpers/helpers.hpp +++ b/test/helpers/helpers.hpp @@ -19,13 +19,15 @@ namespace test } template - static key_type const& get_key(std::pair const& x, char = 0) + static key_type const& get_key( + std::pair const& x, char = 0) { return x.first; } template - static key_type const& get_key(std::pair const& x, unsigned char = 0) + static key_type const& get_key(std::pair const& x, + unsigned char = 0) { return x.first; } diff --git a/test/helpers/invariants.hpp b/test/helpers/invariants.hpp index 1e14d685..a83d76be 100644 --- a/test/helpers/invariants.hpp +++ b/test/helpers/invariants.hpp @@ -17,8 +17,9 @@ #if defined(BOOST_MSVC) #pragma warning(push) -#pragma warning(disable:4127) // conditional expression is constant -#pragma warning(disable:4267) // conversion from 'size_t' to 'unsigned int', possible loss of data +#pragma warning(disable:4127) // conditional expression is constant +#pragma warning(disable:4267) // conversion from 'size_t' to 'unsigned int', + // possible loss of data #endif namespace test @@ -30,9 +31,11 @@ namespace test typedef BOOST_DEDUCED_TYPENAME X::key_type key_type; // Boost.Test was reporting memory leaks for std::set on g++-3.3. // So I work around it by using malloc. - std::set, test::malloc_allocator > found_; + std::set, + test::malloc_allocator > found_; - BOOST_DEDUCED_TYPENAME X::const_iterator it = x1.begin(), end = x1.end(); + BOOST_DEDUCED_TYPENAME X::const_iterator + it = x1.begin(), end = x1.end(); BOOST_DEDUCED_TYPENAME X::size_type size = 0; while(it != end) { // First test that the current key has not occured before, required @@ -72,7 +75,8 @@ namespace test // // Check that the keys are in the correct bucket and are // // adjacent in the bucket. // BOOST_DEDUCED_TYPENAME X::size_type bucket = x1.bucket(key); - // BOOST_DEDUCED_TYPENAME X::const_local_iterator lit = x1.begin(bucket), lend = x1.end(bucket); + // BOOST_DEDUCED_TYPENAME X::const_local_iterator + // lit = x1.begin(bucket), lend = x1.end(bucket); // for(; lit != lend && !eq(get_key(*lit), key); ++lit) continue; // if(lit == lend) // BOOST_ERROR("Unable to find element with a local_iterator"); @@ -82,7 +86,8 @@ namespace test // BOOST_ERROR("Element count doesn't match local_iterator."); // for(; lit != lend; ++lit) { // if(eq(get_key(*lit), key)) { - // BOOST_ERROR("Non-adjacent element with equivalent key in bucket."); + // BOOST_ERROR("Non-adjacent element with equivalent key " + // "in bucket."); // break; // } // } @@ -91,7 +96,8 @@ namespace test // Finally, check that size matches up. if(x1.size() != size) BOOST_ERROR("x1.size() doesn't match actual size."); - float load_factor = static_cast(size) / static_cast(x1.bucket_count()); + float load_factor = + static_cast(size) / static_cast(x1.bucket_count()); using namespace std; if(fabs(x1.load_factor() - load_factor) > x1.load_factor() / 64) BOOST_ERROR("x1.load_factor() doesn't match actual load_factor."); diff --git a/test/helpers/list.hpp b/test/helpers/list.hpp index 3b59ce3e..ebb37b8f 100644 --- a/test/helpers/list.hpp +++ b/test/helpers/list.hpp @@ -126,12 +126,29 @@ namespace test T const& operator*() const { return ptr_->value_; } T const* operator->() const { return &ptr_->value_; } - list_const_iterator& operator++() { - ptr_ = ptr_->next_; return *this; } - list_const_iterator operator++(int) { - list_const_iterator tmp = *this; ptr_ = ptr_->next_; return tmp; } - bool operator==(const_iterator y) const { return ptr_ == y.ptr_; } - bool operator!=(const_iterator y) const { return ptr_ != y.ptr_; } + + list_const_iterator& operator++() + { + ptr_ = ptr_->next_; + return *this; + } + + list_const_iterator operator++(int) + { + list_const_iterator tmp = *this; + ptr_ = ptr_->next_; + return tmp; + } + + bool operator==(const_iterator y) const + { + return ptr_ == y.ptr_; + } + + bool operator!=(const_iterator y) const + { + return ptr_ != y.ptr_; + } }; } diff --git a/test/helpers/memory.hpp b/test/helpers/memory.hpp index 6dbec85f..84c1787b 100644 --- a/test/helpers/memory.hpp +++ b/test/helpers/memory.hpp @@ -62,7 +62,8 @@ namespace test #if defined(BOOST_MPL_CFG_MSVC_ETI_BUG) template <> struct allocator_memory_type_gen { - typedef std::map type; + typedef std::map + type; }; #endif @@ -73,7 +74,8 @@ namespace test std::pair >::type allocator_type; - typedef BOOST_DEDUCED_TYPENAME allocator_memory_type_gen::type + typedef BOOST_DEDUCED_TYPENAME + allocator_memory_type_gen::type allocated_memory_type; allocated_memory_type allocated_memory; @@ -106,7 +108,8 @@ namespace test bool no_constructions_left = (count_constructions == 0); bool allocated_memory_empty = allocated_memory.empty(); - // Clearing the data before the checks terminate the tests. + // Clearing the data before the checks terminate the + // tests. count_allocations = 0; count_constructions = 0; allocated_memory.clear(); @@ -118,7 +121,8 @@ namespace test } } - void track_allocate(void *ptr, std::size_t n, std::size_t size, int tag) + void track_allocate(void *ptr, std::size_t n, std::size_t size, + int tag) { if(n == 0) { BOOST_ERROR("Allocating 0 length array."); @@ -132,10 +136,12 @@ namespace test } } - void track_deallocate(void* ptr, std::size_t n, std::size_t size, int tag) + void track_deallocate(void* ptr, std::size_t n, std::size_t size, + int tag) { - BOOST_DEDUCED_TYPENAME allocated_memory_type::iterator pos - = allocated_memory.find(memory_area(ptr, (char*) ptr + n * size)); + BOOST_DEDUCED_TYPENAME allocated_memory_type::iterator pos = + allocated_memory.find( + memory_area(ptr, (char*) ptr + n * size)); if(pos == allocated_memory.end()) { BOOST_ERROR("Deallocating unknown pointer."); } else { @@ -148,12 +154,14 @@ namespace test if(count_allocations > 0) --count_allocations; } - void track_construct(void* /*ptr*/, std::size_t /*size*/, int /*tag*/) + void track_construct(void* /*ptr*/, std::size_t /*size*/, + int /*tag*/) { ++count_constructions; } - void track_destroy(void* /*ptr*/, std::size_t /*size*/, int /*tag*/) + void track_destroy(void* /*ptr*/, std::size_t /*size*/, + int /*tag*/) { BOOST_TEST(count_constructions > 0); if(count_constructions > 0) --count_constructions; diff --git a/test/helpers/prefix.hpp b/test/helpers/prefix.hpp index 36080e46..ef879fb7 100644 --- a/test/helpers/prefix.hpp +++ b/test/helpers/prefix.hpp @@ -6,5 +6,6 @@ #if defined(_WIN32_WCE) // The standard windows mobile headers trigger this warning so I disable it // before doing anything else. -#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union +#pragma warning(disable:4201) // nonstandard extension used : + // nameless struct/union #endif diff --git a/test/helpers/random_values.hpp b/test/helpers/random_values.hpp index 0d71ea1d..85d22c7a 100644 --- a/test/helpers/random_values.hpp +++ b/test/helpers/random_values.hpp @@ -71,7 +71,9 @@ namespace test type_ == generate_collisions ? generate(int_ptr) % 10 : 1; count; --count) { - x.push_back(std::pair(key, generate(mapped_ptr))); + x.push_back( + std::pair( + key, generate(mapped_ptr))); } } } diff --git a/test/helpers/test.hpp b/test/helpers/test.hpp index 40b642b6..54c75614 100644 --- a/test/helpers/test.hpp +++ b/test/helpers/test.hpp @@ -11,19 +11,20 @@ #include #include -#define UNORDERED_AUTO_TEST(x) \ - struct BOOST_PP_CAT(x, _type) : public ::test::registered_test_base { \ - BOOST_PP_CAT(x, _type)() \ - : ::test::registered_test_base(BOOST_PP_STRINGIZE(x)) \ - { \ - ::test::test_list::add_test(this); \ - } \ - void run(); \ - }; \ - BOOST_PP_CAT(x, _type) x; \ - void BOOST_PP_CAT(x, _type)::run() -#define RUN_TESTS() int main(int, char**) \ - { ::test::test_list::run_tests(); return boost::report_errors(); } +#define UNORDERED_AUTO_TEST(x) \ + struct BOOST_PP_CAT(x, _type) : public ::test::registered_test_base { \ + BOOST_PP_CAT(x, _type)() \ + : ::test::registered_test_base(BOOST_PP_STRINGIZE(x)) \ + { \ + ::test::test_list::add_test(this); \ + } \ + void run(); \ + }; \ + BOOST_PP_CAT(x, _type) x; \ + void BOOST_PP_CAT(x, _type)::run() \ + +#define RUN_TESTS() int main(int, char**) \ + { ::test::test_list::run_tests(); return boost::report_errors(); } \ namespace test { struct registered_test_base { @@ -74,20 +75,22 @@ namespace test { #include // Run test with every combination of the parameters (a sequence of sequences) -#define UNORDERED_TEST(name, parameters) \ - BOOST_PP_SEQ_FOR_EACH_PRODUCT(UNORDERED_TEST_OP, ((name)) parameters) +#define UNORDERED_TEST(name, parameters) \ + BOOST_PP_SEQ_FOR_EACH_PRODUCT(UNORDERED_TEST_OP, ((name)) parameters) \ -#define UNORDERED_TEST_OP(r, product) \ - UNORDERED_TEST_OP2( \ - BOOST_PP_SEQ_HEAD(product), \ - BOOST_PP_SEQ_TAIL(product)) +#define UNORDERED_TEST_OP(r, product) \ + UNORDERED_TEST_OP2( \ + BOOST_PP_SEQ_HEAD(product), \ + BOOST_PP_SEQ_TAIL(product)) \ -#define UNORDERED_TEST_OP2(name, params) \ - UNORDERED_AUTO_TEST(BOOST_PP_SEQ_FOLD_LEFT(UNORDERED_TEST_OP_JOIN, name, params)) { \ - name BOOST_PP_SEQ_TO_TUPLE(params); \ - } +#define UNORDERED_TEST_OP2(name, params) \ + UNORDERED_AUTO_TEST( \ + BOOST_PP_SEQ_FOLD_LEFT(UNORDERED_TEST_OP_JOIN, name, params)) \ + { \ + name BOOST_PP_SEQ_TO_TUPLE(params); \ + } \ -#define UNORDERED_TEST_OP_JOIN(s, state, elem) \ - BOOST_PP_CAT(state, BOOST_PP_CAT(_, elem)) +#define UNORDERED_TEST_OP_JOIN(s, state, elem) \ + BOOST_PP_CAT(state, BOOST_PP_CAT(_, elem)) \ #endif diff --git a/test/helpers/tracker.hpp b/test/helpers/tracker.hpp index b5bf3c22..bf56b356 100644 --- a/test/helpers/tracker.hpp +++ b/test/helpers/tracker.hpp @@ -27,7 +27,8 @@ namespace test { template struct equals_to_compare2 - : public boost::mpl::identity > + : public boost::mpl::identity< + std::less > { }; @@ -62,37 +63,55 @@ namespace test values1.sort(); values2.sort(); BOOST_TEST(values1.size() == values2.size() && - test::equal(values1.begin(), values1.end(), values2.begin(), test::equivalent)); + test::equal(values1.begin(), values1.end(), + values2.begin(), test::equivalent)); } template - struct ordered_set - : public boost::mpl::if_< + struct ordered_set : public + boost::mpl::if_< test::has_unique_keys, - std::set::type>, - std::multiset::type> - > {}; + std::set< + BOOST_DEDUCED_TYPENAME X::value_type, + BOOST_DEDUCED_TYPENAME equals_to_compare< + BOOST_DEDUCED_TYPENAME X::key_equal + >::type + >, + std::multiset< + BOOST_DEDUCED_TYPENAME X::value_type, + BOOST_DEDUCED_TYPENAME equals_to_compare< + BOOST_DEDUCED_TYPENAME X::key_equal + >::type + > + > {}; template - struct ordered_map - : public boost::mpl::if_< + struct ordered_map : public + boost::mpl::if_< test::has_unique_keys, - std::map::type>, - std::multimap::type> - > {}; + std::map< + BOOST_DEDUCED_TYPENAME X::key_type, + BOOST_DEDUCED_TYPENAME X::mapped_type, + BOOST_DEDUCED_TYPENAME equals_to_compare< + BOOST_DEDUCED_TYPENAME X::key_equal + >::type + >, + std::multimap< + BOOST_DEDUCED_TYPENAME X::key_type, + BOOST_DEDUCED_TYPENAME X::mapped_type, + BOOST_DEDUCED_TYPENAME equals_to_compare< + BOOST_DEDUCED_TYPENAME X::key_equal + >::type + > + > {}; template - struct ordered_base - : public boost::mpl::eval_if< + struct ordered_base : public + boost::mpl::eval_if< test::is_set, test::ordered_set, - test::ordered_map > - { - }; + test::ordered_map + > {}; template class ordered : public ordered_base::type @@ -114,7 +133,8 @@ namespace test compare_range(x, *this); } - void compare_key(X const& x, BOOST_DEDUCED_TYPENAME X::value_type const& val) + void compare_key(X const& x, + BOOST_DEDUCED_TYPENAME X::value_type const& val) { compare_pairs( x.equal_range(get_key(val)), @@ -132,7 +152,8 @@ namespace test }; template - BOOST_DEDUCED_TYPENAME equals_to_compare::type create_compare(Equals const&) + BOOST_DEDUCED_TYPENAME + equals_to_compare::type create_compare(Equals const&) { BOOST_DEDUCED_TYPENAME equals_to_compare::type x; return x; diff --git a/test/objects/minimal.hpp b/test/objects/minimal.hpp index 252e3564..4f8680fb 100644 --- a/test/objects/minimal.hpp +++ b/test/objects/minimal.hpp @@ -46,31 +46,61 @@ namespace minimal class copy_constructible_equality_comparable { public: - static copy_constructible_equality_comparable create() { return copy_constructible_equality_comparable(); } - copy_constructible_equality_comparable(copy_constructible_equality_comparable const&) {} - ~copy_constructible_equality_comparable() {} + static copy_constructible_equality_comparable create() { + return copy_constructible_equality_comparable(); + } + + copy_constructible_equality_comparable( + copy_constructible_equality_comparable const&) + { + } + + ~copy_constructible_equality_comparable() + { + } + private: - copy_constructible_equality_comparable& operator=(copy_constructible_equality_comparable const&); + copy_constructible_equality_comparable& operator=( + copy_constructible_equality_comparable const&); copy_constructible_equality_comparable() {} }; - bool operator==(copy_constructible_equality_comparable, copy_constructible_equality_comparable) { + bool operator==( + copy_constructible_equality_comparable, + copy_constructible_equality_comparable) + { return true; } - bool operator!=(copy_constructible_equality_comparable, copy_constructible_equality_comparable) { + bool operator!=( + copy_constructible_equality_comparable, + copy_constructible_equality_comparable) + { return false; } class default_copy_constructible { public: - static default_copy_constructible create() { return default_copy_constructible(); } - default_copy_constructible() {} - default_copy_constructible(default_copy_constructible const&) {} - ~default_copy_constructible() {} + static default_copy_constructible create() + { + return default_copy_constructible(); + } + + default_copy_constructible() + { + } + + default_copy_constructible(default_copy_constructible const&) + { + } + + ~default_copy_constructible() + { + } private: - default_copy_constructible& operator=(default_copy_constructible const&); + default_copy_constructible& operator=( + default_copy_constructible const&); }; class assignable @@ -130,7 +160,8 @@ namespace minimal ptr& operator++() { ++ptr_; return *this; } ptr operator++(int) { ptr tmp(*this); ++ptr_; return tmp; } ptr operator+(std::ptrdiff_t s) const { return ptr(ptr_ + s); } - friend ptr operator+(std::ptrdiff_t s, ptr p) { return ptr(s + p.ptr_); } + friend ptr operator+(std::ptrdiff_t s, ptr p) + { return ptr(s + p.ptr_); } T& operator[](std::ptrdiff_t s) const { return ptr_[s]; } bool operator!() const { return !ptr_; } @@ -169,8 +200,10 @@ namespace minimal T const* operator->() const { return ptr_; } const_ptr& operator++() { ++ptr_; return *this; } const_ptr operator++(int) { const_ptr tmp(*this); ++ptr_; return tmp; } - const_ptr operator+(std::ptrdiff_t s) const { return const_ptr(ptr_ + s); } - friend const_ptr operator+(std::ptrdiff_t s, const_ptr p) { return ptr(s + p.ptr_); } + const_ptr operator+(std::ptrdiff_t s) const + { return const_ptr(ptr_ + s); } + friend const_ptr operator+(std::ptrdiff_t s, const_ptr p) + { return ptr(s + p.ptr_); } T const& operator[](int s) const { return ptr_[s]; } bool operator!() const { return !ptr_; } operator bool() const { return !!ptr_; } @@ -272,7 +305,9 @@ namespace boost { namespace test { namespace minimal { #endif - std::size_t hash_value(test::minimal::copy_constructible_equality_comparable) { + std::size_t hash_value( + test::minimal::copy_constructible_equality_comparable) + { return 1; } #if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) diff --git a/test/objects/test.hpp b/test/objects/test.hpp index 767dbb4a..bfada4d2 100644 --- a/test/objects/test.hpp +++ b/test/objects/test.hpp @@ -190,13 +190,37 @@ namespace test template struct rebind { typedef allocator other; }; - explicit allocator(int t = 0) : tag_(t) { detail::tracker.allocator_ref(); } - template allocator(allocator const& x) : tag_(x.tag_) { detail::tracker.allocator_ref(); } - allocator(allocator const& x) : tag_(x.tag_) { detail::tracker.allocator_ref(); } - ~allocator() { detail::tracker.allocator_unref(); } + explicit allocator(int t = 0) : tag_(t) + { + detail::tracker.allocator_ref(); + } + + template allocator(allocator const& x) + : tag_(x.tag_) + { + detail::tracker.allocator_ref(); + } - pointer address(reference r) { return pointer(&r); } - const_pointer address(const_reference r) { return const_pointer(&r); } + allocator(allocator const& x) + : tag_(x.tag_) + { + detail::tracker.allocator_ref(); + } + + ~allocator() + { + detail::tracker.allocator_unref(); + } + + pointer address(reference r) + { + return pointer(&r); + } + + const_pointer address(const_reference r) + { + return const_pointer(&r); + } pointer allocate(size_type n) { pointer ptr(static_cast(::operator new(n * sizeof(T)))); @@ -250,7 +274,9 @@ namespace test }; template - bool equivalent_impl(allocator const& x, allocator const& y, test::derived_type) { + bool equivalent_impl(allocator const& x, allocator const& y, + test::derived_type) + { return x == y; } diff --git a/test/unordered/assign_tests.cpp b/test/unordered/assign_tests.cpp index 72a73fe7..3d5d4a14 100644 --- a/test/unordered/assign_tests.cpp +++ b/test/unordered/assign_tests.cpp @@ -20,7 +20,8 @@ namespace assign_tests { test::seed_t seed(96785); template -void assign_tests1(T*, test::random_generator generator = test::default_generator) +void assign_tests1(T*, + test::random_generator generator = test::default_generator) { BOOST_DEDUCED_TYPENAME T::hasher hf; BOOST_DEDUCED_TYPENAME T::key_equal eq; @@ -54,7 +55,8 @@ void assign_tests1(T*, test::random_generator generator = test::default_generato } template -void assign_tests2(T*, test::random_generator generator = test::default_generator) +void assign_tests2(T*, + test::random_generator generator = test::default_generator) { BOOST_DEDUCED_TYPENAME T::hasher hf1(1); BOOST_DEDUCED_TYPENAME T::hasher hf2(2); @@ -87,10 +89,18 @@ void assign_tests2(T*, test::random_generator generator = test::default_generato } } -boost::unordered_set >* test_set; -boost::unordered_multiset >* test_multiset; -boost::unordered_map >* test_map; -boost::unordered_multimap >* test_multimap; +boost::unordered_set >* test_set; +boost::unordered_multiset >* test_multiset; +boost::unordered_map >* test_map; +boost::unordered_multimap >* test_multimap; using test::default_generator; using test::generate_collisions; diff --git a/test/unordered/bucket_tests.cpp b/test/unordered/bucket_tests.cpp index 7126b8bb..c87dad84 100644 --- a/test/unordered/bucket_tests.cpp +++ b/test/unordered/bucket_tests.cpp @@ -43,24 +43,40 @@ void tests(X* = 0, test::random_generator generator = test::default_generator) if(bucket < x.max_bucket_count()) { // lit? lend?? I need a new naming scheme. const_local_iterator lit = x.begin(bucket), lend = x.end(bucket); - while(lit != lend && test::get_key(*it) != test::get_key(*lit)) ++lit; + while(lit != lend + && test::get_key(*it) != test::get_key(*lit)) + { + ++lit; + } BOOST_TEST(lit != lend); } } for(size_type i = 0; i < x.bucket_count(); ++i) { - BOOST_TEST(x.bucket_size(i) == (size_type) std::distance(x.begin(i), x.end(i))); - BOOST_TEST(x.bucket_size(i) == (size_type) std::distance(x.cbegin(i), x.cend(i))); + BOOST_TEST(x.bucket_size(i) == static_cast( + std::distance(x.begin(i), x.end(i)))); + BOOST_TEST(x.bucket_size(i) == static_cast( + std::distance(x.cbegin(i), x.cend(i)))); X const& x_ref = x; - BOOST_TEST(x.bucket_size(i) == (size_type) std::distance(x_ref.begin(i), x_ref.end(i))); - BOOST_TEST(x.bucket_size(i) == (size_type) std::distance(x_ref.cbegin(i), x_ref.cend(i))); + BOOST_TEST(x.bucket_size(i) == static_cast( + std::distance(x_ref.begin(i), x_ref.end(i)))); + BOOST_TEST(x.bucket_size(i) == static_cast( + std::distance(x_ref.cbegin(i), x_ref.cend(i)))); } } -boost::unordered_set >* test_set; -boost::unordered_multiset >* test_multiset; -boost::unordered_map >* test_map; -boost::unordered_multimap >* test_multimap; +boost::unordered_set >* test_set; +boost::unordered_multiset >* test_multiset; +boost::unordered_map >* test_map; +boost::unordered_multimap >* test_multimap; UNORDERED_TEST(tests, ((test_set)(test_multiset)(test_map)(test_multimap))) diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index aa33ee35..2def5318 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -37,10 +37,15 @@ void container_test(X& r, T const&) typedef BOOST_DEDUCED_TYPENAME X::difference_type difference_type; typedef BOOST_DEDUCED_TYPENAME X::size_type size_type; - typedef BOOST_DEDUCED_TYPENAME boost::iterator_value::type iterator_value_type; - typedef BOOST_DEDUCED_TYPENAME boost::iterator_value::type const_iterator_value_type; - typedef BOOST_DEDUCED_TYPENAME boost::iterator_difference::type iterator_difference_type; - typedef BOOST_DEDUCED_TYPENAME boost::iterator_difference::type const_iterator_difference_type; + typedef BOOST_DEDUCED_TYPENAME + boost::iterator_value::type iterator_value_type; + typedef BOOST_DEDUCED_TYPENAME + boost::iterator_value::type const_iterator_value_type; + typedef BOOST_DEDUCED_TYPENAME + boost::iterator_difference::type iterator_difference_type; + typedef BOOST_DEDUCED_TYPENAME + boost::iterator_difference::type + const_iterator_difference_type; typedef BOOST_DEDUCED_TYPENAME X::value_type value_type; typedef BOOST_DEDUCED_TYPENAME X::reference reference; @@ -149,7 +154,8 @@ void unordered_map_test(X& r, Key const& k, T const& v) { typedef BOOST_DEDUCED_TYPENAME X::value_type value_type; typedef BOOST_DEDUCED_TYPENAME X::key_type key_type; - BOOST_MPL_ASSERT((boost::is_same >)); + BOOST_MPL_ASSERT(( + boost::is_same >)); r.insert(std::pair(k, v)); @@ -212,25 +218,57 @@ void unordered_test(X&, Key& k, T& t, Hash& hf, Pred& eq) typedef BOOST_DEDUCED_TYPENAME X::local_iterator local_iterator; typedef BOOST_DEDUCED_TYPENAME X::const_local_iterator const_local_iterator; - typedef BOOST_DEDUCED_TYPENAME boost::BOOST_ITERATOR_CATEGORY::type iterator_category; - typedef BOOST_DEDUCED_TYPENAME boost::iterator_difference::type iterator_difference; - typedef BOOST_DEDUCED_TYPENAME boost::iterator_pointer::type iterator_pointer; - typedef BOOST_DEDUCED_TYPENAME boost::iterator_reference::type iterator_reference; + typedef BOOST_DEDUCED_TYPENAME + boost::BOOST_ITERATOR_CATEGORY::type + iterator_category; + typedef BOOST_DEDUCED_TYPENAME + boost::iterator_difference::type + iterator_difference; + typedef BOOST_DEDUCED_TYPENAME + boost::iterator_pointer::type + iterator_pointer; + typedef BOOST_DEDUCED_TYPENAME + boost::iterator_reference::type + iterator_reference; - typedef BOOST_DEDUCED_TYPENAME boost::BOOST_ITERATOR_CATEGORY::type local_iterator_category; - typedef BOOST_DEDUCED_TYPENAME boost::iterator_difference::type local_iterator_difference; - typedef BOOST_DEDUCED_TYPENAME boost::iterator_pointer::type local_iterator_pointer; - typedef BOOST_DEDUCED_TYPENAME boost::iterator_reference::type local_iterator_reference; + typedef BOOST_DEDUCED_TYPENAME + boost::BOOST_ITERATOR_CATEGORY::type + local_iterator_category; + typedef BOOST_DEDUCED_TYPENAME + boost::iterator_difference::type + local_iterator_difference; + typedef BOOST_DEDUCED_TYPENAME + boost::iterator_pointer::type + local_iterator_pointer; + typedef BOOST_DEDUCED_TYPENAME + boost::iterator_reference::type + local_iterator_reference; - typedef BOOST_DEDUCED_TYPENAME boost::BOOST_ITERATOR_CATEGORY::type const_iterator_category; - typedef BOOST_DEDUCED_TYPENAME boost::iterator_difference::type const_iterator_difference; - typedef BOOST_DEDUCED_TYPENAME boost::iterator_pointer::type const_iterator_pointer; - typedef BOOST_DEDUCED_TYPENAME boost::iterator_reference::type const_iterator_reference; + typedef BOOST_DEDUCED_TYPENAME + boost::BOOST_ITERATOR_CATEGORY::type + const_iterator_category; + typedef BOOST_DEDUCED_TYPENAME + boost::iterator_difference::type + const_iterator_difference; + typedef BOOST_DEDUCED_TYPENAME + boost::iterator_pointer::type + const_iterator_pointer; + typedef BOOST_DEDUCED_TYPENAME + boost::iterator_reference::type + const_iterator_reference; - typedef BOOST_DEDUCED_TYPENAME boost::BOOST_ITERATOR_CATEGORY::type const_local_iterator_category; - typedef BOOST_DEDUCED_TYPENAME boost::iterator_difference::type const_local_iterator_difference; - typedef BOOST_DEDUCED_TYPENAME boost::iterator_pointer::type const_local_iterator_pointer; - typedef BOOST_DEDUCED_TYPENAME boost::iterator_reference::type const_local_iterator_reference; + typedef BOOST_DEDUCED_TYPENAME + boost::BOOST_ITERATOR_CATEGORY::type + const_local_iterator_category; + typedef BOOST_DEDUCED_TYPENAME + boost::iterator_difference::type + const_local_iterator_difference; + typedef BOOST_DEDUCED_TYPENAME + boost::iterator_pointer::type + const_local_iterator_pointer; + typedef BOOST_DEDUCED_TYPENAME + boost::iterator_reference::type + const_local_iterator_reference; BOOST_MPL_ASSERT((boost::is_same)); boost::function_requires >(); @@ -243,16 +281,25 @@ void unordered_test(X&, Key& k, T& t, Hash& hf, Pred& eq) test::check_return_type::convertible(eq(k, k)); boost::function_requires >(); - BOOST_MPL_ASSERT((boost::is_same)); - BOOST_MPL_ASSERT((boost::is_same)); - BOOST_MPL_ASSERT((boost::is_same)); - BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); - boost::function_requires >(); - BOOST_MPL_ASSERT((boost::is_same)); - BOOST_MPL_ASSERT((boost::is_same)); - BOOST_MPL_ASSERT((boost::is_same)); - BOOST_MPL_ASSERT((boost::is_same)); + boost::function_requires< + boost::InputIteratorConcept >(); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); X(10, hf, eq); X a(10, hf, eq); diff --git a/test/unordered/constructor_tests.cpp b/test/unordered/constructor_tests.cpp index 5ad411f0..b157bdbd 100644 --- a/test/unordered/constructor_tests.cpp +++ b/test/unordered/constructor_tests.cpp @@ -22,7 +22,8 @@ namespace constructor_tests { test::seed_t seed(356730); template -void constructor_tests1(T*, test::random_generator generator = test::default_generator) +void constructor_tests1(T*, + test::random_generator generator = test::default_generator) { BOOST_DEDUCED_TYPENAME T::hasher hf; BOOST_DEDUCED_TYPENAME T::key_equal eq; @@ -152,7 +153,8 @@ void constructor_tests1(T*, test::random_generator generator = test::default_gen } template -void constructor_tests2(T*, test::random_generator const& generator = test::default_generator) +void constructor_tests2(T*, + test::random_generator const& generator = test::default_generator) { BOOST_DEDUCED_TYPENAME T::hasher hf; BOOST_DEDUCED_TYPENAME T::hasher hf1(1); @@ -247,10 +249,12 @@ void constructor_tests2(T*, test::random_generator const& generator = test::defa test::random_values v(100, generator); BOOST_DEDUCED_TYPENAME test::random_values::const_iterator v_begin = v.begin(), v_end = v.end(); - T x(test::input_iterator(v_begin), test::input_iterator(v_end), 0, hf1, eq1); + T x(test::input_iterator(v_begin), + test::input_iterator(v_end), 0, hf1, eq1); BOOST_DEDUCED_TYPENAME T::const_iterator x_begin = x.begin(), x_end = x.end(); - T y(test::input_iterator(x_begin), test::input_iterator(x_end), 0, hf2, eq2); + T y(test::input_iterator(x_begin), + test::input_iterator(x_end), 0, hf2, eq2); test::check_container(x, v); test::check_container(y, x); test::check_equivalent_keys(x); @@ -325,11 +329,17 @@ void constructor_tests2(T*, test::random_generator const& generator = test::defa } template -void map_constructor_test(T* = 0, test::random_generator const& generator = test::default_generator) +void map_constructor_test(T* = 0, + test::random_generator const& generator = test::default_generator) { std::cerr<<"map_constructor_test\n"; - typedef test::list > list; + typedef test::list< + std::pair< + BOOST_DEDUCED_TYPENAME T::key_type, + BOOST_DEDUCED_TYPENAME T::mapped_type + > + > list; test::random_values v(1000, generator); list l(v.begin(), v.end()); T x(l.begin(), l.end()); @@ -338,10 +348,18 @@ void map_constructor_test(T* = 0, test::random_generator const& generator = test test::check_equivalent_keys(x); } -boost::unordered_set >* test_set; -boost::unordered_multiset >* test_multiset; -boost::unordered_map >* test_map; -boost::unordered_multimap >* test_multimap; +boost::unordered_set >* test_set; +boost::unordered_multiset >* test_multiset; +boost::unordered_map >* test_map; +boost::unordered_multimap >* test_multimap; using test::default_generator; using test::generate_collisions; diff --git a/test/unordered/copy_tests.cpp b/test/unordered/copy_tests.cpp index 8ddfb782..d939d0ff 100644 --- a/test/unordered/copy_tests.cpp +++ b/test/unordered/copy_tests.cpp @@ -20,7 +20,8 @@ namespace copy_tests { template -void copy_construct_tests1(T*, test::random_generator const& generator = test::default_generator) +void copy_construct_tests1(T*, + test::random_generator const& generator = test::default_generator) { BOOST_DEDUCED_TYPENAME T::hasher hf; BOOST_DEDUCED_TYPENAME T::key_equal eq; @@ -65,7 +66,8 @@ void copy_construct_tests1(T*, test::random_generator const& generator = test::d } template -void copy_construct_tests2(T* ptr, test::random_generator const& generator = test::default_generator) +void copy_construct_tests2(T* ptr, + test::random_generator const& generator = test::default_generator) { copy_construct_tests1(ptr); @@ -119,10 +121,18 @@ void copy_construct_tests2(T* ptr, test::random_generator const& generator = tes } } -boost::unordered_set >* test_set; -boost::unordered_multiset >* test_multiset; -boost::unordered_map >* test_map; -boost::unordered_multimap >* test_multimap; +boost::unordered_set >* test_set; +boost::unordered_multiset >* test_multiset; +boost::unordered_map >* test_map; +boost::unordered_multimap >* test_multimap; using test::default_generator; using test::generate_collisions; diff --git a/test/unordered/equality_tests.cpp b/test/unordered/equality_tests.cpp index 45c4c9d3..6d9541b6 100644 --- a/test/unordered/equality_tests.cpp +++ b/test/unordered/equality_tests.cpp @@ -30,36 +30,39 @@ namespace equality_tests } }; -#define UNORDERED_EQUALITY_SET_TEST(seq1, op, seq2) \ - { \ - boost::unordered_set set1, set2; \ - BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \ - BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \ - BOOST_TEST(set1 op set2); \ +#define UNORDERED_EQUALITY_SET_TEST(seq1, op, seq2) \ + { \ + boost::unordered_set set1, set2; \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \ + BOOST_TEST(set1 op set2); \ } -#define UNORDERED_EQUALITY_MULTISET_TEST(seq1, op, seq2) \ - { \ - boost::unordered_multiset set1, set2; \ - BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \ - BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \ - BOOST_TEST(set1 op set2); \ +#define UNORDERED_EQUALITY_MULTISET_TEST(seq1, op, seq2) \ + { \ + boost::unordered_multiset \ + set1, set2; \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \ + BOOST_TEST(set1 op set2); \ } -#define UNORDERED_EQUALITY_MAP_TEST(seq1, op, seq2) \ - { \ - boost::unordered_map map1, map2; \ - BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \ - BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \ - BOOST_TEST(map1 op map2); \ +#define UNORDERED_EQUALITY_MAP_TEST(seq1, op, seq2) \ + { \ + boost::unordered_map \ + map1, map2; \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \ + BOOST_TEST(map1 op map2); \ } -#define UNORDERED_EQUALITY_MULTIMAP_TEST(seq1, op, seq2) \ - { \ - boost::unordered_multimap map1, map2; \ - BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \ - BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \ - BOOST_TEST(map1 op map2); \ +#define UNORDERED_EQUALITY_MULTIMAP_TEST(seq1, op, seq2) \ + { \ + boost::unordered_multimap \ + map1, map2; \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \ + BOOST_TEST(map1 op map2); \ } #define UNORDERED_SET_INSERT(r, set, item) set.insert(item); diff --git a/test/unordered/equivalent_keys_tests.cpp b/test/unordered/equivalent_keys_tests.cpp index 10f3ac1c..994bc668 100644 --- a/test/unordered/equivalent_keys_tests.cpp +++ b/test/unordered/equivalent_keys_tests.cpp @@ -44,17 +44,20 @@ UNORDERED_AUTO_TEST(set_tests) {986, 25, 986} }; - test_equal_insertion >(values[0], values[0] + 1); - test_equal_insertion >(values[1], values[1] + 2); - test_equal_insertion >(values[2], values[2] + 2); - test_equal_insertion >(values[3], values[3] + 2); - test_equal_insertion >(values[4], values[4] + 3); + typedef boost::unordered_set set; + typedef boost::unordered_multiset multiset; - test_equal_insertion >(values[0], values[0] + 1); - test_equal_insertion >(values[1], values[1] + 2); - test_equal_insertion >(values[2], values[2] + 2); - test_equal_insertion >(values[3], values[3] + 2); - test_equal_insertion >(values[4], values[4] + 3); + test_equal_insertion(values[0], values[0] + 1); + test_equal_insertion(values[1], values[1] + 2); + test_equal_insertion(values[2], values[2] + 2); + test_equal_insertion(values[3], values[3] + 2); + test_equal_insertion(values[4], values[4] + 3); + + test_equal_insertion(values[0], values[0] + 1); + test_equal_insertion(values[1], values[1] + 2); + test_equal_insertion(values[2], values[2] + 2); + test_equal_insertion(values[3], values[3] + 2); + test_equal_insertion(values[4], values[4] + 3); } UNORDERED_AUTO_TEST(map_tests) diff --git a/test/unordered/erase_equiv_tests.cpp b/test/unordered/erase_equiv_tests.cpp index 010414be..bb2e5b1b 100644 --- a/test/unordered/erase_equiv_tests.cpp +++ b/test/unordered/erase_equiv_tests.cpp @@ -135,7 +135,8 @@ template void erase_subrange_tests(Container const& x) { for(std::size_t length = 0; length < x.size(); ++length) { - for(std::size_t position = 0; position < x.size() - length; ++position) { + for(std::size_t position = 0; position < x.size() - length; ++position) + { Container y(x); collide_list init(y.begin(), y.end()); if(!general_erase_range_test(y, position, position + length)) { diff --git a/test/unordered/erase_tests.cpp b/test/unordered/erase_tests.cpp index 1bc6e4c6..ca54bf03 100644 --- a/test/unordered/erase_tests.cpp +++ b/test/unordered/erase_tests.cpp @@ -23,14 +23,15 @@ namespace erase_tests test::seed_t seed(85638); template -void erase_tests1(Container*, test::random_generator generator = test::default_generator) +void erase_tests1(Container*, + test::random_generator generator = test::default_generator) { std::cerr<<"Erase by key.\n"; { test::random_values v(1000, generator); Container x(v.begin(), v.end()); - for(BOOST_DEDUCED_TYPENAME test::random_values::iterator it = v.begin(); - it != v.end(); ++it) + for(BOOST_DEDUCED_TYPENAME test::random_values::iterator + it = v.begin(); it != v.end(); ++it) { std::size_t count = x.count(test::get_key(*it)); std::size_t old_size = x.size(); @@ -48,9 +49,11 @@ void erase_tests1(Container*, test::random_generator generator = test::default_g std::size_t size = x.size(); while(size > 0 && !x.empty()) { - BOOST_DEDUCED_TYPENAME Container::key_type key = test::get_key(*x.begin()); + BOOST_DEDUCED_TYPENAME Container::key_type + key = test::get_key(*x.begin()); std::size_t count = x.count(key); - BOOST_DEDUCED_TYPENAME Container::iterator pos = x.erase(x.begin()); + BOOST_DEDUCED_TYPENAME Container::iterator + pos = x.erase(x.begin()); --size; BOOST_TEST(pos == x.begin()); BOOST_TEST(x.count(key) == count - 1); @@ -77,7 +80,8 @@ void erase_tests1(Container*, test::random_generator generator = test::default_g pos = boost::next(prev); } next = boost::next(pos); - BOOST_DEDUCED_TYPENAME Container::key_type key = test::get_key(*pos); + BOOST_DEDUCED_TYPENAME Container::key_type + key = test::get_key(*pos); std::size_t count = x.count(key); BOOST_TEST(next == x.erase(pos)); --size; @@ -119,7 +123,8 @@ void erase_tests1(Container*, test::random_generator generator = test::default_g std::size_t size = x.size(); while(size > 0 && !x.empty()) { - BOOST_DEDUCED_TYPENAME Container::key_type key = test::get_key(*x.begin()); + BOOST_DEDUCED_TYPENAME Container::key_type + key = test::get_key(*x.begin()); std::size_t count = x.count(key); x.erase_return_void(x.begin()); --size; @@ -147,7 +152,8 @@ void erase_tests1(Container*, test::random_generator generator = test::default_g pos = boost::next(prev); } next = boost::next(pos); - BOOST_DEDUCED_TYPENAME Container::key_type key = test::get_key(*pos); + BOOST_DEDUCED_TYPENAME Container::key_type + key = test::get_key(*pos); std::size_t count = x.count(key); x.erase_return_void(pos); --size; @@ -173,10 +179,18 @@ void erase_tests1(Container*, test::random_generator generator = test::default_g std::cerr<<"\n"; } -boost::unordered_set >* test_set; -boost::unordered_multiset >* test_multiset; -boost::unordered_map >* test_map; -boost::unordered_multimap >* test_multimap; +boost::unordered_set >* test_set; +boost::unordered_multiset >* test_multiset; +boost::unordered_map >* test_map; +boost::unordered_multimap >* test_multimap; using test::default_generator; using test::generate_collisions; diff --git a/test/unordered/find_tests.cpp b/test/unordered/find_tests.cpp index e823a04d..363de0c6 100644 --- a/test/unordered/find_tests.cpp +++ b/test/unordered/find_tests.cpp @@ -35,7 +35,8 @@ void find_tests1(X*, test::random_generator generator = test::default_generator) { BOOST_DEDUCED_TYPENAME X::key_type key = test::get_key(*it1); iterator pos = x.find(key); - BOOST_DEDUCED_TYPENAME X::const_iterator const_pos = x_const.find(key); + BOOST_DEDUCED_TYPENAME X::const_iterator + const_pos = x_const.find(key); BOOST_TEST(pos != x.end() && x.key_eq()(key, test::get_key(*pos))); BOOST_TEST(const_pos != x_const.end() && @@ -109,10 +110,12 @@ struct compatible_predicate }; template -void find_compatible_keys_test(X*, test::random_generator generator = test::default_generator) +void find_compatible_keys_test(X*, + test::random_generator generator = test::default_generator) { typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; - typedef BOOST_DEDUCED_TYPENAME test::random_values::iterator value_iterator; + typedef BOOST_DEDUCED_TYPENAME test::random_values::iterator + value_iterator; test::random_values v(500, generator); X x(v.begin(), v.end()); @@ -132,10 +135,18 @@ void find_compatible_keys_test(X*, test::random_generator generator = test::defa } } -boost::unordered_set >* test_set; -boost::unordered_multiset >* test_multiset; -boost::unordered_map >* test_map; -boost::unordered_multimap >* test_multimap; +boost::unordered_set >* test_set; +boost::unordered_multiset >* test_multiset; +boost::unordered_map >* test_map; +boost::unordered_multimap >* test_multimap; using test::default_generator; using test::generate_collisions; diff --git a/test/unordered/fwd_set_test.cpp b/test/unordered/fwd_set_test.cpp index 866ffc4f..b868f62d 100644 --- a/test/unordered/fwd_set_test.cpp +++ b/test/unordered/fwd_set_test.cpp @@ -47,7 +47,8 @@ bool call_not_equals(int_multiset& x, int_multiset& y) { #include "../helpers/test.hpp" UNORDERED_AUTO_TEST(use_fwd_declared_trait_without_definition) { - BOOST_TEST(sizeof(is_unordered_set_impl((int_set*) 0)) == sizeof(true_type)); + BOOST_TEST(sizeof(is_unordered_set_impl((int_set*) 0)) + == sizeof(true_type)); } #include diff --git a/test/unordered/incomplete_test.cpp b/test/unordered/incomplete_test.cpp index a8bf784a..08455600 100644 --- a/test/unordered/incomplete_test.cpp +++ b/test/unordered/incomplete_test.cpp @@ -25,10 +25,14 @@ namespace test // Declare some instances - typedef boost::unordered_map > > map; - typedef boost::unordered_multimap > > multimap; - typedef boost::unordered_set > set; - typedef boost::unordered_multiset > multiset; + typedef boost::unordered_map > > map; + typedef boost::unordered_multimap > > multimap; + typedef boost::unordered_set > set; + typedef boost::unordered_multiset > multiset; // Now define the types which are stored as members, as they are needed for // declaring struct members. @@ -51,19 +55,24 @@ namespace test { // Declare some members of a structs. // - // Incomplete hash, equals and allocator aren't here supported at the moment. + // Incomplete hash, equals and allocator aren't here supported at the + // moment. struct struct1 { - boost::unordered_map > > x; + boost::unordered_map > > x; }; struct struct2 { - boost::unordered_multimap > > x; + boost::unordered_multimap > > x; }; struct struct3 { - boost::unordered_set > x; + boost::unordered_set > x; }; struct struct4 { - boost::unordered_multiset > x; + boost::unordered_multiset > x; }; // Now define the value type. @@ -81,7 +90,9 @@ namespace test test::struct2 c2; test::struct3 c3; test::struct4 c4; - // Now declare, but don't define, the operators required for comparing elements. + + // Now declare, but don't define, the operators required for comparing + // elements. std::size_t hash_value(value const&); bool operator==(value const&, value const&); diff --git a/test/unordered/insert_stable_tests.cpp b/test/unordered/insert_stable_tests.cpp index 4fd44f3f..86304da8 100644 --- a/test/unordered/insert_stable_tests.cpp +++ b/test/unordered/insert_stable_tests.cpp @@ -48,7 +48,8 @@ UNORDERED_AUTO_TEST(stable_insert_test1) { x.insert(insert_stable::member(1,2)); x.insert(insert_stable::member(1,3)); - boost::unordered_multiset::const_iterator it = x.begin(), end = x.end(); + boost::unordered_multiset::const_iterator + it = x.begin(), end = x.end(); BOOST_TEST(it != end); if(it != end) { BOOST_TEST(it->tag2_ == 1); ++it; } BOOST_TEST(it != end); @@ -60,9 +61,12 @@ UNORDERED_AUTO_TEST(stable_insert_test1) { UNORDERED_AUTO_TEST(stable_insert_test2) { boost::unordered_multimap x; - typedef boost::unordered_multimap::const_iterator iterator; + typedef + boost::unordered_multimap::const_iterator + iterator; - iterator it = x.insert(x.end(), std::make_pair(insert_stable::member(1,1), 1)); + iterator it + = x.insert(x.end(), std::make_pair(insert_stable::member(1,1), 1)); it = x.insert(it, std::make_pair(insert_stable::member(1,2), 2)); it = x.insert(it, std::make_pair(insert_stable::member(1,3), 3)); diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 49f133f2..f0136b70 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -23,7 +23,8 @@ namespace insert_tests { test::seed_t seed(243432); template -void unique_insert_tests1(X*, test::random_generator generator = test::default_generator) +void unique_insert_tests1(X*, + test::random_generator generator = test::default_generator) { typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; typedef test::ordered ordered; @@ -43,7 +44,8 @@ void unique_insert_tests1(X*, test::random_generator generator = test::default_g float b = x.max_load_factor(); std::pair r1 = x.insert(*it); - std::pair r2 = tracker.insert(*it); + std::pair + r2 = tracker.insert(*it); BOOST_TEST(r1.second == r2.second); BOOST_TEST(*r1.first == *r2.first); @@ -58,7 +60,8 @@ void unique_insert_tests1(X*, test::random_generator generator = test::default_g } template -void equivalent_insert_tests1(X*, test::random_generator generator = test::default_generator) +void equivalent_insert_tests1(X*, + test::random_generator generator = test::default_generator) { std::cerr<<"insert(value) tests for containers with equivalent keys.\n"; @@ -73,7 +76,8 @@ void equivalent_insert_tests1(X*, test::random_generator generator = test::defau float b = x.max_load_factor(); BOOST_DEDUCED_TYPENAME X::iterator r1 = x.insert(*it); - BOOST_DEDUCED_TYPENAME test::ordered::iterator r2 = tracker.insert(*it); + BOOST_DEDUCED_TYPENAME test::ordered::iterator r2 + = tracker.insert(*it); BOOST_TEST(*r1 == *r2); @@ -87,7 +91,8 @@ void equivalent_insert_tests1(X*, test::random_generator generator = test::defau } template -void insert_tests2(X*, test::random_generator generator = test::default_generator) +void insert_tests2(X*, + test::random_generator generator = test::default_generator) { typedef BOOST_DEDUCED_TYPENAME test::ordered tracker_type; typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; @@ -101,10 +106,11 @@ void insert_tests2(X*, test::random_generator generator = test::default_generato tracker_type tracker = test::create_ordered(x); test::random_values v(1000, generator); - for(BOOST_DEDUCED_TYPENAME test::random_values::iterator it = v.begin(); - it != v.end(); ++it) + for(BOOST_DEDUCED_TYPENAME test::random_values::iterator + it = v.begin(); it != v.end(); ++it) { - BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count = x.bucket_count(); + BOOST_DEDUCED_TYPENAME X::size_type + old_bucket_count = x.bucket_count(); float b = x.max_load_factor(); iterator r1 = x.insert(x.begin(), *it); @@ -127,10 +133,11 @@ void insert_tests2(X*, test::random_generator generator = test::default_generato tracker_type tracker = test::create_ordered(x); test::random_values v(100, generator); - for(BOOST_DEDUCED_TYPENAME test::random_values::iterator it = v.begin(); - it != v.end(); ++it) + for(BOOST_DEDUCED_TYPENAME test::random_values::iterator + it = v.begin(); it != v.end(); ++it) { - BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count = x.bucket_count(); + BOOST_DEDUCED_TYPENAME X::size_type + old_bucket_count = x.bucket_count(); float b = x.max_load_factor(); const_iterator r1 = x.insert(x_const.end(), *it); @@ -153,10 +160,11 @@ void insert_tests2(X*, test::random_generator generator = test::default_generato tracker_type tracker = test::create_ordered(x); test::random_values v(1000, generator); - for(BOOST_DEDUCED_TYPENAME test::random_values::iterator it = v.begin(); - it != v.end(); ++it) + for(BOOST_DEDUCED_TYPENAME test::random_values::iterator + it = v.begin(); it != v.end(); ++it) { - BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count = x.bucket_count(); + BOOST_DEDUCED_TYPENAME X::size_type + old_bucket_count = x.bucket_count(); float b = x.max_load_factor(); pos = x.insert(pos, *it); @@ -178,10 +186,11 @@ void insert_tests2(X*, test::random_generator generator = test::default_generato tracker_type tracker = test::create_ordered(x); test::random_values v(1000, generator); - for(BOOST_DEDUCED_TYPENAME test::random_values::iterator it = v.begin(); - it != v.end(); ++it) + for(BOOST_DEDUCED_TYPENAME test::random_values::iterator + it = v.begin(); it != v.end(); ++it) { - BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count = x.bucket_count(); + BOOST_DEDUCED_TYPENAME X::size_type + old_bucket_count = x.bucket_count(); float b = x.max_load_factor(); x.insert(it, boost::next(it)); @@ -225,7 +234,8 @@ void insert_tests2(X*, test::random_generator generator = test::default_generato #if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) template -void unique_emplace_tests1(X*, test::random_generator generator = test::default_generator) +void unique_emplace_tests1(X*, + test::random_generator generator = test::default_generator) { typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; typedef test::ordered ordered; @@ -245,7 +255,8 @@ void unique_emplace_tests1(X*, test::random_generator generator = test::default_ float b = x.max_load_factor(); std::pair r1 = x.emplace(*it); - std::pair r2 = tracker.insert(*it); + std::pair + r2 = tracker.insert(*it); BOOST_TEST(r1.second == r2.second); BOOST_TEST(*r1.first == *r2.first); @@ -260,7 +271,8 @@ void unique_emplace_tests1(X*, test::random_generator generator = test::default_ } template -void equivalent_emplace_tests1(X*, test::random_generator generator = test::default_generator) +void equivalent_emplace_tests1(X*, + test::random_generator generator = test::default_generator) { std::cerr<<"emplace(value) tests for containers with equivalent keys.\n"; @@ -275,7 +287,8 @@ void equivalent_emplace_tests1(X*, test::random_generator generator = test::defa float b = x.max_load_factor(); BOOST_DEDUCED_TYPENAME X::iterator r1 = x.emplace(*it); - BOOST_DEDUCED_TYPENAME test::ordered::iterator r2 = tracker.insert(*it); + BOOST_DEDUCED_TYPENAME test::ordered::iterator + r2 = tracker.insert(*it); BOOST_TEST(*r1 == *r2); @@ -317,14 +330,21 @@ void map_tests(X*, test::random_generator generator = test::default_generator) test::check_equivalent_keys(x); } -// Some tests for when the range's value type doesn't match the container's value type. +// Some tests for when the range's value type doesn't match the container's +// value type. template -void map_insert_range_test1(X*, test::random_generator generator = test::default_generator) +void map_insert_range_test1(X*, + test::random_generator generator = test::default_generator) { std::cerr<<"map_insert_range_test1\n"; - typedef test::list > list; + typedef test::list< + std::pair< + BOOST_DEDUCED_TYPENAME X::key_type, + BOOST_DEDUCED_TYPENAME X::mapped_type + > + > list; test::random_values v(1000, generator); list l(v.begin(), v.end()); @@ -334,12 +354,17 @@ void map_insert_range_test1(X*, test::random_generator generator = test::default } template -void map_insert_range_test2(X*, test::random_generator generator = test::default_generator) +void map_insert_range_test2(X*, + test::random_generator generator = test::default_generator) { std::cerr<<"map_insert_range_test2\n"; - typedef test::list > list; - test::random_values > v(1000, generator); + typedef test::list< + std::pair + > list; + test::random_values< + boost::unordered_map + > v(1000, generator); list l(v.begin(), v.end()); X x; x.insert(l.begin(), l.end()); @@ -347,10 +372,18 @@ void map_insert_range_test2(X*, test::random_generator generator = test::default test::check_equivalent_keys(x); } -boost::unordered_set >* test_set; -boost::unordered_multiset >* test_multiset; -boost::unordered_map >* test_map; -boost::unordered_multimap >* test_multimap; +boost::unordered_set >* test_set; +boost::unordered_multiset >* test_multiset; +boost::unordered_map >* test_map; +boost::unordered_multimap >* test_multimap; using test::default_generator; using test::generate_collisions; diff --git a/test/unordered/load_factor_tests.cpp b/test/unordered/load_factor_tests.cpp index 10baf1f5..52cd0456 100644 --- a/test/unordered/load_factor_tests.cpp +++ b/test/unordered/load_factor_tests.cpp @@ -36,7 +36,8 @@ void set_load_factor_tests(X* = 0) } template -void insert_test(X*, float mlf, test::random_generator generator = test::default_generator) +void insert_test(X*, float mlf, + test::random_generator generator = test::default_generator) { X x; x.max_load_factor(mlf); diff --git a/test/unordered/move_tests.cpp b/test/unordered/move_tests.cpp index 47e77bb9..1e580848 100644 --- a/test/unordered/move_tests.cpp +++ b/test/unordered/move_tests.cpp @@ -46,7 +46,8 @@ namespace move_tests } template - void move_construct_tests1(T* ptr, test::random_generator const& generator = test::default_generator) + void move_construct_tests1(T* ptr, + test::random_generator const& generator = test::default_generator) { BOOST_DEDUCED_TYPENAME T::hasher hf; BOOST_DEDUCED_TYPENAME T::key_equal eq; @@ -75,7 +76,8 @@ namespace move_tests } template - void move_assign_tests1(T*, test::random_generator const& generator = test::default_generator) + void move_assign_tests1(T*, + test::random_generator const& generator = test::default_generator) { { test::random_values v(500, generator); @@ -116,7 +118,8 @@ namespace move_tests } { - // TODO: To do this correctly requires the fancy new allocator stuff. + // TODO: To do this correctly requires the fancy new allocator + // stuff. test::random_values v(500, generator); T y(create(v, count, hf, eq, al, 2.0), al2); BOOST_TEST(count != test::global_object_count); @@ -134,7 +137,8 @@ namespace move_tests #if defined(BOOST_HAS_RVALUE_REFS) BOOST_TEST(count == test::global_object_count); #else - BOOST_TEST(test::global_object_count.constructions - count.constructions <= + BOOST_TEST( + test::global_object_count.constructions - count.constructions <= (test::is_map::value ? 50 : 25)); BOOST_TEST(count.instances == test::global_object_count.instances); #endif @@ -147,10 +151,18 @@ namespace move_tests } */ } - boost::unordered_set >* test_set; - boost::unordered_multiset >* test_multiset; - boost::unordered_map >* test_map; - boost::unordered_multimap >* test_multimap; + boost::unordered_set >* test_set; + boost::unordered_multiset >* test_multiset; + boost::unordered_map >* test_map; + boost::unordered_multimap >* test_multimap; using test::default_generator; using test::generate_collisions; diff --git a/test/unordered/rehash_tests.cpp b/test/unordered/rehash_tests.cpp index 7f66edc1..9b419e8d 100644 --- a/test/unordered/rehash_tests.cpp +++ b/test/unordered/rehash_tests.cpp @@ -19,7 +19,8 @@ test::seed_t seed(2974); template bool postcondition(X const& x, BOOST_DEDUCED_TYPENAME X::size_type n) { - return x.bucket_count() > x.size() / x.max_load_factor() && x.bucket_count() >= n; + return x.bucket_count() > x.size() / x.max_load_factor() && + x.bucket_count() >= n; } template @@ -35,7 +36,8 @@ void rehash_empty_test1(X* = 0) } template -void rehash_empty_test2(X* = 0, test::random_generator generator = test::default_generator) +void rehash_empty_test2(X* = 0, + test::random_generator generator = test::default_generator) { test::random_values v(1000, generator); test::ordered tracker; @@ -53,7 +55,8 @@ void rehash_empty_test2(X* = 0, test::random_generator generator = test::default } template -void rehash_empty_test3(X* = 0, test::random_generator generator = test::default_generator) +void rehash_empty_test3(X* = 0, + test::random_generator generator = test::default_generator) { test::random_values v(1000, generator); test::ordered tracker; @@ -72,7 +75,8 @@ void rehash_empty_test3(X* = 0, test::random_generator generator = test::default template -void rehash_test1(X* = 0, test::random_generator generator = test::default_generator) +void rehash_test1(X* = 0, + test::random_generator generator = test::default_generator) { test::random_values v(1000, generator); test::ordered tracker; diff --git a/test/unordered/simple_tests.cpp b/test/unordered/simple_tests.cpp index e7b9539e..ca343542 100644 --- a/test/unordered/simple_tests.cpp +++ b/test/unordered/simple_tests.cpp @@ -72,7 +72,8 @@ void simple_test(X const& a) { BOOST_TEST(a.size() == - (BOOST_DEDUCED_TYPENAME X::size_type) std::distance(a.begin(), a.end())); + static_cast( + std::distance(a.begin(), a.end()))); } { diff --git a/test/unordered/swap_tests.cpp b/test/unordered/swap_tests.cpp index 5fe8be91..3705cce4 100644 --- a/test/unordered/swap_tests.cpp +++ b/test/unordered/swap_tests.cpp @@ -62,7 +62,8 @@ void swap_tests1(X*, test::random_generator generator = test::default_generator) } template -void swap_tests2(X* ptr = 0, test::random_generator generator = test::default_generator) +void swap_tests2(X* ptr = 0, + test::random_generator generator = test::default_generator) { swap_tests1(ptr); @@ -98,7 +99,8 @@ void swap_tests2(X* ptr = 0, test::random_generator generator = test::default_ge X y(vy.begin(), vy.end(), 0, hasher(), key_equal(), allocator_type(2)); try { swap_test_impl(x, y); - BOOST_ERROR("Using swap method 1, swapping with unequal allocators didn't throw."); + BOOST_ERROR("Using swap method 1, " + "swapping with unequal allocators didn't throw."); } catch (std::runtime_error) {} } #else @@ -111,18 +113,28 @@ void swap_tests2(X* ptr = 0, test::random_generator generator = test::default_ge { test::random_values vx(100, generator), vy(100, generator); - X x(vx.begin(), vx.end(), 0, hasher(1), key_equal(1), allocator_type(1)); - X y(vy.begin(), vy.end(), 0, hasher(2), key_equal(2), allocator_type(2)); + X x(vx.begin(), vx.end(), 0, hasher(1), key_equal(1), + allocator_type(1)); + X y(vy.begin(), vy.end(), 0, hasher(2), key_equal(2), + allocator_type(2)); swap_test_impl(x, y); swap_test_impl(x, y); } #endif } -boost::unordered_set >* test_set; -boost::unordered_multiset >* test_multiset; -boost::unordered_map >* test_map; -boost::unordered_multimap >* test_multimap; +boost::unordered_set >* test_set; +boost::unordered_multiset >* test_multiset; +boost::unordered_map >* test_map; +boost::unordered_multimap >* test_multimap; UNORDERED_TEST(swap_tests1, ((test_set)(test_multiset)(test_map)(test_multimap)) diff --git a/test/unordered/unnecessary_copy_tests.cpp b/test/unordered/unnecessary_copy_tests.cpp index 40df82f6..b3a580df 100644 --- a/test/unordered/unnecessary_copy_tests.cpp +++ b/test/unordered/unnecessary_copy_tests.cpp @@ -67,25 +67,33 @@ 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 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: "< b) { \ + BOOST_ERROR("Wrong number of moves."); \ + std::cerr \ + << "Number of moves: " << count_copies::copies \ + << " expecting: [" << a << ", " << b << "]" << std::endl; \ } namespace unnecessary_copy_tests From 2b212d7c49ae28d1d65cfed7f69bf6b3de9fbc65 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 9 Jan 2010 17:17:53 +0000 Subject: [PATCH 047/100] Merge unordered documentation. [SVN r58844] --- doc/changes.qbk | 1 + doc/ref.xml | 32 ++++++++++++++++++++++++++++---- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index fa454d4b..f776fa01 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -115,5 +115,6 @@ First official release. * Add templated find overload for compatible keys. * [@http://svn.boost.org/trac/boost/ticket/3773 Ticket 3773]: Add missing `std` qualifier to `ptrdiff_t`. +* Some code formatting changes to fit almost all lines into 80 characters. [endsect] diff --git a/doc/ref.xml b/doc/ref.xml index 76d15a1a..3abf9d45 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -507,7 +507,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) const_iterator - iterator + void Erase the element pointed to by position. @@ -613,6 +613,12 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) An iterator pointing to an element with key equivalent to k, or b.end() if no such element exists. + + The templated overloads are a non-standard extensions which + allows you to use a compatible hash function and equality + predicate for a key of a different type in order to avoid + an expensive type cast. In general, its use is not encouraged. + @@ -1364,7 +1370,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) const_iterator - iterator + void Erase the element pointed to by position. @@ -1470,6 +1476,12 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) An iterator pointing to an element with key equivalent to k, or b.end() if no such element exists. + + The templated overloads are a non-standard extensions which + allows you to use a compatible hash function and equality + predicate for a key of a different type in order to avoid + an expensive type cast. In general, its use is not encouraged. + @@ -2235,7 +2247,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) const_iterator - iterator + void Erase the element pointed to by position. @@ -2341,6 +2353,12 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) An iterator pointing to an element with key equivalent to k, or b.end() if no such element exists. + + The templated overloads are a non-standard extensions which + allows you to use a compatible hash function and equality + predicate for a key of a different type in order to avoid + an expensive type cast. In general, its use is not encouraged. + @@ -3141,7 +3159,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) const_iterator - iterator + void Erase the element pointed to by position. @@ -3247,6 +3265,12 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) An iterator pointing to an element with key equivalent to k, or b.end() if no such element exists. + + The templated overloads are a non-standard extensions which + allows you to use a compatible hash function and equality + predicate for a key of a different type in order to avoid + an expensive type cast. In general, its use is not encouraged. + From 3fb7d15f5b4efc771fe7f6c704f64e5895202d10 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 25 Feb 2010 19:05:01 +0000 Subject: [PATCH 048/100] Merge hash and unordered from trunk. - Replace uses of deprecated C++0x macros - Set length of primes inside template on Sun C++. Fixes #3854 - Missing newline at end of file. [SVN r59911] --- doc/Jamfile.v2 | 3 --- include/boost/unordered/detail/fwd.hpp | 2 +- include/boost/unordered/detail/util.hpp | 20 ++++++++++++++------ include/boost/unordered/unordered_map.hpp | 6 +++--- include/boost/unordered/unordered_set.hpp | 6 +++--- test/exception/insert_exception_tests.cpp | 4 ++-- test/unordered/insert_tests.cpp | 4 ++-- test/unordered/move_tests.cpp | 2 +- test/unordered/unnecessary_copy_tests.cpp | 10 +++++----- 9 files changed, 31 insertions(+), 26 deletions(-) diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index ceb7d91a..1ccb5214 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -8,10 +8,7 @@ path-constant admonishment_location : ../../../../doc/src/images ; xml unordered : unordered.qbk ; boostbook standalone : unordered : - html.stylesheet=../../../../doc/html/boostbook.css boost.root=../../../.. - boost.libraries=../../../libraries.htm - navig.graphics=1 chunk.first.sections=1 chunk.section.depth=2 diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index 1598cdb0..c1c31ffc 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -31,7 +31,7 @@ // G = Grouped/Ungrouped // E = Key Extractor -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) +#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES) # if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION) // STLport doesn't have std::forward. # else diff --git a/include/boost/unordered/detail/util.hpp b/include/boost/unordered/detail/util.hpp index 22b41583..55409651 100644 --- a/include/boost/unordered/detail/util.hpp +++ b/include/boost/unordered/detail/util.hpp @@ -32,12 +32,6 @@ namespace boost { namespace unordered_detail { //////////////////////////////////////////////////////////////////////////// // primes - template struct prime_list_template - { - static std::size_t const value[]; - static std::ptrdiff_t const length; - }; - #define BOOST_UNORDERED_PRIMES \ (5ul)(11ul)(17ul)(29ul)(37ul)(53ul)(67ul)(79ul) \ (97ul)(131ul)(193ul)(257ul)(389ul)(521ul)(769ul) \ @@ -47,14 +41,28 @@ namespace boost { namespace unordered_detail { (50331653ul)(100663319ul)(201326611ul)(402653189ul)(805306457ul) \ (1610612741ul)(3221225473ul)(4294967291ul) + template struct prime_list_template + { + static std::size_t const value[]; + +#if !defined(SUNPRO_CC) + static std::ptrdiff_t const length; +#else + static std::ptrdiff_t const length + = BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES); +#endif + }; + template std::size_t const prime_list_template::value[] = { BOOST_PP_SEQ_ENUM(BOOST_UNORDERED_PRIMES) }; +#if !defined(SUNPRO_CC) template std::ptrdiff_t const prime_list_template::length = BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES); +#endif #undef BOOST_UNORDERED_PRIMES diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 93e19789..4c399b8a 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -19,7 +19,7 @@ #include #include -#if !defined(BOOST_HAS_RVALUE_REFS) +#if defined(BOOST_NO_RVALUE_REFERENCES) #include #endif @@ -159,7 +159,7 @@ namespace boost ~unordered_map() {} -#if defined(BOOST_HAS_RVALUE_REFS) +#if !defined(BOOST_NO_RVALUE_REFERENCES) unordered_map(unordered_map&& other) : table_(other.table_, boost::unordered_detail::move_tag()) { @@ -699,7 +699,7 @@ namespace boost ~unordered_multimap() {} -#if defined(BOOST_HAS_RVALUE_REFS) +#if !defined(BOOST_NO_RVALUE_REFERENCES) unordered_multimap(unordered_multimap&& other) : table_(other.table_, boost::unordered_detail::move_tag()) { diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 87c1011b..2c291f46 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -19,7 +19,7 @@ #include #include -#if !defined(BOOST_HAS_RVALUE_REFS) +#if defined(BOOST_NO_RVALUE_REFERENCES) #include #endif @@ -153,7 +153,7 @@ namespace boost ~unordered_set() {} -#if defined(BOOST_HAS_RVALUE_REFS) +#if !defined(BOOST_NO_RVALUE_REFERENCES) unordered_set(unordered_set&& other) : table_(other.table_, boost::unordered_detail::move_tag()) { @@ -645,7 +645,7 @@ namespace boost ~unordered_multiset() {} -#if defined(BOOST_HAS_RVALUE_REFS) +#if !defined(BOOST_NO_RVALUE_REFERENCES) unordered_multiset(unordered_multiset&& other) : table_(other.table_, boost::unordered_detail::move_tag()) { diff --git a/test/exception/insert_exception_tests.cpp b/test/exception/insert_exception_tests.cpp index 85776241..84278c0e 100644 --- a/test/exception/insert_exception_tests.cpp +++ b/test/exception/insert_exception_tests.cpp @@ -39,7 +39,7 @@ struct insert_test_base : public test::exception_base } }; -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) +#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES) template struct emplace_test1 : public insert_test_base @@ -238,7 +238,7 @@ struct insert_test_rehash3 : public insert_test_base (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) +#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES) #define ALL_TESTS (emplace_test1)BASIC_TESTS #else #define ALL_TESTS BASIC_TESTS diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index f0136b70..5af8be66 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -231,7 +231,7 @@ void insert_tests2(X*, } } -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) +#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES) template void unique_emplace_tests1(X*, @@ -403,7 +403,7 @@ UNORDERED_TEST(insert_tests2, ((default_generator)(generate_collisions)) ) -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) +#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES) UNORDERED_TEST(unique_emplace_tests1, ((test_set)(test_map)) ((default_generator)(generate_collisions)) diff --git a/test/unordered/move_tests.cpp b/test/unordered/move_tests.cpp index 1e580848..f29983eb 100644 --- a/test/unordered/move_tests.cpp +++ b/test/unordered/move_tests.cpp @@ -134,7 +134,7 @@ namespace move_tests { test::random_values v(25, generator); T y(create(v, count, hf, eq, al, 1.0), al); -#if defined(BOOST_HAS_RVALUE_REFS) +#if !defined(BOOST_NO_RVALUE_REFERENCES) BOOST_TEST(count == test::global_object_count); #else BOOST_TEST( diff --git a/test/unordered/unnecessary_copy_tests.cpp b/test/unordered/unnecessary_copy_tests.cpp index b3a580df..58bc3b70 100644 --- a/test/unordered/unnecessary_copy_tests.cpp +++ b/test/unordered/unnecessary_copy_tests.cpp @@ -31,7 +31,7 @@ namespace unnecessary_copy_tests : tag_(x.tag_) { ++copies; } count_copies(count_copies const& x) : tag_(x.tag_) { ++copies; } -#if defined(BOOST_HAS_RVALUE_REFS) +#if !defined(BOOST_NO_RVALUE_REFERENCES) count_copies(count_copies&& x) : tag_(x.tag_) { x.tag_ = -1; ++moves; } @@ -136,7 +136,7 @@ namespace unnecessary_copy_tests reset(); T x; x.emplace(source()); -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) +#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES) COPY_COUNT(1); #else COPY_COUNT(2); @@ -148,7 +148,7 @@ namespace unnecessary_copy_tests UNORDERED_TEST(unnecessary_copy_emplace_rvalue_test, ((set)(multiset)(map)(multimap))) -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) +#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES) template void unnecessary_copy_emplace_move_test(T*) { @@ -199,7 +199,7 @@ namespace unnecessary_copy_tests x.emplace(source()); COPY_COUNT(1); MOVE_COUNT(0); -#if defined(BOOST_HAS_RVALUE_REFS) +#if !defined(BOOST_NO_RVALUE_REFERENCES) // No move should take place. reset(); x.emplace(std::move(a)); @@ -271,7 +271,7 @@ namespace unnecessary_copy_tests //x.emplace(a_ref); //COPY_COUNT(0); MOVE_COUNT(0); -#if defined(BOOST_HAS_RVALUE_REFS) +#if !defined(BOOST_NO_RVALUE_REFERENCES) // No move should take place. // (since a is already in the container) reset(); From 958738c7af5a1102ad4b3621840066ba9d9c86b6 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 17 Mar 2010 00:34:26 +0000 Subject: [PATCH 049/100] Merge a warning fix for unordered. [SVN r60668] --- test/unordered/fwd_set_test.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/unordered/fwd_set_test.cpp b/test/unordered/fwd_set_test.cpp index b868f62d..7fc3a8c1 100644 --- a/test/unordered/fwd_set_test.cpp +++ b/test/unordered/fwd_set_test.cpp @@ -57,8 +57,7 @@ UNORDERED_AUTO_TEST(use_fwd_declared_trait) { boost::unordered_set x; BOOST_TEST(sizeof(is_unordered_set_impl(&x)) == sizeof(true_type)); - int dummy; - BOOST_TEST(sizeof(is_unordered_set_impl(&dummy)) == sizeof(false_type)); + BOOST_TEST(sizeof(is_unordered_set_impl((int*) 0)) == sizeof(false_type)); } UNORDERED_AUTO_TEST(use_set_fwd_declared_function) { From fe2a6c521bfd9a3b1aff8c360e75cf71161ed7bd Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 31 Mar 2010 21:39:07 +0000 Subject: [PATCH 050/100] Merge from trunk. - Add `quick_erase` for unordered. `erase_return_void` is now deprecated. Fixes #3966 - Avoid collision between 0 and 0.5. Fixes #4038 [SVN r60980] --- doc/changes.qbk | 11 ++ doc/ref.xml | 144 ++++++++++++++++++---- include/boost/unordered/unordered_map.hpp | 10 ++ include/boost/unordered/unordered_set.hpp | 10 ++ test/unordered/erase_tests.cpp | 8 +- 5 files changed, 155 insertions(+), 28 deletions(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index f776fa01..608f0d52 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -117,4 +117,15 @@ First official release. Add missing `std` qualifier to `ptrdiff_t`. * Some code formatting changes to fit almost all lines into 80 characters. + +[h2 Boost 1.43.0] + +* [@http://svn.boost.org/trac/boost/ticket/3966 Ticket 3966]: + `erase_return_void` is now `quick_erase`, which is the + [@http://home.roadrunner.com/~hinnant/issue_review/lwg-active.html#579 + current forerunner for resolving the slow erase by iterator], although + there's a strong possibility that this may change in the future. The old + method name remains for backwards compatibility but is considered deprecated + and will be removed in a future release. + [endsect] diff --git a/doc/ref.xml b/doc/ref.xml index 3abf9d45..92aaffa7 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -464,8 +464,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) When the number of elements is a lot smaller than the number of buckets this function can be very inefficient as it has to search through empty buckets for the next element, in order to return the iterator. - As a temporary workaround, the container has the method - erase_return_void which will be faster. + The method quick_erase is faster, but has yet + to be standardized. @@ -503,6 +503,30 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + + + const_iterator + + void + + Erase the element pointed to by position. + + + Only throws an exception if it is thrown by hasher or key_equal. + In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + + + + This method is faster than erase as + it doesn't have to find the next element in the container - + a potentially costly operation. + + + As it hasn't been standardized, it's likely that this may + change in the future. + + + const_iterator @@ -517,10 +541,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - This is a temporary workaround for the inefficient - erase method. Hopefully, in a future - version the signature of erase will - be changed and this will be deprecated. + This method is now deprecated, use + quick_return instead. Although be + warned that as that isn't standardized yet, it could also + change. @@ -1327,8 +1351,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) When the number of elements is a lot smaller than the number of buckets this function can be very inefficient as it has to search through empty buckets for the next element, in order to return the iterator. - As a temporary workaround, the container has the method - erase_return_void which will be faster. + The method quick_erase is faster, but has yet + to be standardized. @@ -1366,6 +1390,30 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + + + const_iterator + + void + + Erase the element pointed to by position. + + + Only throws an exception if it is thrown by hasher or key_equal. + In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + + + + This method is faster than erase as + it doesn't have to find the next element in the container - + a potentially costly operation. + + + As it hasn't been standardized, it's likely that this may + change in the future. + + + const_iterator @@ -1380,10 +1428,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - This is a temporary workaround for the inefficient - erase method. Hopefully, in a future - version the signature of erase will - be changed and this will be deprecated. + This method is now deprecated, use + quick_return instead. Although be + warned that as that isn't standardized yet, it could also + change. @@ -2204,8 +2252,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) When the number of elements is a lot smaller than the number of buckets this function can be very inefficient as it has to search through empty buckets for the next element, in order to return the iterator. - As a temporary workaround, the container has the method - erase_return_void which will be faster. + The method quick_erase is faster, but has yet + to be standardized. @@ -2243,6 +2291,30 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + + + const_iterator + + void + + Erase the element pointed to by position. + + + Only throws an exception if it is thrown by hasher or key_equal. + In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + + + + This method is faster than erase as + it doesn't have to find the next element in the container - + a potentially costly operation. + + + As it hasn't been standardized, it's likely that this may + change in the future. + + + const_iterator @@ -2257,10 +2329,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - This is a temporary workaround for the inefficient - erase method. Hopefully, in a future - version the signature of erase will - be changed and this will be deprecated. + This method is now deprecated, use + quick_return instead. Although be + warned that as that isn't standardized yet, it could also + change. @@ -3116,8 +3188,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) When the number of elements is a lot smaller than the number of buckets this function can be very inefficient as it has to search through empty buckets for the next element, in order to return the iterator. - As a temporary workaround, the container has the method - erase_return_void which will be faster. + The method quick_erase is faster, but has yet + to be standardized. @@ -3155,6 +3227,30 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + + + const_iterator + + void + + Erase the element pointed to by position. + + + Only throws an exception if it is thrown by hasher or key_equal. + In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + + + + This method is faster than erase as + it doesn't have to find the next element in the container - + a potentially costly operation. + + + As it hasn't been standardized, it's likely that this may + change in the future. + + + const_iterator @@ -3169,10 +3265,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - This is a temporary workaround for the inefficient - erase method. Hopefully, in a future - version the signature of erase will - be changed and this will be deprecated. + This method is now deprecated, use + quick_return instead. Although be + warned that as that isn't standardized yet, it could also + change. diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 4c399b8a..5bad0ebd 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -369,6 +369,11 @@ namespace boost return iterator(table_.erase_range(get(first), get(last))); } + void quick_erase(const_iterator position) + { + table_.erase(get(position)); + } + void erase_return_void(const_iterator position) { table_.erase(get(position)); @@ -907,6 +912,11 @@ namespace boost return iterator(table_.erase_range(get(first), get(last))); } + void quick_erase(const_iterator position) + { + table_.erase(get(position)); + } + void erase_return_void(const_iterator position) { table_.erase(get(position)); diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 2c291f46..ec48b8c8 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -361,6 +361,11 @@ namespace boost return iterator(table_.erase_range(get(first), get(last))); } + void quick_erase(const_iterator position) + { + table_.erase(get(position)); + } + void erase_return_void(const_iterator position) { table_.erase(get(position)); @@ -849,6 +854,11 @@ namespace boost return iterator(table_.erase_range(get(first), get(last))); } + void quick_erase(const_iterator position) + { + table_.erase(get(position)); + } + void erase_return_void(const_iterator position) { table_.erase(get(position)); diff --git a/test/unordered/erase_tests.cpp b/test/unordered/erase_tests.cpp index ca54bf03..4a3fe2c9 100644 --- a/test/unordered/erase_tests.cpp +++ b/test/unordered/erase_tests.cpp @@ -116,7 +116,7 @@ void erase_tests1(Container*, BOOST_TEST(x.erase(x.begin(), x.end()) == x.begin()); } - std::cerr<<"erase_return_void(begin()).\n"; + std::cerr<<"quick_erase(begin()).\n"; { test::random_values v(1000, generator); Container x(v.begin(), v.end()); @@ -126,7 +126,7 @@ void erase_tests1(Container*, BOOST_DEDUCED_TYPENAME Container::key_type key = test::get_key(*x.begin()); std::size_t count = x.count(key); - x.erase_return_void(x.begin()); + x.quick_erase(x.begin()); --size; BOOST_TEST(x.count(key) == count - 1); BOOST_TEST(x.size() == size); @@ -134,7 +134,7 @@ void erase_tests1(Container*, BOOST_TEST(x.empty()); } - std::cerr<<"erase_return_void(random position).\n"; + std::cerr<<"quick_erase(random position).\n"; { test::random_values v(1000, generator); Container x(v.begin(), v.end()); @@ -155,7 +155,7 @@ void erase_tests1(Container*, BOOST_DEDUCED_TYPENAME Container::key_type key = test::get_key(*pos); std::size_t count = x.count(key); - x.erase_return_void(pos); + x.quick_erase(pos); --size; if(size > 0) BOOST_TEST(index == 0 ? next == x.begin() : From d3ca85bdbd91b30e2837a4ca3c2e0ad1ac2429f1 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 5 Apr 2010 08:08:25 +0000 Subject: [PATCH 051/100] Merge throw_exception use in unordered. [SVN r61063] --- include/boost/unordered/detail/table.hpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 198548d3..d37c0155 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include @@ -608,15 +609,15 @@ namespace boost { namespace unordered_detail { hash_table::at(key_type const& k) const { if(!this->size_) - throw std::out_of_range("Unable to find key in unordered_map."); + boost::throw_exception(std::out_of_range("Unable to find key in unordered_map.")); bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); node_ptr it = find_iterator(bucket, k); - if (BOOST_UNORDERED_BORLAND_BOOL(it)) - return node::get_value(it); - else - throw std::out_of_range("Unable to find key in unordered_map."); + if (!it) + boost::throw_exception(std::out_of_range("Unable to find key in unordered_map.")); + + return node::get_value(it); } // equal_range From ec97640b1baa1508c18847c507b0e443322229b6 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 21 Apr 2010 23:00:35 +0000 Subject: [PATCH 052/100] Merge some link fixes and release notes. [SVN r61474] --- doc/changes.qbk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index 608f0d52..5dc34cc4 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -117,7 +117,6 @@ First official release. Add missing `std` qualifier to `ptrdiff_t`. * Some code formatting changes to fit almost all lines into 80 characters. - [h2 Boost 1.43.0] * [@http://svn.boost.org/trac/boost/ticket/3966 Ticket 3966]: @@ -127,5 +126,7 @@ First official release. there's a strong possibility that this may change in the future. The old method name remains for backwards compatibility but is considered deprecated and will be removed in a future release. +* Use Boost.Exception. +* Stop using deprecated `BOOST_HAS_*` macros. [endsect] From 795d9f0aa7b91f7a31792014ee6d163155fc042c Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 28 Apr 2010 08:23:41 +0000 Subject: [PATCH 053/100] Support for clang. [SVN r61640] --- include/boost/unordered/detail/fwd.hpp | 23 +++++++++++++++++++ .../exception/constructor_exception_tests.cpp | 14 +++++++++++ test/exception/copy_exception_tests.cpp | 6 +++++ test/helpers/list.hpp | 2 +- test/unordered/compile_tests.hpp | 18 +++++++++++++++ test/unordered/constructor_tests.cpp | 1 - 6 files changed, 62 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index c1c31ffc..a290ded9 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -731,6 +731,7 @@ namespace boost { namespace unordered_detail { // Iterator Access +#if !defined(__clang__) class iterator_access { public: @@ -741,6 +742,28 @@ namespace boost { namespace unordered_detail { return it.base_; } }; +#else + class iterator_access + { + public: + // Note: we access Iterator::base here, rather than in the function + // signature to work around a bug in the friend support of an + // early version of clang. + + template + struct base + { + typedef BOOST_DEDUCED_TYPENAME Iterator::base type; + }; + + template + static BOOST_DEDUCED_TYPENAME base::type const& + get(Iterator const& it) + { + return it.base_; + } + }; +#endif // Iterators diff --git a/test/exception/constructor_exception_tests.cpp b/test/exception/constructor_exception_tests.cpp index ef3119e4..96d5c1f2 100644 --- a/test/exception/constructor_exception_tests.cpp +++ b/test/exception/constructor_exception_tests.cpp @@ -9,6 +9,8 @@ #include "../helpers/random_values.hpp" #include "../helpers/input_iterator.hpp" +template inline void avoid_unused_warning(T const&) {} + test::seed_t seed(91274); struct objects @@ -24,6 +26,7 @@ struct construct_test1 : public objects, test::exception_base { void run() const { T x; + avoid_unused_warning(x); } }; @@ -32,6 +35,7 @@ struct construct_test2 : public objects, test::exception_base { void run() const { T x(300); + avoid_unused_warning(x); } }; @@ -40,6 +44,7 @@ struct construct_test3 : public objects, test::exception_base { void run() const { T x(0, hash); + avoid_unused_warning(x); } }; @@ -48,6 +53,7 @@ struct construct_test4 : public objects, test::exception_base { void run() const { T x(0, hash, equal_to); + avoid_unused_warning(x); } }; @@ -56,6 +62,7 @@ struct construct_test5 : public objects, test::exception_base { void run() const { T x(50, hash, equal_to, allocator); + avoid_unused_warning(x); } }; @@ -64,6 +71,7 @@ struct construct_test6 : public objects, test::exception_base { void run() const { T x(allocator); + avoid_unused_warning(x); } }; @@ -81,6 +89,7 @@ struct range_construct_test1 : public range, objects { void run() const { T x(this->values.begin(), this->values.end()); + avoid_unused_warning(x); } }; @@ -89,6 +98,7 @@ struct range_construct_test2 : public range, objects { void run() const { T x(this->values.begin(), this->values.end(), 0); + avoid_unused_warning(x); } }; @@ -97,6 +107,7 @@ struct range_construct_test3 : public range, objects { void run() const { T x(this->values.begin(), this->values.end(), 0, hash); + avoid_unused_warning(x); } }; @@ -105,6 +116,7 @@ struct range_construct_test4 : public range, objects { void run() const { T x(this->values.begin(), this->values.end(), 100, hash, equal_to); + avoid_unused_warning(x); } }; @@ -118,6 +130,7 @@ struct range_construct_test5 : public range, objects void run() const { T x(this->values.begin(), this->values.end(), 0, hash, equal_to, allocator); + avoid_unused_warning(x); } }; @@ -131,6 +144,7 @@ struct input_range_construct_test : public range, objects begin = this->values.begin(), end = this->values.end(); T x(test::input_iterator(begin), test::input_iterator(end), 0, hash, equal_to, allocator); + avoid_unused_warning(x); } }; diff --git a/test/exception/copy_exception_tests.cpp b/test/exception/copy_exception_tests.cpp index 36a0d798..0d0e2e14 100644 --- a/test/exception/copy_exception_tests.cpp +++ b/test/exception/copy_exception_tests.cpp @@ -8,6 +8,8 @@ #include "./containers.hpp" #include "../helpers/random_values.hpp" +template inline void avoid_unused_warning(T const&) {} + test::seed_t seed(73041); template @@ -17,6 +19,7 @@ struct copy_test1 : public test::exception_base void run() const { T y(x); + avoid_unused_warning(y); } }; @@ -30,6 +33,7 @@ struct copy_test2 : public test::exception_base void run() const { T y(x); + avoid_unused_warning(y); } }; @@ -43,6 +47,7 @@ struct copy_test3 : public test::exception_base void run() const { T y(x); + avoid_unused_warning(y); } }; @@ -57,6 +62,7 @@ struct copy_with_allocator_test : public test::exception_base void run() const { T y(x, allocator); + avoid_unused_warning(y); } }; diff --git a/test/helpers/list.hpp b/test/helpers/list.hpp index ebb37b8f..991404ee 100644 --- a/test/helpers/list.hpp +++ b/test/helpers/list.hpp @@ -94,7 +94,7 @@ namespace test node* ptr_; public: - list_iterator() : ptr_(0) {}; + list_iterator() : ptr_(0) {} explicit list_iterator(node* x) : ptr_(x) {} T& operator*() const { return ptr_->value_; } diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index 2def5318..d22a9fc0 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -138,6 +138,12 @@ void container_test(X& r, T const&) typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type; test::check_return_type::equals(a_const.get_allocator()); + + // Avoid unused variable warnings: + + sink(u); + sink(u2); + sink(u3); } template @@ -375,4 +381,16 @@ void unordered_test(X&, Key& k, T& t, Hash& hf, Pred& eq) test::check_return_type::equals(b.max_load_factor()); a.max_load_factor((float) 2.0); a.rehash(100); + + // Avoid unused variable warnings: + + sink(a); + sink(a2); + sink(a3); + sink(a4); + sink(a5); + sink(a6); + sink(a7); + sink(a8); + sink(a9); } diff --git a/test/unordered/constructor_tests.cpp b/test/unordered/constructor_tests.cpp index b157bdbd..e48cecde 100644 --- a/test/unordered/constructor_tests.cpp +++ b/test/unordered/constructor_tests.cpp @@ -142,7 +142,6 @@ void constructor_tests1(T*, std::cerr<<"Construct 11\n"; { - test::random_values v(1000, generator); T x(al); BOOST_TEST(x.empty()); BOOST_TEST(test::equivalent(x.hash_function(), hf)); From 70ca44b503a3ca164ac6d50d0049df631aaf4796 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 8 Jun 2010 23:23:43 +0000 Subject: [PATCH 054/100] Merge unordered. [SVN r62610] --- include/boost/unordered/detail/equivalent.hpp | 95 ++++++++ include/boost/unordered/detail/fwd.hpp | 210 +----------------- include/boost/unordered/detail/unique.hpp | 113 ++++++++++ 3 files changed, 210 insertions(+), 208 deletions(-) diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 639dd5ef..1c497c32 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -12,6 +12,101 @@ namespace boost { namespace unordered_detail { + template + class hash_equivalent_table : public T::table + { + public: + typedef BOOST_DEDUCED_TYPENAME T::hasher hasher; + typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal; + typedef BOOST_DEDUCED_TYPENAME T::value_allocator value_allocator; + typedef BOOST_DEDUCED_TYPENAME T::key_type key_type; + typedef BOOST_DEDUCED_TYPENAME T::value_type value_type; + typedef BOOST_DEDUCED_TYPENAME T::table table; + typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor; + + typedef BOOST_DEDUCED_TYPENAME T::node node; + typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr; + typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr; + typedef BOOST_DEDUCED_TYPENAME T::iterator_base iterator_base; + typedef BOOST_DEDUCED_TYPENAME T::extractor extractor; + + // Constructors + + hash_equivalent_table(std::size_t n, + hasher const& hf, key_equal const& eq, value_allocator const& a) + : table(n, hf, eq, a) {} + hash_equivalent_table(hash_equivalent_table const& x) + : table(x, x.node_alloc()) {} + hash_equivalent_table(hash_equivalent_table const& x, + value_allocator const& a) + : table(x, a) {} + hash_equivalent_table(hash_equivalent_table& x, move_tag m) + : table(x, m) {} + hash_equivalent_table(hash_equivalent_table& x, + value_allocator const& a, move_tag m) + : table(x, a, m) {} + ~hash_equivalent_table() {} + + // Insert methods + + iterator_base emplace_impl(node_constructor& a); + void emplace_impl_no_rehash(node_constructor& a); + + // equals + + bool equals(hash_equivalent_table const&) const; + + inline node_ptr add_node(node_constructor& a, + bucket_ptr bucket, node_ptr pos); + +#if defined(BOOST_UNORDERED_STD_FORWARD) + + template + iterator_base emplace(Args&&... args); + +#else + +#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ + template \ + iterator_base emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); + + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_INSERT_IMPL, _) + +#undef BOOST_UNORDERED_INSERT_IMPL +#endif + + template + void insert_for_range(I i, I j, forward_traversal_tag); + template + void insert_for_range(I i, I j, boost::incrementable_traversal_tag); + template + void insert_range(I i, I j); + }; + + template + struct multiset : public types< + BOOST_DEDUCED_TYPENAME A::value_type, + BOOST_DEDUCED_TYPENAME A::value_type, + H, P, A, + set_extractor, + grouped> + { + typedef hash_equivalent_table > impl; + typedef hash_table > table; + }; + + template + struct multimap : public types< + K, BOOST_DEDUCED_TYPENAME A::value_type, + H, P, A, + map_extractor, + grouped> + { + typedef hash_equivalent_table > impl; + typedef hash_table > table; + }; + //////////////////////////////////////////////////////////////////////////// // Equality diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index a290ded9..be4d5e1a 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -64,6 +64,8 @@ namespace boost { namespace unordered_detail { static const std::size_t default_bucket_count = 11; struct move_tag {}; + template class hash_unique_table; + template class hash_equivalent_table; template class hash_node_constructor; template @@ -567,168 +569,6 @@ namespace boost { namespace unordered_detail { node_constructor&, std::size_t); }; - template - class hash_unique_table : public T::table - { - public: - typedef BOOST_DEDUCED_TYPENAME T::hasher hasher; - typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal; - typedef BOOST_DEDUCED_TYPENAME T::value_allocator value_allocator; - typedef BOOST_DEDUCED_TYPENAME T::key_type key_type; - typedef BOOST_DEDUCED_TYPENAME T::value_type value_type; - typedef BOOST_DEDUCED_TYPENAME T::table table; - typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor; - - typedef BOOST_DEDUCED_TYPENAME T::node node; - typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr; - typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME T::iterator_base iterator_base; - typedef BOOST_DEDUCED_TYPENAME T::extractor extractor; - - typedef std::pair emplace_return; - - // Constructors - - hash_unique_table(std::size_t n, hasher const& hf, key_equal const& eq, - value_allocator const& a) - : table(n, hf, eq, a) {} - hash_unique_table(hash_unique_table const& x) - : table(x, x.node_alloc()) {} - hash_unique_table(hash_unique_table const& x, value_allocator const& a) - : table(x, a) {} - hash_unique_table(hash_unique_table& x, move_tag m) - : table(x, m) {} - hash_unique_table(hash_unique_table& x, value_allocator const& a, - move_tag m) - : table(x, a, m) {} - ~hash_unique_table() {} - - // Insert methods - - emplace_return emplace_impl_with_node(node_constructor& a); - value_type& operator[](key_type const& k); - - // equals - - bool equals(hash_unique_table const&) const; - - node_ptr add_node(node_constructor& a, bucket_ptr bucket); - -#if defined(BOOST_UNORDERED_STD_FORWARD) - - template - emplace_return emplace(Args&&... args); - template - emplace_return emplace_impl(key_type const& k, Args&&... args); - template - emplace_return emplace_impl(no_key, Args&&... args); - template - emplace_return emplace_empty_impl(Args&&... args); -#else - -#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ - template \ - emplace_return emplace( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \ - template \ - emplace_return emplace_impl(key_type const& k, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \ - template \ - emplace_return emplace_impl(no_key, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \ - template \ - emplace_return emplace_empty_impl( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); - - BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, - BOOST_UNORDERED_INSERT_IMPL, _) - -#undef BOOST_UNORDERED_INSERT_IMPL - -#endif - - // if hash function throws, or inserting > 1 element, basic exception - // safety strong otherwise - template - void insert_range(InputIt i, InputIt j); - template - void insert_range_impl(key_type const&, InputIt i, InputIt j); - template - void insert_range_impl(no_key, InputIt i, InputIt j); - }; - - template - class hash_equivalent_table : public T::table - { - public: - typedef BOOST_DEDUCED_TYPENAME T::hasher hasher; - typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal; - typedef BOOST_DEDUCED_TYPENAME T::value_allocator value_allocator; - typedef BOOST_DEDUCED_TYPENAME T::key_type key_type; - typedef BOOST_DEDUCED_TYPENAME T::value_type value_type; - typedef BOOST_DEDUCED_TYPENAME T::table table; - typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor; - - typedef BOOST_DEDUCED_TYPENAME T::node node; - typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr; - typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME T::iterator_base iterator_base; - typedef BOOST_DEDUCED_TYPENAME T::extractor extractor; - - // Constructors - - hash_equivalent_table(std::size_t n, - hasher const& hf, key_equal const& eq, value_allocator const& a) - : table(n, hf, eq, a) {} - hash_equivalent_table(hash_equivalent_table const& x) - : table(x, x.node_alloc()) {} - hash_equivalent_table(hash_equivalent_table const& x, - value_allocator const& a) - : table(x, a) {} - hash_equivalent_table(hash_equivalent_table& x, move_tag m) - : table(x, m) {} - hash_equivalent_table(hash_equivalent_table& x, - value_allocator const& a, move_tag m) - : table(x, a, m) {} - ~hash_equivalent_table() {} - - // Insert methods - - iterator_base emplace_impl(node_constructor& a); - void emplace_impl_no_rehash(node_constructor& a); - - // equals - - bool equals(hash_equivalent_table const&) const; - - inline node_ptr add_node(node_constructor& a, - bucket_ptr bucket, node_ptr pos); - -#if defined(BOOST_UNORDERED_STD_FORWARD) - - template - iterator_base emplace(Args&&... args); - -#else - -#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ - template \ - iterator_base emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); - - BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, - BOOST_UNORDERED_INSERT_IMPL, _) - -#undef BOOST_UNORDERED_INSERT_IMPL -#endif - - template - void insert_for_range(I i, I j, forward_traversal_tag); - template - void insert_for_range(I i, I j, boost::incrementable_traversal_tag); - template - void insert_range(I i, I j); - }; - // Iterator Access #if !defined(__clang__) @@ -1011,52 +851,6 @@ namespace boost { namespace unordered_detail { typedef std::pair iterator_pair; }; - - template - struct set : public types< - BOOST_DEDUCED_TYPENAME A::value_type, - BOOST_DEDUCED_TYPENAME A::value_type, - H, P, A, - set_extractor, - ungrouped> - { - typedef hash_unique_table > impl; - typedef hash_table > table; - }; - - template - struct multiset : public types< - BOOST_DEDUCED_TYPENAME A::value_type, - BOOST_DEDUCED_TYPENAME A::value_type, - H, P, A, - set_extractor, - grouped> - { - typedef hash_equivalent_table > impl; - typedef hash_table > table; - }; - - template - struct map : public types< - K, BOOST_DEDUCED_TYPENAME A::value_type, - H, P, A, - map_extractor, - ungrouped> - { - typedef hash_unique_table > impl; - typedef hash_table > table; - }; - - template - struct multimap : public types< - K, BOOST_DEDUCED_TYPENAME A::value_type, - H, P, A, - map_extractor, - grouped> - { - typedef hash_equivalent_table > impl; - typedef hash_table > table; - }; }} #endif diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index 59920d00..7ad367fe 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -12,6 +12,119 @@ namespace boost { namespace unordered_detail { + template + class hash_unique_table : public T::table + { + public: + typedef BOOST_DEDUCED_TYPENAME T::hasher hasher; + typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal; + typedef BOOST_DEDUCED_TYPENAME T::value_allocator value_allocator; + typedef BOOST_DEDUCED_TYPENAME T::key_type key_type; + typedef BOOST_DEDUCED_TYPENAME T::value_type value_type; + typedef BOOST_DEDUCED_TYPENAME T::table table; + typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor; + + typedef BOOST_DEDUCED_TYPENAME T::node node; + typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr; + typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr; + typedef BOOST_DEDUCED_TYPENAME T::iterator_base iterator_base; + typedef BOOST_DEDUCED_TYPENAME T::extractor extractor; + + typedef std::pair emplace_return; + + // Constructors + + hash_unique_table(std::size_t n, hasher const& hf, key_equal const& eq, + value_allocator const& a) + : table(n, hf, eq, a) {} + hash_unique_table(hash_unique_table const& x) + : table(x, x.node_alloc()) {} + hash_unique_table(hash_unique_table const& x, value_allocator const& a) + : table(x, a) {} + hash_unique_table(hash_unique_table& x, move_tag m) + : table(x, m) {} + hash_unique_table(hash_unique_table& x, value_allocator const& a, + move_tag m) + : table(x, a, m) {} + ~hash_unique_table() {} + + // Insert methods + + emplace_return emplace_impl_with_node(node_constructor& a); + value_type& operator[](key_type const& k); + + // equals + + bool equals(hash_unique_table const&) const; + + node_ptr add_node(node_constructor& a, bucket_ptr bucket); + +#if defined(BOOST_UNORDERED_STD_FORWARD) + + template + emplace_return emplace(Args&&... args); + template + emplace_return emplace_impl(key_type const& k, Args&&... args); + template + emplace_return emplace_impl(no_key, Args&&... args); + template + emplace_return emplace_empty_impl(Args&&... args); +#else + +#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ + template \ + emplace_return emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \ + template \ + emplace_return emplace_impl(key_type const& k, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \ + template \ + emplace_return emplace_impl(no_key, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \ + template \ + emplace_return emplace_empty_impl( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); + + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_INSERT_IMPL, _) + +#undef BOOST_UNORDERED_INSERT_IMPL + +#endif + + // if hash function throws, or inserting > 1 element, basic exception + // safety strong otherwise + template + void insert_range(InputIt i, InputIt j); + template + void insert_range_impl(key_type const&, InputIt i, InputIt j); + template + void insert_range_impl(no_key, InputIt i, InputIt j); + }; + + template + struct set : public types< + BOOST_DEDUCED_TYPENAME A::value_type, + BOOST_DEDUCED_TYPENAME A::value_type, + H, P, A, + set_extractor, + ungrouped> + { + typedef hash_unique_table > impl; + typedef hash_table > table; + }; + + template + struct map : public types< + K, BOOST_DEDUCED_TYPENAME A::value_type, + H, P, A, + map_extractor, + ungrouped> + { + typedef hash_unique_table > impl; + typedef hash_table > table; + }; + //////////////////////////////////////////////////////////////////////////// // Equality From 8b4c480d47194ad209d8e00bfbc8d854a7374bec Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 1 Jul 2010 21:42:52 +0000 Subject: [PATCH 055/100] Merge unordered build and documentation tweaks. [SVN r63503] --- doc/Jamfile.v2 | 10 ++++++++-- doc/unordered.qbk | 2 +- test/exception/Jamfile.v2 | 2 +- test/unordered/Jamfile.v2 | 2 +- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 1ccb5214..ed333b66 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -8,8 +8,6 @@ path-constant admonishment_location : ../../../../doc/src/images ; xml unordered : unordered.qbk ; boostbook standalone : unordered : - boost.root=../../../.. - chunk.first.sections=1 chunk.section.depth=2 generate.section.toc.level=2 @@ -20,7 +18,15 @@ boostbook standalone : unordered : boost.compact.function=0 boost.compact.enum=0 + # HTML Options: + + html:boost.root=../../../.. + html:img.src.path=../../../../doc/html/ + xhtml:boost.root=../../../.. + xhtml:img.src.path=../../../../doc/html/ + # PDF Options: + # TOC Generation: this is needed for FOP-0.9 and later: fop1.extensions=0 pdf:xep.extensions=1 diff --git a/doc/unordered.qbk b/doc/unordered.qbk index e4f2ce6d..fb3837f4 100644 --- a/doc/unordered.qbk +++ b/doc/unordered.qbk @@ -13,7 +13,7 @@ [license Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at - [@http://www.boost.org/LICENSE_1_0.txt] + [@http://www.boost.org/LICENSE_1_0.txt]) ] ] diff --git a/test/exception/Jamfile.v2 b/test/exception/Jamfile.v2 index cc0ec8e8..87ee3250 100644 --- a/test/exception/Jamfile.v2 +++ b/test/exception/Jamfile.v2 @@ -15,7 +15,7 @@ project unordered-test/exception-tests gcc:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter" darwin:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter" gcc:_GLIBCXX_DEBUG - darwin:_GLIBCXX_DEBUG + #darwin:_GLIBCXX_DEBUG msvc:on #gcc:on #darwin:on diff --git a/test/unordered/Jamfile.v2 b/test/unordered/Jamfile.v2 index 9454d206..07be6c28 100644 --- a/test/unordered/Jamfile.v2 +++ b/test/unordered/Jamfile.v2 @@ -12,7 +12,7 @@ project unordered-test/unordered gcc:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter" darwin:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter" gcc:_GLIBCXX_DEBUG - darwin:_GLIBCXX_DEBUG + #darwin:_GLIBCXX_DEBUG msvc:on #gcc:on #darwin:on From dc8e65043b49136c5ebf3b54d54d211974a59cf8 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 23 Oct 2010 12:02:18 +0000 Subject: [PATCH 056/100] Merge fix for unordered container insertion bug. [SVN r66151] --- doc/changes.qbk | 5 + include/boost/unordered/detail/unique.hpp | 63 ++++++++----- .../exception/constructor_exception_tests.cpp | 16 +++- test/helpers/input_iterator.hpp | 92 ++++++++++++++++++- test/unordered/constructor_tests.cpp | 15 ++- test/unordered/insert_tests.cpp | 14 ++- 6 files changed, 176 insertions(+), 29 deletions(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index 5dc34cc4..7fb950a6 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -129,4 +129,9 @@ First official release. * Use Boost.Exception. * Stop using deprecated `BOOST_HAS_*` macros. +[h2 Boost 1.45.0] + +* Fix a bug when inserting into an `unordered_map` or `unordered_set` using + iterators which returns `value_type` by copy. + [endsect] diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index 7ad367fe..96fdfee6 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -1,6 +1,6 @@ // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. -// Copyright (C) 2005-2009 Daniel James +// Copyright (C) 2005-2010 Daniel James // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -99,6 +99,8 @@ namespace boost { namespace unordered_detail { template void insert_range_impl(key_type const&, InputIt i, InputIt j); template + void insert_range_impl2(node_constructor&, key_type const&, InputIt i, InputIt j); + template void insert_range_impl(no_key, InputIt i, InputIt j); }; @@ -420,6 +422,36 @@ namespace boost { namespace unordered_detail { //////////////////////////////////////////////////////////////////////////// // Insert range methods + template + template + inline void hash_unique_table::insert_range_impl2( + node_constructor& a, key_type const& k, InputIt i, InputIt j) + { + // No side effects in this initial code + std::size_t hash_value = this->hash_function()(k); + bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); + node_ptr pos = this->find_iterator(bucket, k); + + if (!BOOST_UNORDERED_BORLAND_BOOL(pos)) { + // 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). + a.construct(*i); + + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + if(this->size_ + 1 >= this->max_load_) { + this->reserve_for_insert(this->size_ + insert_size(i, j)); + bucket = this->bucket_ptr_from_hash(hash_value); + } + + // Nothing after this point can throw. + add_node(a, bucket); + } + } + template template inline void hash_unique_table::insert_range_impl( @@ -435,33 +467,14 @@ namespace boost { namespace unordered_detail { } do { - // No side effects in this initial code // Note: can't use get_key as '*i' might not be value_type - it // could be a pair with first_types as key_type without const or a // different second_type. - key_type const& k = extractor::extract(*i); - std::size_t hash_value = this->hash_function()(k); - bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); - node_ptr pos = this->find_iterator(bucket, k); - - if (!BOOST_UNORDERED_BORLAND_BOOL(pos)) { - // 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). - a.construct(*i); - - // reserve has basic exception safety if the hash function - // throws, strong otherwise. - if(this->size_ + 1 >= this->max_load_) { - this->reserve_for_insert(this->size_ + insert_size(i, j)); - bucket = this->bucket_ptr_from_hash(hash_value); - } - - // Nothing after this point can throw. - add_node(a, bucket); - } + // + // TODO: Might be worth storing the value_type instead of the key + // here. Could be more efficient if '*i' is expensive. Could be + // less efficient if copying the full value_type is expensive. + insert_range_impl2(a, extractor::extract(*i), i, j); } while(++i != j); } diff --git a/test/exception/constructor_exception_tests.cpp b/test/exception/constructor_exception_tests.cpp index 96d5c1f2..aa1e02a4 100644 --- a/test/exception/constructor_exception_tests.cpp +++ b/test/exception/constructor_exception_tests.cpp @@ -148,6 +148,19 @@ struct input_range_construct_test : public range, objects } }; +template +struct copy_range_construct_test : public range, objects +{ + copy_range_construct_test() : range(60) {} + + void run() const { + T x(test::copy_iterator(this->values.begin()), + test::copy_iterator(this->values.end()), + 0, hash, equal_to, allocator); + avoid_unused_warning(x); + } +}; + RUN_EXCEPTION_TESTS( (construct_test1) (construct_test2) @@ -160,5 +173,6 @@ RUN_EXCEPTION_TESTS( (range_construct_test3) (range_construct_test4) (range_construct_test5) - (input_range_construct_test), + (input_range_construct_test) + (copy_range_construct_test), CONTAINER_SEQ) diff --git a/test/helpers/input_iterator.hpp b/test/helpers/input_iterator.hpp index 873120cd..1671e0c0 100644 --- a/test/helpers/input_iterator.hpp +++ b/test/helpers/input_iterator.hpp @@ -1,5 +1,5 @@ -// Copyright 2005-2009 Daniel James. +// Copyright 2005-2010 Daniel James. // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -69,6 +69,96 @@ namespace test { return input_iterator_adaptor(it); } + + template + struct copy_iterator_adaptor + : public boost::iterator< + BOOST_DEDUCED_TYPENAME boost::iterator_category::type, + BOOST_DEDUCED_TYPENAME boost::iterator_value::type, + BOOST_DEDUCED_TYPENAME boost::iterator_difference::type, + BOOST_DEDUCED_TYPENAME boost::iterator_pointer::type, + proxy + > + { + typedef BOOST_DEDUCED_TYPENAME boost::iterator_value::type + value_type; + typedef BOOST_DEDUCED_TYPENAME boost::iterator_difference::type + difference_type; + + copy_iterator_adaptor() + : base_() {} + explicit copy_iterator_adaptor(Iterator const& it) + : base_(it) {} + value_type operator*() const { + return *base_; + } + value_type* operator->() const { + return &*base_; + } + value_type operator[](difference_type d) { + return base_[d]; + } + copy_iterator_adaptor& operator++() { + ++base_; return *this; + } + copy_iterator_adaptor operator++(int) { + copy_iterator_adaptor tmp(*this); ++base_; return tmp; + } + copy_iterator_adaptor& operator--() { + --base_; return *this; + } + copy_iterator_adaptor operator--(int) { + copy_iterator_adaptor tmp(*this); --base_; return tmp; + } + copy_iterator_adaptor operator+=(difference_type x) { + base_ += x; + return *this; + } + copy_iterator_adaptor operator-=(difference_type x) { + base_ -= x; + return *this; + } + copy_iterator_adaptor operator+(difference_type n) { + return copy_iterator_adaptor(base_+n); + } + copy_iterator_adaptor operator-(difference_type n) { + return copy_iterator_adaptor(base_-n); + } + friend copy_iterator_adaptor operator+( + difference_type n, copy_iterator_adaptor x) { + return x+n; + } + difference_type operator-(copy_iterator_adaptor const& other) { + return base_-other.base_; + } + bool operator==(copy_iterator_adaptor const& x) const { + return base_ == x.base_; + } + bool operator!=(copy_iterator_adaptor const& x) const { + return base_ != x.base_; + } + bool operator<(copy_iterator_adaptor const& x) const { + return base_ < x.base_; + } + bool operator>(copy_iterator_adaptor const& x) const { + return base_ > x.base_; + } + bool operator<=(copy_iterator_adaptor const& x) const { + return base_ <= x.base_; + } + bool operator>=(copy_iterator_adaptor const& x) const { + return base_ >= x.base_; + } + private: + Iterator base_; + }; + + template + copy_iterator_adaptor copy_iterator(Iterator const& it) + { + return copy_iterator_adaptor(it); + } + } #endif diff --git a/test/unordered/constructor_tests.cpp b/test/unordered/constructor_tests.cpp index e48cecde..489bf01a 100644 --- a/test/unordered/constructor_tests.cpp +++ b/test/unordered/constructor_tests.cpp @@ -1,5 +1,5 @@ -// Copyright 2006-2009 Daniel James. +// Copyright 2006-2010 Daniel James. // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -260,6 +260,19 @@ void constructor_tests2(T*, test::check_equivalent_keys(y); } + std::cerr<<"Construct 8.5 - from copy iterator\n"; + { + test::random_values v(100, generator); + T x(test::copy_iterator(v.begin()), + test::copy_iterator(v.end()), 0, hf1, eq1); + T y(test::copy_iterator(x.begin()), + test::copy_iterator(x.end()), 0, hf2, eq2); + test::check_container(x, v); + test::check_container(y, x); + test::check_equivalent_keys(x); + test::check_equivalent_keys(y); + } + std::cerr<<"Construct 9\n"; { test::random_values v(100, generator); diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 5af8be66..4fee0771 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -1,5 +1,5 @@ -// Copyright 2006-2009 Daniel James. +// Copyright 2006-2010 Daniel James. // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -229,6 +229,18 @@ void insert_tests2(X*, test::check_equivalent_keys(x); } + + std::cerr<<"insert copy iterator range tests.\n"; + + { + X x; + + test::random_values v(1000, generator); + x.insert(test::copy_iterator(v.begin()), test::copy_iterator(v.end())); + test::check_container(x, v); + + test::check_equivalent_keys(x); + } } #if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES) From 54f9626c1298d46e28d89f5ba7aca3155a2f62b7 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 4 Jan 2011 23:05:55 +0000 Subject: [PATCH 057/100] Merge unordered from trunk. - Avoid using operator& with the value type. - More comments in headers. - Remove old clang workaround. - Adjust use of inline to make Borland a little happier. - Avoid `-Wconversion` warnings. [SVN r67663] --- doc/Jamfile.v2 | 3 + include/boost/unordered/detail/buckets.hpp | 2 +- include/boost/unordered/detail/fwd.hpp | 140 ++++++++++++++---- include/boost/unordered/detail/util.hpp | 4 +- include/boost/unordered/unordered_map_fwd.hpp | 12 +- include/boost/unordered/unordered_set_fwd.hpp | 12 +- test/objects/minimal.hpp | 20 +++ test/unordered/Jamfile.v2 | 6 +- test/unordered/fwd_map_test.cpp | 37 +++-- test/unordered/fwd_set_test.cpp | 37 +++-- test/unordered/insert_tests.cpp | 18 +-- test/unordered/load_factor_tests.cpp | 2 +- test/unordered/rehash_tests.cpp | 3 +- 13 files changed, 215 insertions(+), 81 deletions(-) diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index ed333b66..156d8d7c 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -3,6 +3,9 @@ # Distributed under the Boost Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +using boostbook ; +using quickbook ; + path-constant images_location : ../ ; path-constant admonishment_location : ../../../../doc/src/images ; diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index b1dee5cf..913dbcd2 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -64,7 +64,7 @@ namespace boost { namespace unordered_detail { inline void hash_buckets::delete_node(node_ptr b) { node* raw_ptr = static_cast(&*b); - boost::unordered_detail::destroy(&raw_ptr->value()); + boost::unordered_detail::destroy(raw_ptr->value_ptr()); real_node_ptr n(node_alloc().address(*raw_ptr)); node_alloc().destroy(n); node_alloc().deallocate(n, 1); diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index be4d5e1a..471d1d2e 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -21,14 +21,14 @@ // This header defines most of the classes used to implement the unordered // containers. It doesn't include the insert methods as they require a lot -// of preprocessor metaprogramming - they are in insert.hpp +// of preprocessor metaprogramming - they are in unique.hpp and equivalent.hpp. // Template parameters: // // H = Hash Function // P = Predicate // A = Value Allocator -// G = Grouped/Ungrouped +// G = Bucket group policy, 'grouped' or 'ungrouped' // E = Key Extractor #if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES) @@ -90,7 +90,37 @@ namespace boost { namespace unordered_detail { #pragma warning(pop) #endif + //////////////////////////////////////////////////////////////////////////// + // + // This section implements buckets and nodes. Here's a rough + // inheritance diagram, to show how they pull together. + // + // For unordered_set/unordered_map: + // + // hash_bucket + // | + // ungrouped_node_base value_base + // | | + // +--------------+-------------+ + // | + // hash_node + // + // For unordered_multiset/unordered_multimap: + // + // hash_bucket + // | + // grouped_node_base value_base + // | | + // +--------------+-------------+ + // | + // hash_node + // hash_bucket + // + // hash_bucket is used for both the buckets and as a base class for + // nodes. By using 'bucket_ptr' for 'node_ptr', 'next_' can point + // to either a bucket or a node. This is used later to implement a + // sentinel at the end of the bucket array. template class hash_bucket @@ -109,6 +139,16 @@ namespace boost { namespace unordered_detail { hash_bucket() : next_() {} }; + // In containers with equivalent keys (unordered_multimap and + // unordered_multiset) equivalent nodes are grouped together, in + // containers with unique keys (unordered_map and unordered_set) + // individual nodes are treated as groups of one. The following two + // classes implement the data structure. + + // This is used for containers with unique keys. There are no groups + // so it doesn't add any extra members, and just treats individual + // nodes as groups of one. + template struct ungrouped_node_base : hash_bucket { typedef hash_bucket bucket; @@ -125,6 +165,10 @@ namespace boost { namespace unordered_detail { static void unlink_nodes(bucket& b, node_ptr end); }; + // This is used for containers with equivalent keys. It implements a + // circular list running in the opposite direction to the linked + // list through the nodes. + template struct grouped_node_base : hash_bucket { @@ -151,6 +195,10 @@ namespace boost { namespace unordered_detail { } }; + // These two classes implement an easy way to pass around the node + // group policy classes without the messy template parameters. + // Whenever you see the template parameter 'G' it's one of these. + struct ungrouped { template @@ -167,6 +215,8 @@ namespace boost { namespace unordered_detail { }; }; + // The space used to store values in a node. + template struct value_base { @@ -181,6 +231,9 @@ namespace boost { namespace unordered_detail { value_type& value() { return *(ValueType*) this; } + value_type* value_ptr() { + return (ValueType*) this; + } private: value_base& operator=(value_base const&); }; @@ -199,11 +252,20 @@ namespace boost { namespace unordered_detail { static value_type& get_value(node_ptr p) { return static_cast(*p).value(); } + static value_type* get_value_ptr(node_ptr p) { + return static_cast(*p).value_ptr(); + } private: hash_node& operator=(hash_node const&); }; + //////////////////////////////////////////////////////////////////////////// + // // Iterator Base + // + // This is the iterator used internally, the external iterators are + // provided by lightweight wrappers (hash_iterator and + // hast_const_iterator) which provide the full iterator interface. template class hash_iterator_base @@ -248,12 +310,24 @@ namespace boost { namespace unordered_detail { } }; + //////////////////////////////////////////////////////////////////////////// + // + // Now the main data structure: + // + // hash_buckets hash_buffered_functions + // | | + // +-------------+--------------+ + // | + // hash_table + // + // T is a class which contains typedefs for all the types we need. + // hash_buckets // // This is responsible for allocating and deallocating buckets and nodes. // // Notes: - // 1. For the sake exception safety the allocators themselves don't allocate + // 1. For the sake exception safety the consturctors don't allocate // anything. // 2. It's the callers responsibility to allocate the buckets before calling // any of the methods (other than getters and setters). @@ -327,6 +401,17 @@ namespace boost { namespace unordered_detail { std::size_t delete_to_bucket_end(node_ptr begin); }; + // Assigning and swapping the equality and hash function objects + // needs strong exception safety. To implement that normally we'd + // require one of them to be known to not throw and the other to + // guarantee strong exception safety. Unfortunately they both only + // have basic exception safety. So to acheive strong exception + // safety we have storage space for two copies, and assign the new + // copies to the unused space. Then switch to using that to use + // them. This is implemented in 'set_hash_functions' which + // atomically assigns the new function objects in a strongly + // exception safe manner. + template class set_hash_functions; template @@ -429,6 +514,12 @@ namespace boost { namespace unordered_detail { } }; + // This implements almost all of the required functionality, apart + // from some things that are specific to containers with unique and + // equivalent keys which is implemented in hash_unique_table and + // hash_equivalent_table. See unique.hpp and equivalent.hpp for + // their declaration and implementation. + template class hash_table : public T::buckets, public T::buffered_functions { @@ -569,9 +660,13 @@ namespace boost { namespace unordered_detail { node_constructor&, std::size_t); }; - // Iterator Access + /////////////////////////////////////////////////////////////////// + // + // Iterators + + // iterator_access is used to access the internal iterator without + // making it publicly available. -#if !defined(__clang__) class iterator_access { public: @@ -582,30 +677,6 @@ namespace boost { namespace unordered_detail { return it.base_; } }; -#else - class iterator_access - { - public: - // Note: we access Iterator::base here, rather than in the function - // signature to work around a bug in the friend support of an - // early version of clang. - - template - struct base - { - typedef BOOST_DEDUCED_TYPENAME Iterator::base type; - }; - - template - static BOOST_DEDUCED_TYPENAME base::type const& - get(Iterator const& it) - { - return it.base_; - } - }; -#endif - - // Iterators template class hash_iterator; template class hash_const_iterator; @@ -644,7 +715,7 @@ namespace boost { namespace unordered_detail { return node::get_value(ptr_); } value_type* operator->() const { - return &node::get_value(ptr_); + return node::get_value_ptr(ptr_); } hash_local_iterator& operator++() { ptr_ = ptr_->next_; return *this; @@ -694,7 +765,7 @@ namespace boost { namespace unordered_detail { return node::get_value(ptr_); } value_type const* operator->() const { - return &node::get_value(ptr_); + return node::get_value_ptr(ptr_); } hash_const_local_iterator& operator++() { ptr_ = ptr_->next_; return *this; @@ -716,7 +787,7 @@ namespace boost { namespace unordered_detail { } }; - // iterators + // Iterators // // all no throw @@ -823,7 +894,12 @@ namespace boost { namespace unordered_detail { } }; + //////////////////////////////////////////////////////////////////////////// + // // types + // + // This is used to convieniently pass around a container's typedefs + // without having 7 template parameters. template struct types diff --git a/include/boost/unordered/detail/util.hpp b/include/boost/unordered/detail/util.hpp index 55409651..989883e0 100644 --- a/include/boost/unordered/detail/util.hpp +++ b/include/boost/unordered/detail/util.hpp @@ -299,7 +299,7 @@ namespace boost { namespace unordered_detail { #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) struct dummy { hash_node x; }; #endif - boost::unordered_detail::destroy(&node_->value()); + boost::unordered_detail::destroy(node_->value_ptr()); } if (node_constructed_) @@ -322,7 +322,7 @@ namespace boost { namespace unordered_detail { } else { BOOST_ASSERT(node_constructed_ && value_constructed_); - boost::unordered_detail::destroy(&node_->value()); + boost::unordered_detail::destroy(node_->value_ptr()); value_constructed_ = false; } } diff --git a/include/boost/unordered/unordered_map_fwd.hpp b/include/boost/unordered/unordered_map_fwd.hpp index 5e9bb076..edecc5d9 100644 --- a/include/boost/unordered/unordered_map_fwd.hpp +++ b/include/boost/unordered/unordered_map_fwd.hpp @@ -24,13 +24,13 @@ namespace boost class A = std::allocator > > class unordered_map; template - bool operator==(unordered_map const&, + inline bool operator==(unordered_map const&, unordered_map const&); template - bool operator!=(unordered_map const&, + inline bool operator!=(unordered_map const&, unordered_map const&); template - void swap(unordered_map&, + inline void swap(unordered_map&, unordered_map&); template > > class unordered_multimap; template - bool operator==(unordered_multimap const&, + inline bool operator==(unordered_multimap const&, unordered_multimap const&); template - bool operator!=(unordered_multimap const&, + inline bool operator!=(unordered_multimap const&, unordered_multimap const&); template - void swap(unordered_multimap&, + inline void swap(unordered_multimap&, unordered_multimap&); } diff --git a/include/boost/unordered/unordered_set_fwd.hpp b/include/boost/unordered/unordered_set_fwd.hpp index 8000eb14..fead1243 100644 --- a/include/boost/unordered/unordered_set_fwd.hpp +++ b/include/boost/unordered/unordered_set_fwd.hpp @@ -23,13 +23,13 @@ namespace boost class A = std::allocator > class unordered_set; template - bool operator==(unordered_set const&, + inline bool operator==(unordered_set const&, unordered_set const&); template - bool operator!=(unordered_set const&, + inline bool operator!=(unordered_set const&, unordered_set const&); template - void swap(unordered_set &m1, + inline void swap(unordered_set &m1, unordered_set &m2); template > class unordered_multiset; template - bool operator==(unordered_multiset const&, + inline bool operator==(unordered_multiset const&, unordered_multiset const&); template - bool operator!=(unordered_multiset const&, + inline bool operator!=(unordered_multiset const&, unordered_multiset const&); template - void swap(unordered_multiset &m1, + inline void swap(unordered_multiset &m1, unordered_multiset &m2); } diff --git a/test/objects/minimal.hpp b/test/objects/minimal.hpp index 4f8680fb..1cd8a2d3 100644 --- a/test/objects/minimal.hpp +++ b/test/objects/minimal.hpp @@ -26,6 +26,8 @@ namespace minimal class default_copy_constructible; class assignable; + struct ampersand_operator_used {}; + template class hash; template class equal_to; template class ptr; @@ -63,6 +65,7 @@ namespace minimal copy_constructible_equality_comparable& operator=( copy_constructible_equality_comparable const&); copy_constructible_equality_comparable() {} + ampersand_operator_used operator&() const { return ampersand_operator_used(); } }; bool operator==( @@ -98,9 +101,11 @@ namespace minimal ~default_copy_constructible() { } + private: default_copy_constructible& operator=( default_copy_constructible const&); + ampersand_operator_used operator&() const { return ampersand_operator_used(); } }; class assignable @@ -110,8 +115,11 @@ namespace minimal assignable(assignable const&) {} assignable& operator=(assignable const&) { return *this; } ~assignable() {} + private: assignable() {} + // TODO: This messes up a concept check in the tests. + //ampersand_operator_used operator&() const { return ampersand_operator_used(); } }; template @@ -125,6 +133,8 @@ namespace minimal ~hash() {} std::size_t operator()(T const&) const { return 0; } + private: + ampersand_operator_used operator&() const { return ampersand_operator_used(); } }; template @@ -138,6 +148,8 @@ namespace minimal ~equal_to() {} bool operator()(T const&, T const&) const { return true; } + private: + ampersand_operator_used operator&() const { return ampersand_operator_used(); } }; template class ptr; @@ -182,6 +194,9 @@ namespace minimal bool operator>(const_ptr const& x) const { return ptr_ > x.ptr_; } bool operator<=(const_ptr const& x) const { return ptr_ <= x.ptr_; } bool operator>=(const_ptr const& x) const { return ptr_ >= x.ptr_; } + private: + // TODO: + //ampersand_operator_used operator&() const { return ampersand_operator_used(); } }; template @@ -221,6 +236,9 @@ namespace minimal bool operator>(const_ptr const& x) const { return ptr_ > x.ptr_; } bool operator<=(const_ptr const& x) const { return ptr_ <= x.ptr_; } bool operator>=(const_ptr const& x) const { return ptr_ >= x.ptr_; } + private: + // TODO: + //ampersand_operator_used operator&() const { return ampersand_operator_used(); } }; template @@ -278,6 +296,8 @@ namespace minimal #else private: allocator& operator=(allocator const&); #endif + private: + ampersand_operator_used operator&() const { return ampersand_operator_used(); } }; template diff --git a/test/unordered/Jamfile.v2 b/test/unordered/Jamfile.v2 index 07be6c28..fc343747 100644 --- a/test/unordered/Jamfile.v2 +++ b/test/unordered/Jamfile.v2 @@ -9,8 +9,8 @@ project unordered-test/unordered : requirements all intel:on - gcc:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter" - darwin:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter" + gcc:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion" + darwin:"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion" gcc:_GLIBCXX_DEBUG #darwin:_GLIBCXX_DEBUG msvc:on @@ -30,7 +30,7 @@ test-suite unordered [ run equivalent_keys_tests.cpp ] [ run constructor_tests.cpp ] [ run copy_tests.cpp ] - [ run move_tests.cpp : : : always_show_run_output ] + [ run move_tests.cpp ] [ run assign_tests.cpp ] [ run insert_tests.cpp ] [ run insert_stable_tests.cpp ] diff --git a/test/unordered/fwd_map_test.cpp b/test/unordered/fwd_map_test.cpp index 531d573c..dc2267bf 100644 --- a/test/unordered/fwd_map_test.cpp +++ b/test/unordered/fwd_map_test.cpp @@ -7,37 +7,54 @@ #include -typedef boost::unordered_map int_map; - -void call_swap(int_map& x, int_map& y) { +template +void call_swap(boost::unordered_map& x, + boost::unordered_map& y) +{ swap(x,y); } -bool call_equals(int_map& x, int_map& y) { +template +bool call_equals(boost::unordered_map& x, + boost::unordered_map& y) +{ return x == y; } -bool call_not_equals(int_map& x, int_map& y) { +template +bool call_not_equals(boost::unordered_map& x, + boost::unordered_map& y) +{ return x != y; } -typedef boost::unordered_multimap int_multimap; - -void call_swap(int_multimap& x, int_multimap& y) { +template +void call_swap(boost::unordered_multimap& x, + boost::unordered_multimap& y) +{ swap(x,y); } -bool call_equals(int_multimap& x, int_multimap& y) { +template +bool call_equals(boost::unordered_multimap& x, + boost::unordered_multimap& y) +{ return x == y; } -bool call_not_equals(int_multimap& x, int_multimap& y) { +template +bool call_not_equals(boost::unordered_multimap& x, + boost::unordered_multimap& y) +{ return x != y; } #include #include "../helpers/test.hpp" +typedef boost::unordered_map int_map; +typedef boost::unordered_multimap int_multimap; + UNORDERED_AUTO_TEST(use_map_fwd_declared_function) { int_map x, y; x[1] = 2; diff --git a/test/unordered/fwd_set_test.cpp b/test/unordered/fwd_set_test.cpp index 7fc3a8c1..4fa66b90 100644 --- a/test/unordered/fwd_set_test.cpp +++ b/test/unordered/fwd_set_test.cpp @@ -16,36 +16,53 @@ template true_type is_unordered_set_impl( boost::unordered_set*); -typedef boost::unordered_set int_set; - -void call_swap(int_set& x, int_set& y) { +template +void call_swap(boost::unordered_set& x, + boost::unordered_set& y) +{ swap(x,y); } -bool call_equals(int_set& x, int_set& y) { +template +bool call_equals(boost::unordered_set& x, + boost::unordered_set& y) +{ return x == y; } -bool call_not_equals(int_set& x, int_set& y) { +template +bool call_not_equals(boost::unordered_set& x, + boost::unordered_set& y) +{ return x != y; } -typedef boost::unordered_multiset int_multiset; - -void call_swap(int_multiset& x, int_multiset& y) { +template +void call_swap(boost::unordered_multiset& x, + boost::unordered_multiset& y) +{ swap(x,y); } -bool call_equals(int_multiset& x, int_multiset& y) { +template +bool call_equals(boost::unordered_multiset& x, + boost::unordered_multiset& y) +{ return x == y; } -bool call_not_equals(int_multiset& x, int_multiset& y) { +template +bool call_not_equals(boost::unordered_multiset& x, + boost::unordered_multiset& y) +{ return x != y; } #include "../helpers/test.hpp" +typedef boost::unordered_set int_set; +typedef boost::unordered_multiset int_multiset; + UNORDERED_AUTO_TEST(use_fwd_declared_trait_without_definition) { BOOST_TEST(sizeof(is_unordered_set_impl((int_set*) 0)) == sizeof(true_type)); diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 4fee0771..d832c7d2 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -52,7 +52,7 @@ void unique_insert_tests1(X*, tracker.compare_key(x, *it); - if(x.size() < b * old_bucket_count) + if(static_cast(x.size()) < b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } @@ -83,7 +83,7 @@ void equivalent_insert_tests1(X*, tracker.compare_key(x, *it); - if(x.size() < b * old_bucket_count) + if(static_cast(x.size()) < b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } @@ -118,7 +118,7 @@ void insert_tests2(X*, BOOST_TEST(*r1 == *r2); tracker.compare_key(x, *it); - if(x.size() < b * old_bucket_count) + if(static_cast(x.size()) < b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } @@ -145,7 +145,7 @@ void insert_tests2(X*, BOOST_TEST(*r1 == *r2); tracker.compare_key(x, *it); - if(x.size() < b * old_bucket_count) + if(static_cast(x.size()) < b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } @@ -172,7 +172,7 @@ void insert_tests2(X*, BOOST_TEST(*pos == *r2); tracker.compare_key(x, *it); - if(x.size() < b * old_bucket_count) + if(static_cast(x.size()) < b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } @@ -197,7 +197,7 @@ void insert_tests2(X*, tracker.insert(*it); tracker.compare_key(x, *it); - if(x.size() < b * old_bucket_count) + if(static_cast(x.size()) < b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } @@ -275,7 +275,7 @@ void unique_emplace_tests1(X*, tracker.compare_key(x, *it); - if(x.size() < b * old_bucket_count) + if(static_cast(x.size()) < b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } @@ -306,7 +306,7 @@ void equivalent_emplace_tests1(X*, tracker.compare_key(x, *it); - if(x.size() < b * old_bucket_count) + if(static_cast(x.size()) < b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } @@ -335,7 +335,7 @@ void map_tests(X*, test::random_generator generator = test::default_generator) tracker.compare_key(x, *it); - if(x.size() < b * old_bucket_count) + if(static_cast(x.size()) < b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } diff --git a/test/unordered/load_factor_tests.cpp b/test/unordered/load_factor_tests.cpp index 52cd0456..8788da9b 100644 --- a/test/unordered/load_factor_tests.cpp +++ b/test/unordered/load_factor_tests.cpp @@ -51,7 +51,7 @@ void insert_test(X*, float mlf, BOOST_DEDUCED_TYPENAME X::size_type old_size = x.size(), old_bucket_count = x.bucket_count(); x.insert(*it); - if(old_size + 1 < b * old_bucket_count) + if(static_cast(old_size + 1) < b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } } diff --git a/test/unordered/rehash_tests.cpp b/test/unordered/rehash_tests.cpp index 9b419e8d..434389b0 100644 --- a/test/unordered/rehash_tests.cpp +++ b/test/unordered/rehash_tests.cpp @@ -19,7 +19,8 @@ test::seed_t seed(2974); template bool postcondition(X const& x, BOOST_DEDUCED_TYPENAME X::size_type n) { - return x.bucket_count() > x.size() / x.max_load_factor() && + return static_cast(x.bucket_count()) > + static_cast(x.size()) / x.max_load_factor() && x.bucket_count() >= n; } From 147181530de32a5ef729bdf1957ab938b6f7200d Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 2 Mar 2011 08:47:34 +0000 Subject: [PATCH 058/100] Add copy constructors and assignment operators when using rvalue references. Fixes #5119. [SVN r69469] --- include/boost/unordered/unordered_map.hpp | 22 ++++++++++++++++++++++ include/boost/unordered/unordered_set.hpp | 22 ++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 5bad0ebd..86a6fc63 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -160,6 +160,11 @@ namespace boost ~unordered_map() {} #if !defined(BOOST_NO_RVALUE_REFERENCES) + unordered_map(unordered_map const& other) + : table_(other.table_) + { + } + unordered_map(unordered_map&& other) : table_(other.table_, boost::unordered_detail::move_tag()) { @@ -170,6 +175,12 @@ namespace boost { } + unordered_map& operator=(unordered_map const& x) + { + table_ = x.table_; + return *this; + } + unordered_map& operator=(unordered_map&& x) { table_.move(x.table_); @@ -705,6 +716,11 @@ namespace boost ~unordered_multimap() {} #if !defined(BOOST_NO_RVALUE_REFERENCES) + unordered_multimap(unordered_multimap const& other) + : table_(other.table_) + { + } + unordered_multimap(unordered_multimap&& other) : table_(other.table_, boost::unordered_detail::move_tag()) { @@ -715,6 +731,12 @@ namespace boost { } + unordered_multimap& operator=(unordered_multimap const& x) + { + table_ = x.table_; + return *this; + } + unordered_multimap& operator=(unordered_multimap&& x) { table_.move(x.table_); diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index ec48b8c8..89d1c1cf 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -154,6 +154,11 @@ namespace boost ~unordered_set() {} #if !defined(BOOST_NO_RVALUE_REFERENCES) + unordered_set(unordered_set const& other) + : table_(other.table_) + { + } + unordered_set(unordered_set&& other) : table_(other.table_, boost::unordered_detail::move_tag()) { @@ -164,6 +169,12 @@ namespace boost { } + unordered_set& operator=(unordered_set const& x) + { + table_ = x.table_; + return *this; + } + unordered_set& operator=(unordered_set&& x) { table_.move(x.table_); @@ -651,6 +662,11 @@ namespace boost ~unordered_multiset() {} #if !defined(BOOST_NO_RVALUE_REFERENCES) + unordered_multiset(unordered_multiset const& other) + : table_(other.table_) + { + } + unordered_multiset(unordered_multiset&& other) : table_(other.table_, boost::unordered_detail::move_tag()) { @@ -661,6 +677,12 @@ namespace boost { } + unordered_multiset& operator=(unordered_multiset const& x) + { + table_ = x.table_; + return *this; + } + unordered_multiset& operator=(unordered_multiset&& x) { table_.move(x.table_); From 3fd5635d7d831943191e5b51781649d4ebebef62 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 23 Mar 2011 00:07:17 +0000 Subject: [PATCH 059/100] Unordered: Fix some overly strict tests. [SVN r70443] --- test/objects/test.hpp | 65 ++++++++++------------- test/unordered/insert_tests.cpp | 4 +- test/unordered/unnecessary_copy_tests.cpp | 2 +- 3 files changed, 30 insertions(+), 41 deletions(-) diff --git a/test/objects/test.hpp b/test/objects/test.hpp index bfada4d2..44a241d2 100644 --- a/test/objects/test.hpp +++ b/test/objects/test.hpp @@ -20,11 +20,13 @@ namespace test // Note that the default hash function will work for any equal_to (but not // very well). class object; + class implicitly_convertible; class hash; class less; class equal_to; template class allocator; object generate(object const*); + implicitly_convertible generate(implicitly_convertible const*); class object : globally_counted_object { @@ -64,6 +66,31 @@ namespace test } }; + class implicitly_convertible : globally_counted_object + { + int tag1_, tag2_; + public: + + explicit implicitly_convertible(int t1 = 0, int t2 = 0) + : tag1_(t1), tag2_(t2) + {} + + operator object() const + { + return object(tag1_, tag2_); + } + + friend implicitly_convertible generate(implicitly_convertible const*) { + int* x = 0; + return implicitly_convertible(generate(x), generate(x)); + } + + friend std::ostream& operator<<(std::ostream& out, implicitly_convertible const& o) + { + return out<<"("< - void swap(test::allocator& x, test::allocator& y) { - test::allocator tmp; - tmp = x; - x = y; - y = tmp; - } -#endif } #endif diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index d832c7d2..30d6bd8d 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -372,10 +372,10 @@ void map_insert_range_test2(X*, std::cerr<<"map_insert_range_test2\n"; typedef test::list< - std::pair + std::pair > list; test::random_values< - boost::unordered_map + boost::unordered_map > v(1000, generator); list l(v.begin(), v.end()); diff --git a/test/unordered/unnecessary_copy_tests.cpp b/test/unordered/unnecessary_copy_tests.cpp index 58bc3b70..2f59f2fa 100644 --- a/test/unordered/unnecessary_copy_tests.cpp +++ b/test/unordered/unnecessary_copy_tests.cpp @@ -261,7 +261,7 @@ namespace unnecessary_copy_tests // copied. reset(); x.emplace(source >()); - COPY_COUNT(2); MOVE_COUNT(0); + COPY_COUNT(2); MOVE_COUNT_RANGE(0,2); // TODO: This doesn't work on older versions of gcc. //count_copies part; From a4372314c280a1ae2493fedfcd5aa16f8f41703b Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 21 Aug 2011 19:19:12 +0000 Subject: [PATCH 060/100] Unordered: Merge to release. Using Boost.Move and better C++11 support. [SVN r73987] --- doc/changes.qbk | 17 + doc/compliance.qbk | 54 + doc/rationale.qbk | 2 +- doc/ref.php | 1040 ++++++++++ doc/ref.xml | 128 +- doc/unordered.qbk | 1 + .../unordered/detail/allocator_helpers.hpp | 273 ++- include/boost/unordered/detail/buckets.hpp | 927 +++++++-- include/boost/unordered/detail/equivalent.hpp | 479 ++--- .../boost/unordered/detail/extract_key.hpp | 31 +- include/boost/unordered/detail/fwd.hpp | 956 +-------- include/boost/unordered/detail/move.hpp | 243 --- include/boost/unordered/detail/node.hpp | 502 +++-- include/boost/unordered/detail/table.hpp | 1342 +++++++------ include/boost/unordered/detail/unique.hpp | 750 ++++---- include/boost/unordered/detail/util.hpp | 368 ++-- include/boost/unordered/unordered_map.hpp | 1702 +++++++++++------ include/boost/unordered/unordered_map_fwd.hpp | 64 +- include/boost/unordered/unordered_set.hpp | 1525 +++++++++------ include/boost/unordered/unordered_set_fwd.hpp | 62 +- test/exception/swap_exception_tests.cpp | 14 +- test/helpers/count.hpp | 7 + test/helpers/invariants.hpp | 49 +- test/helpers/memory.hpp | 37 +- test/objects/cxx11_allocator.hpp | 294 +++ test/objects/exception.hpp | 22 +- test/objects/minimal.hpp | 144 +- test/objects/test.hpp | 31 +- test/unordered/Jamfile.v2 | 2 +- test/unordered/assign_tests.cpp | 87 +- test/unordered/bucket_tests.cpp | 2 + test/unordered/compile_map.cpp | 100 +- test/unordered/compile_set.cpp | 192 +- test/unordered/compile_tests.hpp | 223 ++- test/unordered/constructor_tests.cpp | 43 + test/unordered/copy_tests.cpp | 81 +- test/unordered/equality_tests.cpp | 8 +- test/unordered/erase_tests.cpp | 14 + test/unordered/find_tests.cpp | 4 + test/unordered/insert_tests.cpp | 23 + test/unordered/move_tests.cpp | 139 +- test/unordered/swap_tests.cpp | 135 +- test/unordered/unnecessary_copy_tests.cpp | 141 +- 43 files changed, 7656 insertions(+), 4602 deletions(-) create mode 100644 doc/compliance.qbk create mode 100644 doc/ref.php delete mode 100644 include/boost/unordered/detail/move.hpp create mode 100644 test/objects/cxx11_allocator.hpp diff --git a/doc/changes.qbk b/doc/changes.qbk index 7fb950a6..58a16854 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -134,4 +134,21 @@ First official release. * Fix a bug when inserting into an `unordered_map` or `unordered_set` using iterators which returns `value_type` by copy. +[h2 Boost 1.48.0] + +This is major change which has been converted to use Boost.Move's move +emulation, and be more compliant with the C++11 standard. This has resulted +in some breaking changes: + +* Equality comparison has been changed to the C++11 specification. + In a container with equivalent keys, elements in a group with equal + keys used to have to be in the same order to be considered equal, + now they can be a permutation of each other. + +* The behaviour of swap is different when the two containers to be + swapped has unequal allocators. It used to allocate new nodes using + the appropriate allocators, it now swaps the allocators if + the allocator has a member structure `propagate_on_container_swap`, + such that `propagate_on_container_swap::value` is true. + [endsect] diff --git a/doc/compliance.qbk b/doc/compliance.qbk new file mode 100644 index 00000000..759d9bde --- /dev/null +++ b/doc/compliance.qbk @@ -0,0 +1,54 @@ +[/ Copyright 2011 Daniel James. + / Distributed under the Boost Software License, Version 1.0. (See accompanying + / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ] + +[section:compliance C++11 Compliance] + +/TODO/: Look into C++11's `std::pair`. + +[section:allocator_compliance Use of allocators] + +* Objects are not constructed using the allocator. The node containing them + is constructed using the allocator's `construct` function, but then the + object is constructed in a buffer in that node by calling the constructor + directly. +* Similarly the object is destructed by calling its destructor directly, and + then the allocator's `destroy` method is used to destruct the node. +* For most compilers `select_on_container_copy` is only detected for an + exact signature match in the allocator itself - not in a base. There is full + detection for g++ 4.4 or laster, Visual C++ 2008 or later, Clang and maybe + other compilers which support SFINAE for expressions. +* `pointer_traits` aren't used. Instead, pointer types are obtained from + rebound allocators. +* /TODO/: Any other defficiences of `allocator_traits` emulation. +* Pointers of base types are used to store the location of a derived type. + (/TODO/: I'm not sure if that isn't compliant). + +[endsect] + +[section:move Move emulation] + +Move emulation is implemented using Boost.Move. If rvalue references are +available it will use them, but if not it uses a close, but imperfect emulation +and to get the advantage of using movable container elements, you'll need to +use Boost.Move. + +* Non-copyable objects can be stored in the containers, but without support + for rvalue references the container will not be movable. +* The number of arguments used in emplace is limited to /TODO/. +* Argument forwarding is not perfect. +* /TODO/: Constructor call for pairs. + +[endsect] + +[section:other Other] + +* When swapping, `Pred` and `Hash` are not currently swapped by calling + `swap`, their copy constructors are used. +* As a consequence when swapping an exception may be throw from their + copy constructor. + + +[endsect] + +[endsect] diff --git a/doc/rationale.qbk b/doc/rationale.qbk index ff371386..6662f13e 100644 --- a/doc/rationale.qbk +++ b/doc/rationale.qbk @@ -126,7 +126,7 @@ a little to accomodate non-C++0x compilers. It isn't clear how to swap containers when their allocators aren't equal. This is -[@http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#431 +[@http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#431 Issue 431: Swapping containers with unequal allocators]. This has been resolved with the new allocator specification, so this should be fixed when support is added. diff --git a/doc/ref.php b/doc/ref.php new file mode 100644 index 00000000..66f4d930 --- /dev/null +++ b/doc/ref.php @@ -0,0 +1,1040 @@ + + + + + +EOL; + + $key_type = 'Key'; + $key_name = 'key'; + $value_type = 'std::pair<Key const, Mapped>'; + $full_type = $name.'<Key, Mapped, Hash, Pred, Alloc>'; + } + else + { + $template_value = << + + +EOL; + + $key_type = 'Value'; + $key_name = 'value'; + $value_type = 'Value'; + $full_type = $name.'<Value, Hash, Pred, Alloc>'; + } +?> + + + + An unordered associative container that + + + + Based on chapter 23 of + the working draft of the C++ standard [n2960]. + But without the updated rules for allocators. + + Template Parameters + + + + + + Key + Key must be Assignable and CopyConstructible. + + Mapped + Mapped must be CopyConstructible + + + Value + Value must be Assignable and CopyConstructible + + + Hash + A unary function object type that acts a hash function for a . It takes a single argument of type and returns a value of type std::size_t. + + Pred + A binary function object that implements an equivalence relation on values of type . + A binary function object that induces an equivalence relation on values of type . + It takes two arguments of type and returns a value of type bool. + + Alloc + An allocator whose value type is the same as the container's value type. + The elements are organized into buckets. + The number of buckets can be automatically increased by a call to insert, or as the result of calling rehash. + + + + + + + + + + Mapped + + + + Hash + + + Pred + + + Alloc + + + typename allocator_type::pointer + + + typename allocator_type::const_pointer + + + typename allocator_type::reference + lvalue of value_type. + + + typename allocator_type::const_reference + const lvalue of value_type. + + + implementation-defined + + An unsigned integral type. + size_type can represent any non-negative value of difference_type. + + + + implementation-defined + + A signed integral type. + Is identical to the difference type of iterator and const_iterator. + + + + implementation-defined + + iterator whose value type is value_type. + The iterator category is at least a forward iterator. + Convertible to const_iterator. + + + + implementation-defined + + A constant iterator whose value type is value_type. + The iterator category is at least a forward iterator. + + + + implementation-defined + + An iterator with the same value type, difference type and pointer and reference type as iterator. + A local_iterator object can be used to iterate through a single bucket. + + + + implementation-defined + + A constant iterator with the same value type, difference type and pointer and reference type as const_iterator. + A const_local_iterator object can be used to iterate through a single bucket. + + + + + size_type + implementation-defined + + + hasher const& + hasher() + + + key_equal const& + key_equal() + + + allocator_type const& + allocator_type() + + + size() == 0 + + + Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0. + + + + + + InputIterator + + + InputIterator + + + size_type + implementation-defined + + + hasher const& + hasher() + + + key_equal const& + key_equal() + + + allocator_type const& + allocator_type() + + + Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0 and inserts the elements from [f, l) into it. + + + + + const& + + + The copy constructor. Copies the contained elements, hash function, predicate, maximum load factor and allocator. + + + value_type is copy constructible + + + + + && + + + The move constructor. + + + This is emulated on compilers without rvalue references. + + + + value_type is move constructible. + (TODO: This is not actually required in this implementation). + + + + + + Allocator const& + + + Constructs an empty container, using allocator a. + + + + + const& + + + Allocator const& + + + Constructs an container, copying x's contained elements, hash function, predicate, maximum load factor, but using allocator a. + + + + + The destructor is applied to every element, and all memory is deallocated + + + + + const& + + & + + The assignment operator. Copies the contained elements, hash function, predicate and maximum load factor but not the allocator. + + + + On compilers without rvalue references, there is a single assignment + operator with the signature operator=() + in order to emulate move semantics. + + + + value_type is copy constructible + + + + + && + + & + + The move assignment operator. + + + + On compilers without rvalue references, there is a single assignment + operator with the signature operator=() + in order to emulate move semantics. + + + + + value_type is move constructible. + (TODO: This is not actually required in this implementation). + + + + + allocator_type + + + + bool + + size() == 0 + + + + size_type + + std::distance(begin(), end()) + + + + size_type + size() of the largest possible container. + + + + + + iterator + const_iterator + An iterator referring to the first element of the container, or if the container is empty the past-the-end value for the container. + + + + + iterator + + + const_iterator + + An iterator which refers to the past-the-end value for the container. + + + + const_iterator + A constant iterator referring to the first element of the container, or if the container is empty the past-the-end value for the container. + + + + const_iterator + A constant iterator which refers to the past-the-end value for the container. + + + + + + + + Args&& + + + + Inserts an object, constructed with the arguments args, in the container + + + + An iterator pointing to the inserted element. + + The bool component of the return type is true if an insert took place. + If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent . + + + + If an exception is thrown by an operation other than a call to hasher the function has no effect. + + + Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + Pointers and references to elements are never invalidated. + If the compiler doesn't support variadic template arguments or rvalue + references, this is emulated for up to 10 arguments, with no support + for rvalue references or move semantics. + + + + + + const_iterator + + + Args&& + + iterator + + Inserts an object, constructed with the arguments args, in the container + hint is a suggestion to where the element should be inserted. + + + + An iterator pointing to the inserted element. + + If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent . + + + + If an exception is thrown by an operation other than a call to hasher the function has no effect. + + + 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 . + Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + Pointers and references to elements are never invalidated. + If the compiler doesn't support variadic template arguments or rvalue + references, this is emulated for up to 10 arguments, with no support + for rvalue references or move semantics. + + + + + value_type const& + + + + Inserts obj in the container + + + + An iterator pointing to the inserted element. + + The bool component of the return type is true if an insert took place. + If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent . + + + + If an exception is thrown by an operation other than a call to hasher the function has no effect. + + + Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + Pointers and references to elements are never invalidated. + + + + + const_iterator + + + value_type const& + + iterator + + + Inserts obj in the container. + + Inserts obj in the container if and only if there is no element in the container with an equivalent . + + hint is a suggestion to where the element should be inserted. + + + + An iterator pointing to the inserted element. + + If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent . + + + + If an exception is thrown by an operation other than a call to hasher the function has no effect. + + + 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 . + Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + Pointers and references to elements are never invalidated. + + + + + + InputIterator + + + InputIterator + + void + + Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent . + + + When inserting a single element, if an exception is thrown by an operation other than a call to hasher the function has no effect. + + + Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + Pointers and references to elements are never invalidated. + + + + + const_iterator + + iterator + + Erase the element pointed to by position. + + + The iterator following position before the erasure. + + + Only throws an exception if it is thrown by hasher or key_equal. + In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + + + + When the number of elements is a lot smaller than the number of buckets + this function can be very inefficient as it has to search through empty + buckets for the next element, in order to return the iterator. + The method quick_erase is faster, but has yet + to be standardized. + + + + + + key_type const& + + size_type + + Erase all elements with key equivalent to k. + + + The number of elements erased. + + + Only throws an exception if it is thrown by hasher or key_equal. + + + + + const_iterator + + + const_iterator + + iterator + + Erases the elements in the range from first to last. + + + The iterator following the erased elements - i.e. last. + + + Only throws an exception if it is thrown by hasher or key_equal. + In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + + + + + const_iterator + + void + + Erase the element pointed to by position. + + + Only throws an exception if it is thrown by hasher or key_equal. + In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + + + + This method is faster than erase as + it doesn't have to find the next element in the container - + a potentially costly operation. + + + As it hasn't been standardized, it's likely that this may + change in the future. + + + + + + const_iterator + + void + + Erase the element pointed to by position. + + + Only throws an exception if it is thrown by hasher or key_equal. + In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + + + + This method is now deprecated, use + quick_return instead. Although be + warned that as that isn't standardized yet, it could also + change. + + + + + void + + Erases all elements in the container. + + + size() == 0 + + + Never throws an exception. + + + + + & + + void + + If the allocators are equal, doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of key_equal or hasher. + + + For a discussion of the behavior when allocators aren't equal see + the implementation details. + + + + + + hasher + The container's hash function. + + + + key_equal + The container's key equality predicate. + + + + + + + + key_type const& + + iterator + + + + key_type const& + + const_iterator + + + + + CompatibleKey const& + + + CompatibleHash const& + + + CompatiblePredicate const& + + iterator + + + + + CompatibleKey const& + + + CompatibleHash const& + + + CompatiblePredicate const& + + const_iterator + + + An iterator pointing to an element with key equivalent to k, or b.end() if no such element exists. + + + The templated overloads are a non-standard extensions which + allows you to use a compatible hash function and equality + predicate for a key of a different type in order to avoid + an expensive type cast. In general, its use is not encouraged. + + + + + key_type const& + + size_type + + The number of elements with key equivalent to k. + + + + + + key_type const& + + std::pair<iterator, iterator> + + + + key_type const& + + std::pair<const_iterator, const_iterator> + + + A range containing all elements with key equivalent to k. + If the container doesn't container any such elements, returns + std::make_pair(b.end(),b.end()). + + + + + + + key_type const& + + mapped_type& + + If the container does not already contain an elements with a key equivalent to k, inserts the value std::pair<key_type const, mapped_type>(k, mapped_type()) + + + A reference to x.second where x is the element already in the container, or the newly inserted element with a key equivalent to k + + + If an exception is thrown by an operation other than a call to hasher the function has no effect. + + + Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + Pointers and references to elements are never invalidated. + + + + Mapped& + key_type const& + Mapped const& + key_type const& + + A reference to x.second where x is the (unique) element whose key is equivalent to k. + + + An exception object of type std::out_of_range if no such element is present. + + + This is not specified in the draft standard, but that is probably an oversight. The issue has been raised in + comp.std.c++. + + + + + + + size_type + + The number of buckets. + + + + size_type + + An upper bound on the number of buckets. + + + + + size_type + + size_type + + n < bucket_count() + + + The number of elements in bucket n. + + + + + key_type const& + + size_type + + The index of the bucket which would contain an element with key k. + + + The return value is less than bucket_count() + + + + + + size_type + + local_iterator + + + + size_type + + const_local_iterator + + + n shall be in the range [0, bucket_count()). + + + A local iterator pointing the first element in the bucket with index n. + + + + + + size_type + + local_iterator + + + + size_type + + const_local_iterator + + + n shall be in the range [0, bucket_count()). + + + A local iterator pointing the 'one past the end' element in the bucket with index n. + + + + + size_type + + const_local_iterator + + n shall be in the range [0, bucket_count()). + + + A constant local iterator pointing the first element in the bucket with index n. + + + + + size_type + + const_local_iterator + + n shall be in the range [0, bucket_count()). + + + A constant local iterator pointing the 'one past the end' element in the bucket with index n. + + + + + + float + + The average number of elements per bucket. + + + + float + + Returns the current maximum load factor. + + + + + float + + void + + Changes the container's maximum load factor, using z as a hint. + + + + + size_type + + void + + Changes the number of buckets so that there at least n buckets, and so that the load factor is less than the maximum load factor. + Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated. + + + The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function. + + + + + + + + const& + + + const& + + bool + + This is a boost extension. + Behavior is undefined if the two containers don't have + equivalent equality predicates. + + + + + + const& + + + const& + + bool + + This is a boost extension. + Behavior is undefined if the two containers don't have + equivalent equality predicates. + + + + + + + + & + + + & + + void + + x.swap(y) + + + If the allocators are equal, doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of Hash or Pred. + + + For a discussion of the behavior when allocators aren't equal see + the implementation details. + + + + + + +
+ + + +
+
+ + + +
+
diff --git a/doc/ref.xml b/doc/ref.xml index 92aaffa7..7825de2f 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -40,8 +40,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Pred A binary function object that implements an equivalence relation on values of type Value. - A binary function object that induces an equivalence relation on values of type Key. - It takes two arguments of type Key and returns a value of type bool. + A binary function object that induces an equivalence relation on values of type Value. + It takes two arguments of type Value and returns a value of type bool. Alloc An allocator whose value type is the same as the container's value type. @@ -360,7 +360,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) iterator Inserts an object, constructed with the arguments args, in the container if and only if there is no element in the container with an equivalent value. - hint is a suggestion to where the element should be inserted. + hint is a suggestion to where the element should be inserted. If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent value. @@ -383,7 +383,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) std::pair<iterator, bool> - Inserts obj in the container if and only if there is no element in the container with an equivalent value. + Inserts obj in the container if and only if there is no element in the container with an equivalent value. The bool component of the return type is true if an insert took place. @@ -406,7 +406,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) iterator - Inserts obj in the container if and only if there is no element in the container with an equivalent value. + Inserts obj in the container if and only if there is no element in the container with an equivalent value. hint is a suggestion to where the element should be inserted. @@ -815,8 +815,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)