From 885574e1bfb3d2037a58ca32922406a5f055f24b Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 11 Jun 2008 22:06:52 +0000 Subject: [PATCH 001/471] Fix typo. Thanks to Thorsten. Merged revisions 46112 via svnmerge from https://svn.boost.org/svn/boost/branches/unordered/trunk ........ r46112 | danieljames | 2008-06-04 13:34:29 +0100 (Wed, 04 Jun 2008) | 1 line Fix copy and paste error in the max_load_factor documentation. ........ [SVN r46340] --- 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 659a014976e941ddf01a199c5e477c8a97b7ec40 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 15 Jun 2008 17:03:37 +0000 Subject: [PATCH 002/471] Fix in an error in the unordered containers' emulated move constructors. These aren't actually used, so I could probalby just remove 'move_from' for now (it's used in the full move library). [SVN r46410] --- 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 9bd3f498a76b563d82098d6078a28b1428bc7f97 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 21 Jun 2008 15:32:11 +0000 Subject: [PATCH 003/471] 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. [SVN r46579] --- include/boost/unordered_map.hpp | 116 ++++++++++++++++++++++---------- include/boost/unordered_set.hpp | 114 +++++++++++++++++++++---------- 2 files changed, 161 insertions(+), 69 deletions(-) diff --git a/include/boost/unordered_map.hpp b/include/boost/unordered_map.hpp index bd6cfb2f..ec82da34 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 m1.base.equals(m2.base); + } + + template + inline bool operator!=(unordered_map const& m1, + unordered_map const& m2) + { + return !m1.base.equals(m2.base); + } + + template + inline std::size_t hash_value(unordered_map const& m) + { + return m.base.hash_value(); + } + + 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 m1.base.equals(m2.base); + } + + template + inline bool operator!=(unordered_multimap const& m1, + unordered_multimap const& m2) + { + return !m1.base.equals(m2.base); + } + + template + inline std::size_t hash_value(unordered_multimap const& m) + { + return m.base.hash_value(); + } + + 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..44e8e639 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 m1.base.equals(m2.base); + } + + template + inline bool operator!=(unordered_set const& m1, + unordered_set const& m2) + { + return !m1.base.equals(m2.base); + } + + template + inline std::size_t hash_value(unordered_set const& m) + { + return m.base.hash_value(); + } + + 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 m1.base.equals(m2.base); + } + + template + inline bool operator!=(unordered_multiset const& m1, + unordered_multiset const& m2) + { + return !m1.base.equals(m2.base); + } + + template + inline std::size_t hash_value(unordered_multiset const& m) + { + return m.base.hash_value(); + } + + template + inline void swap(unordered_multiset &m1, unordered_multiset &m2) { m1.swap(m2); From ebd75b401079f1e5151390550951885359587682 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 21 Jun 2008 19:58:39 +0000 Subject: [PATCH 004/471] 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. [SVN r46587] --- test/unordered/unnecessary_copy_tests.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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 8868fa46873137e89da03ceaf09e0c4f01f1329b Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 21 Jun 2008 22:02:15 +0000 Subject: [PATCH 005/471] 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. ................ [SVN r46594] --- doc/bibliography.xml | 5 + examples/hash_functions/fnv-1.hpp | 7 +- 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 +++++++++++++-------------- 8 files changed, 118 insertions(+), 93 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/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))); + } } From ec1e809fc32f71fcc69d2cae4d2a88093d995b43 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 22 Jun 2008 13:54:45 +0000 Subject: [PATCH 006/471] 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 [SVN r46607] --- .../unordered/detail/hash_table_impl.hpp | 237 +++++++++++------- include/boost/unordered_map.hpp | 12 +- include/boost/unordered_set.hpp | 12 +- 3 files changed, 153 insertions(+), 108 deletions(-) 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 ec82da34..cf6562b3 100644 --- a/include/boost/unordered_map.hpp +++ b/include/boost/unordered_map.hpp @@ -431,20 +431,20 @@ namespace boost inline bool operator==(unordered_map const& m1, unordered_map const& m2) { - return m1.base.equals(m2.base); + return boost::unordered_detail::equals(m1.base, m2.base); } template inline bool operator!=(unordered_map const& m1, unordered_map const& m2) { - return !m1.base.equals(m2.base); + return !boost::unordered_detail::equals(m1.base, m2.base); } template inline std::size_t hash_value(unordered_map const& m) { - return m.base.hash_value(); + return boost::unordered_detail::hash_value(m.base); } template @@ -805,20 +805,20 @@ namespace boost inline bool operator==(unordered_multimap const& m1, unordered_multimap const& m2) { - return m1.base.equals(m2.base); + return boost::unordered_detail::equals(m1.base, m2.base); } template inline bool operator!=(unordered_multimap const& m1, unordered_multimap const& m2) { - return !m1.base.equals(m2.base); + return !boost::unordered_detail::equals(m1.base, m2.base); } template inline std::size_t hash_value(unordered_multimap const& m) { - return m.base.hash_value(); + return boost::unordered_detail::hash_value(m.base); } template diff --git a/include/boost/unordered_set.hpp b/include/boost/unordered_set.hpp index 44e8e639..f68502e3 100644 --- a/include/boost/unordered_set.hpp +++ b/include/boost/unordered_set.hpp @@ -401,20 +401,20 @@ namespace boost inline bool operator==(unordered_set const& m1, unordered_set const& m2) { - return m1.base.equals(m2.base); + return boost::unordered_detail::equals(m1.base, m2.base); } template inline bool operator!=(unordered_set const& m1, unordered_set const& m2) { - return !m1.base.equals(m2.base); + return !boost::unordered_detail::equals(m1.base, m2.base); } template inline std::size_t hash_value(unordered_set const& m) { - return m.base.hash_value(); + return boost::unordered_detail::hash_value(m.base); } template @@ -761,20 +761,20 @@ namespace boost inline bool operator==(unordered_multiset const& m1, unordered_multiset const& m2) { - return m1.base.equals(m2.base); + return boost::unordered_detail::equals(m1.base, m2.base); } template inline bool operator!=(unordered_multiset const& m1, unordered_multiset const& m2) { - return !m1.base.equals(m2.base); + return !boost::unordered_detail::equals(m1.base, m2.base); } template inline std::size_t hash_value(unordered_multiset const& m) { - return m.base.hash_value(); + return boost::unordered_detail::hash_value(m.base); } template From 3640e1e96ca4cfa8feed9132e3cb89553fa77092 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 3 Jul 2008 14:34:56 +0000 Subject: [PATCH 007/471] Workaround for some template syntax not supported in old versions of Visual C++ 6.5 [SVN r47040] --- 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 d66936a64000ec5b21e79ce79bad5ed7b48cb683 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 4 Jul 2008 22:57:20 +0000 Subject: [PATCH 008/471] Require explicit conversion from allocators. (Not what it says in the draft standard, but I think that might be a defect). [SVN r47085] --- doc/ref.xml | 10 +++++----- include/boost/unordered_map.hpp | 5 ++--- include/boost/unordered_set.hpp | 6 ++---- 3 files changed, 9 insertions(+), 12 deletions(-) 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/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 f723f857e4ca58c2c94fecb95b4637b6c81973c3 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 6 Jul 2008 12:41:09 +0000 Subject: [PATCH 009/471] 'Bias' should be 'basis'. [SVN r47132] --- examples/hash_functions/fnv-1.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/hash_functions/fnv-1.hpp b/examples/hash_functions/fnv-1.hpp index 9caf1687..a5c63a67 100644 --- a/examples/hash_functions/fnv-1.hpp +++ b/examples/hash_functions/fnv-1.hpp @@ -9,12 +9,12 @@ namespace hash { - template + template struct basic_fnv_1 { std::size_t operator()(std::string const& text) const { - std::size_t hash = OffsetBias; + std::size_t hash = OffsetBasis; for(std::string::const_iterator it = text.begin(), end = text.end(); it != end; ++it) { @@ -26,12 +26,12 @@ namespace hash } }; - template + template struct basic_fnv_1a { std::size_t operator()(std::string const& text) const { - std::size_t hash = OffsetBias; + std::size_t hash = OffsetBasis; for(std::string::const_iterator it = text.begin(), end = text.end(); it != end; ++it) { @@ -43,7 +43,7 @@ namespace hash } }; - // TODO: Select Bias & Prime base on the size of std::size_t. + // TODO: Select Basis & Prime base on the size of std::size_t. // // 32 bit FNV_prime = 16777619 // 64 bit FNV_prime = 1099511628211 @@ -60,12 +60,12 @@ namespace hash // 128 bit FNV_prime = 309485009821345068724781401 // 256 bit FNV_prime = 374144419156711147060143317175368453031918731002211 - const std::size_t fnv_offset_bias = 2166136261u; + const std::size_t fnv_offset_basis = 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; + typedef basic_fnv_1 fnv_1; + typedef basic_fnv_1a fnv_1a; } From 2960390f7951eb241754bdaf8295c3cebb9dbfd6 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 6 Jul 2008 21:06:52 +0000 Subject: [PATCH 010/471] Clean up the FNV-1 comments. [SVN r47143] --- examples/hash_functions/fnv-1.hpp | 37 +++++++++++++------------------ 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/examples/hash_functions/fnv-1.hpp b/examples/hash_functions/fnv-1.hpp index a5c63a67..60bf8985 100644 --- a/examples/hash_functions/fnv-1.hpp +++ b/examples/hash_functions/fnv-1.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) +// This code is also released into the public domain. + // Algorithm from: http://www.isthe.com/chongo/tech/comp/fnv/ #include @@ -43,29 +45,22 @@ namespace hash } }; - // TODO: Select Basis & 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 - + // For 32 bit machines: + const std::size_t fnv_prime = 16777619u; const std::size_t fnv_offset_basis = 2166136261u; - // 64 bit offset_basis = 14695981039346656037 - // 128 bit offset_basis = 275519064689413815358837431229664493455 - // 256 bit offset_basis = 100029257958052580907070968620625704837092796014241193945225284501741471925557 + + // 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; - } From c3d97bd613b0c97fdade93ca16d3133f456f4a35 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 6 Jul 2008 21:07:31 +0000 Subject: [PATCH 011/471] I've only got one hash function for release, so no need for its own directory. [SVN r47144] --- examples/{hash_functions/fnv-1.hpp => fnv1.hpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{hash_functions/fnv-1.hpp => fnv1.hpp} (100%) diff --git a/examples/hash_functions/fnv-1.hpp b/examples/fnv1.hpp similarity index 100% rename from examples/hash_functions/fnv-1.hpp rename to examples/fnv1.hpp From d5fdc0b47ef5ec8f560c9ab4a5c5d2b9203e9894 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 6 Jul 2008 21:29:47 +0000 Subject: [PATCH 012/471] Update the docs for the new location of FNV-1. [SVN r47146] --- doc/hash_equality.qbk | 4 ++-- doc/src_code/dictionary.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) 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/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 From c7bde21be7bb8ad427e3d1547f5e3e27b776e50f Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 13 Jul 2008 19:42:56 +0000 Subject: [PATCH 013/471] Note that emplace is only available on a few compilers. [SVN r47402] --- doc/ref.xml | 8 ++++++++ 1 file changed, 8 insertions(+) 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 c49dbd782dceb69b0c47e5a9c71fc01397bc06e9 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 13 Jul 2008 20:07:45 +0000 Subject: [PATCH 014/471] Update the implementation details. [SVN r47403] --- doc/rationale.qbk | 37 +++++++++++++++---------------------- 1 file changed, 15 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] From d5b38b01fc5113b1090e3efd0f8307bc19b1df66 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 15 Jul 2008 21:26:54 +0000 Subject: [PATCH 015/471] Better hash function for unordered containers. Still a bit rubbish. [SVN r47463] --- include/boost/unordered/detail/hash_table_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/hash_table_impl.hpp b/include/boost/unordered/detail/hash_table_impl.hpp index fc8443ee..d4870067 100644 --- a/include/boost/unordered/detail/hash_table_impl.hpp +++ b/include/boost/unordered/detail/hash_table_impl.hpp @@ -2294,7 +2294,7 @@ namespace boost { 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); + seed += group_hash(t, it, (type_wrapper*)0); } return seed; From 4305d10264bf7482dfc5c1f68e6c5e2b504e6d90 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 15 Jul 2008 22:03:15 +0000 Subject: [PATCH 016/471] 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. [SVN r47465] --- 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 -- 6 files changed, 182 deletions(-) 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 d4870067..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 eae2a90463074cd903ac492f2de3fa60ef54e42f Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 17 Jul 2008 23:08:32 +0000 Subject: [PATCH 017/471] Remove a mention of the hash functions which I missed before. [SVN r47522] --- doc/changes.qbk | 3 +-- 1 file changed, 1 insertion(+), 2 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] From f2c420e2895b60d5d3bb43e48a77b6a30e119841 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 24 Jul 2008 10:14:15 +0000 Subject: [PATCH 018/471] Remove some old information that's no longer true. [SVN r47750] --- doc/intro.qbk | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 506f478ec7e60921a608e501960a5ac8bb71f24f Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 25 Jul 2008 21:25:58 +0000 Subject: [PATCH 019/471] Fix a typo. [SVN r47813] --- doc/changes.qbk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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. From d8fa4cef60cf17924186f210252b10b8013e5b62 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 30 Jul 2008 09:44:26 +0000 Subject: [PATCH 020/471] Fix a link and a header. [SVN r47881] --- 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 d6f513be5210e0e5ab035f415414f32d0286ccf8 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 11 Aug 2008 07:52:37 +0000 Subject: [PATCH 021/471] Rename 'emplace' with hint to 'emplace_hint'. [SVN r48081] --- doc/changes.qbk | 5 +++++ doc/ref.xml | 8 ++++---- include/boost/unordered_map.hpp | 4 ++-- include/boost/unordered_set.hpp | 4 ++-- test/unordered/compile_tests.hpp | 2 +- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index 8fd4c2a9..07163a6a 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -33,4 +33,9 @@ First official release. are available. * Added equality operators. +[h2 Development...] + +* 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]. + [endsect] diff --git a/doc/ref.xml b/doc/ref.xml index d7dd9259..1600042b 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -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 3a8739cd601d48ac61d20d254ed34851b4d05fc0 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 26 Mar 2009 07:00:21 +0000 Subject: [PATCH 053/471] Revert [51409] It isn't working on Borland. [SVN r51982] --- include/boost/unordered/detail/hash_table.hpp | 43 ------- .../unordered/detail/hash_table_impl.hpp | 105 ++++++++++++------ 2 files changed, 69 insertions(+), 79 deletions(-) diff --git a/include/boost/unordered/detail/hash_table.hpp b/include/boost/unordered/detail/hash_table.hpp index 1bdcced8..4b145196 100644 --- a/include/boost/unordered/detail/hash_table.hpp +++ b/include/boost/unordered/detail/hash_table.hpp @@ -228,49 +228,6 @@ namespace boost { 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; } - }; } } diff --git a/include/boost/unordered/detail/hash_table_impl.hpp b/include/boost/unordered/detail/hash_table_impl.hpp index c7ab515d..8d589cdb 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. @@ -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 188bcafdece6a3764b019111e8f8eaa099b55bb9 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 26 Mar 2009 07:00:46 +0000 Subject: [PATCH 054/471] Try to destruct values in a way that all compilers might like. [SVN r51983] --- include/boost/unordered/detail/hash_table.hpp | 5 ----- include/boost/unordered/detail/hash_table_impl.hpp | 4 ++-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/include/boost/unordered/detail/hash_table.hpp b/include/boost/unordered/detail/hash_table.hpp index 4b145196..9d5e78e6 100644 --- a/include/boost/unordered/detail/hash_table.hpp +++ b/include/boost/unordered/detail/hash_table.hpp @@ -223,11 +223,6 @@ namespace boost { functions func2_; functions_ptr func_; // The currently active functions. }; - - template - void destroy(T* x) { - x->~T(); - } } } diff --git a/include/boost/unordered/detail/hash_table_impl.hpp b/include/boost/unordered/detail/hash_table_impl.hpp index 8d589cdb..145ef965 100644 --- a/include/boost/unordered/detail/hash_table_impl.hpp +++ b/include/boost/unordered/detail/hash_table_impl.hpp @@ -130,7 +130,7 @@ namespace boost { void destroy(link_ptr ptr) { node* raw_ptr = static_cast(&*ptr); - boost::unordered_detail::destroy(&raw_ptr->value()); + (&raw_ptr->value())->~value_type(); node_ptr n(node_alloc_.address(*raw_ptr)); node_alloc_.destroy(n); node_alloc_.deallocate(n, 1); @@ -172,7 +172,7 @@ namespace boost { { if (node_) { if (value_constructed_) { - boost::unordered_detail::destroy(&node_->value()); + (&node_->value())->~value_type(); } if (node_constructed_) From 6ccc68b15c87051aa276087079d8a4bc0991c951 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 26 Mar 2009 21:09:51 +0000 Subject: [PATCH 055/471] Give up and use another macro to destruct values. [SVN r51995] --- include/boost/unordered/detail/hash_table.hpp | 10 ++++++++++ include/boost/unordered/detail/hash_table_impl.hpp | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/hash_table.hpp b/include/boost/unordered/detail/hash_table.hpp index 9d5e78e6..c6ded509 100644 --- a/include/boost/unordered/detail/hash_table.hpp +++ b/include/boost/unordered/detail/hash_table.hpp @@ -223,6 +223,16 @@ namespace boost { 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 } } diff --git a/include/boost/unordered/detail/hash_table_impl.hpp b/include/boost/unordered/detail/hash_table_impl.hpp index 145ef965..a8e86ad4 100644 --- a/include/boost/unordered/detail/hash_table_impl.hpp +++ b/include/boost/unordered/detail/hash_table_impl.hpp @@ -130,7 +130,7 @@ namespace boost { void destroy(link_ptr ptr) { node* raw_ptr = static_cast(&*ptr); - (&raw_ptr->value())->~value_type(); + 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); @@ -172,7 +172,7 @@ namespace boost { { if (node_) { if (value_constructed_) { - (&node_->value())->~value_type(); + BOOST_UNORDERED_DESTRUCT(&node_->value(), value_type); } if (node_constructed_) From 290c7566ffedb61ba137266d44f53edd05e24919 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 31 Mar 2009 19:43:58 +0000 Subject: [PATCH 056/471] Changelog for unordered and hash. [SVN r52084] --- 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 4ac0a12a836b2f35869c6224d27f6c8da9d2fe57 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 6 Apr 2009 22:51:36 +0000 Subject: [PATCH 057/471] Avoid an unnecessary copy in 'operator[]' [SVN r52224] --- .../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 5a86d0827142c59efdb576aa07fa6afc92904987 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 12 Apr 2009 10:50:57 +0000 Subject: [PATCH 058/471] Note change to operator[] in the unordered release notes. [SVN r52350] --- 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 a07e4c5810f258d0c135237a87c5117c9ec4ff8a Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 14 Apr 2009 17:23:37 +0000 Subject: [PATCH 059/471] Implement full extract_key for compilers without SFINAE and variadic templates. [SVN r52393] --- include/boost/unordered/detail/hash_table.hpp | 10 +- .../unordered/detail/hash_table_impl.hpp | 100 ++++++++++++++---- test/unordered/unnecessary_copy_tests.cpp | 2 + 3 files changed, 82 insertions(+), 30 deletions(-) diff --git a/include/boost/unordered/detail/hash_table.hpp b/include/boost/unordered/detail/hash_table.hpp index c6ded509..26a0455a 100644 --- a/include/boost/unordered/detail/hash_table.hpp +++ b/include/boost/unordered/detail/hash_table.hpp @@ -28,20 +28,16 @@ #include #include #include +#include +#include #include #include +#include #include #include #include -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) -#include -#include -#include -#include -#endif - #if BOOST_WORKAROUND(__BORLANDC__, <= 0x0582) #define BOOST_UNORDERED_BORLAND_BOOL(x) (bool)(x) #else diff --git a/include/boost/unordered/detail/hash_table_impl.hpp b/include/boost/unordered/detail/hash_table_impl.hpp index e7cdc5b9..65966127 100644 --- a/include/boost/unordered/detail/hash_table_impl.hpp +++ b/include/boost/unordered/detail/hash_table_impl.hpp @@ -1428,7 +1428,18 @@ namespace boost { // key extractors + struct no_key { + no_key() {} + template no_key(T const&) {} + }; + // no throw + + static no_key extract_key() + { + return no_key(); + } + static key_type const& extract_key(value_type const& v) { return extract(v, (type_wrapper*)0); @@ -1445,40 +1456,46 @@ 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&...) + + template + static BOOST_DEDUCED_TYPENAME + boost::mpl::if_, key_type const&, no_key>::type + extract_key(Arg const& k) { return k; } 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&...) +#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, Args const&...) { - return no_key(); + return k; } + #endif public: @@ -1963,6 +1980,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 +2016,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: diff --git a/test/unordered/unnecessary_copy_tests.cpp b/test/unordered/unnecessary_copy_tests.cpp index df4baf3c..d2ab8629 100644 --- a/test/unordered/unnecessary_copy_tests.cpp +++ b/test/unordered/unnecessary_copy_tests.cpp @@ -192,6 +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. reset(); x.emplace(b, b); From ac2409627ab13756b329ba7ca5de292b628fa178 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 14 Apr 2009 17:23:51 +0000 Subject: [PATCH 060/471] Use emplace instead of insert in the backend as it's more appropriate. [SVN r52394] --- .../unordered/detail/hash_table_impl.hpp | 50 +++++++++---------- include/boost/unordered/unordered_map.hpp | 16 +++--- include/boost/unordered/unordered_set.hpp | 16 +++--- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/include/boost/unordered/detail/hash_table_impl.hpp b/include/boost/unordered/detail/hash_table_impl.hpp index 65966127..5d8f2f32 100644 --- a/include/boost/unordered/detail/hash_table_impl.hpp +++ b/include/boost/unordered/detail/hash_table_impl.hpp @@ -1604,67 +1604,67 @@ namespace boost { // if hash function throws, basic exception safety // strong otherwise - iterator_base insert(value_type const& v) + iterator_base emplace(value_type const& v) { // Create the node before rehashing in case it throws an // exception (need strong safety in such a case). node_constructor a(data_.allocators_); a.construct(v); - return insert_impl(a); + return emplace_impl(a); } // Insert (equivalent key containers) // if hash function throws, basic exception safety // strong otherwise - iterator_base insert_hint(iterator_base const& it, value_type const& v) + iterator_base emplace_hint(iterator_base const& it, value_type const& v) { // Create the node before rehashing in case it throws an // exception (need strong safety in such a case). node_constructor a(data_.allocators_); a.construct(v); - return 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') + // 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 insert(Args&&... args) + 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 insert_impl(a); + return emplace_impl(a); } // Insert (equivalent key containers) - // (I'm using an overloaded insert for both 'insert' and 'emplace') + // (I'm using an overloaded emplace 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) + 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 insert_hint_impl(it, a); + return emplace_hint_impl(it, a); } #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); @@ -1685,13 +1685,13 @@ 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 // to a matching key. - return insert_impl(a); + return emplace_impl(a); } else { // Find the first node in the group - so that the node @@ -1724,7 +1724,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 @@ -1754,7 +1754,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: @@ -1809,7 +1809,7 @@ namespace boost { // if hash function throws, basic exception safety // strong otherwise - std::pair insert(value_type const& v) + std::pair emplace(value_type const& v) { // No side effects in this initial code key_type const& k = extract_key(v); @@ -1849,12 +1849,12 @@ namespace boost { // if hash function throws, basic exception safety // strong otherwise - iterator_base insert_hint(iterator_base const& it, value_type const& v) + iterator_base emplace_hint(iterator_base const& it, value_type const& v) { if(it != data_.end() && equal(extract_key(v), *it)) return it; else - return insert(v).first; + return emplace(v).first; } #else @@ -1869,15 +1869,15 @@ namespace boost { // 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)...); } template - std::pair insert_impl(key_type const& k, Args&&... args) + std::pair emplace_impl(key_type const& k, Args&&... args) { // No side effects in this initial code size_type hash_value = hash_function()(k); @@ -1911,7 +1911,7 @@ 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 @@ -1947,10 +1947,10 @@ namespace boost { // if hash function throws, basic exception safety // strong otherwise template - iterator_base insert_hint(iterator_base const&, Args&&... args) + iterator_base emplace_hint(iterator_base const&, Args&&... args) { // Life is complicated - just call the normal implementation. - return insert(std::forward(args)...).first; + return emplace(std::forward(args)...).first; } #endif diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index f787de2a..4d3f7a53 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -224,25 +224,25 @@ 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)...)); } #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 +630,24 @@ 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)...)); } #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..a99db075 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -222,26 +222,26 @@ 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)...)); } #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 +599,24 @@ 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)...)); } #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 From 3f0e2b478b3e1e47e60041f8d286793c02ada924 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 14 Apr 2009 17:51:34 +0000 Subject: [PATCH 061/471] Add stream output to the count test helper for unordered. [SVN r52397] --- test/helpers/count.hpp | 7 +++++++ 1 file changed, 7 insertions(+) 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: "< From 4c3c18467ce9e754d8dda3461ab40498fdd04886 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 29 Apr 2009 10:05:17 +0000 Subject: [PATCH 062/471] Fix the length of the prime number list. Refs #2975 [SVN r52658] --- include/boost/unordered/detail/hash_table.hpp | 2 +- test/unordered/Jamfile.v2 | 1 + test/unordered/detail_tests.cpp | 27 +++++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 test/unordered/detail_tests.cpp diff --git a/include/boost/unordered/detail/hash_table.hpp b/include/boost/unordered/detail/hash_table.hpp index 26a0455a..2a7431ff 100644 --- a/include/boost/unordered/detail/hash_table.hpp +++ b/include/boost/unordered/detail/hash_table.hpp @@ -83,7 +83,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; diff --git a/test/unordered/Jamfile.v2 b/test/unordered/Jamfile.v2 index 9ecec284..a524fa31 100644 --- a/test/unordered/Jamfile.v2 +++ b/test/unordered/Jamfile.v2 @@ -37,4 +37,5 @@ test-suite unordered [ run rehash_tests.cpp ] [ run equality_tests.cpp ] [ run swap_tests.cpp : : : BOOST_UNORDERED_SWAP_METHOD=2 ] + [ run detail_tests.cpp ] ; diff --git a/test/unordered/detail_tests.cpp b/test/unordered/detail_tests.cpp new file mode 100644 index 00000000..daa89895 --- /dev/null +++ b/test/unordered/detail_tests.cpp @@ -0,0 +1,27 @@ + +// 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) + +// Test some of the library's implementation details. + +#include +#include + +#include +#include + +int main() { + + // Test that the prime list has the right length. + // + // It would have been better to automatically set the length in the header + // but that doesn't work on some older compilers. + + BOOST_TEST_EQ( + boost::end(boost::unordered_detail::prime_list::value) - + boost::begin(boost::unordered_detail::prime_list::value), + boost::unordered_detail::prime_list::length); + + return boost::report_errors(); +} \ No newline at end of file From 24091f8bd8dc5d12afc7ce19f4f10649d988adc0 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 29 Apr 2009 21:43:41 +0000 Subject: [PATCH 063/471] Don't test prime_list::length on Visual C++. Checking the array size doesn't seem to work on it. [SVN r52669] --- test/unordered/detail_tests.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/unordered/detail_tests.cpp b/test/unordered/detail_tests.cpp index daa89895..757f6aee 100644 --- a/test/unordered/detail_tests.cpp +++ b/test/unordered/detail_tests.cpp @@ -16,12 +16,17 @@ int main() { // Test that the prime list has the right length. // // It would have been better to automatically set the length in the header - // but that doesn't work on some older compilers. + // but that doesn't work on some compilers. It's okay that this isn't tested + // on all compilers, as it really only needs to be checked on one. + +#if !defined(BOOST_MSVC) BOOST_TEST_EQ( boost::end(boost::unordered_detail::prime_list::value) - boost::begin(boost::unordered_detail::prime_list::value), boost::unordered_detail::prime_list::length); + +#endif return boost::report_errors(); } \ No newline at end of file From f8e1ec8d2b364b7eade8fd3dbb97226fd81317c1 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 30 Apr 2009 05:08:40 +0000 Subject: [PATCH 064/471] Revert changes to unordered, as the test fails on most compilers. [SVN r52673] --- include/boost/unordered/detail/hash_table.hpp | 2 +- test/unordered/Jamfile.v2 | 1 - test/unordered/detail_tests.cpp | 32 ------------------- 3 files changed, 1 insertion(+), 34 deletions(-) delete mode 100644 test/unordered/detail_tests.cpp diff --git a/include/boost/unordered/detail/hash_table.hpp b/include/boost/unordered/detail/hash_table.hpp index 2a7431ff..26a0455a 100644 --- a/include/boost/unordered/detail/hash_table.hpp +++ b/include/boost/unordered/detail/hash_table.hpp @@ -83,7 +83,7 @@ namespace boost { 1610612741ul, 3221225473ul, 4294967291ul }; template - std::ptrdiff_t const prime_list_template::length = 40; + std::ptrdiff_t const prime_list_template::length = 28; typedef prime_list_template prime_list; diff --git a/test/unordered/Jamfile.v2 b/test/unordered/Jamfile.v2 index a524fa31..9ecec284 100644 --- a/test/unordered/Jamfile.v2 +++ b/test/unordered/Jamfile.v2 @@ -37,5 +37,4 @@ test-suite unordered [ run rehash_tests.cpp ] [ run equality_tests.cpp ] [ run swap_tests.cpp : : : BOOST_UNORDERED_SWAP_METHOD=2 ] - [ run detail_tests.cpp ] ; diff --git a/test/unordered/detail_tests.cpp b/test/unordered/detail_tests.cpp deleted file mode 100644 index 757f6aee..00000000 --- a/test/unordered/detail_tests.cpp +++ /dev/null @@ -1,32 +0,0 @@ - -// 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) - -// Test some of the library's implementation details. - -#include -#include - -#include -#include - -int main() { - - // Test that the prime list has the right length. - // - // It would have been better to automatically set the length in the header - // but that doesn't work on some compilers. It's okay that this isn't tested - // on all compilers, as it really only needs to be checked on one. - -#if !defined(BOOST_MSVC) - - BOOST_TEST_EQ( - boost::end(boost::unordered_detail::prime_list::value) - - boost::begin(boost::unordered_detail::prime_list::value), - boost::unordered_detail::prime_list::length); - -#endif - - return boost::report_errors(); -} \ No newline at end of file From ce379f7bb555ebf266d70d9d10e561219bcfc0aa Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 30 Apr 2009 05:10:57 +0000 Subject: [PATCH 065/471] Fix the prime number list length in unordered. [SVN r52674] --- 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 26a0455a..2a7431ff 100644 --- a/include/boost/unordered/detail/hash_table.hpp +++ b/include/boost/unordered/detail/hash_table.hpp @@ -83,7 +83,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 3e70155100b1f69c66e6413d9204f598034925df Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 1 May 2009 20:50:32 +0000 Subject: [PATCH 066/471] 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 r52711] --- 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 2a7431ff..b6bd9aa6 100644 --- a/include/boost/unordered/detail/hash_table.hpp +++ b/include/boost/unordered/detail/hash_table.hpp @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include @@ -72,18 +74,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 294d58d2fef354d5baa4bc292d4619f2ca53d55a Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 10 May 2009 21:24:41 +0000 Subject: [PATCH 067/471] Cherrypick some unordered container changes from sandbox. Not including anything which depends on the new move library. ------------------------------------------------------------------------ r52746 | danieljames | 2009-05-03 11:12:30 +0100 (Sun, 03 May 2009) | 1 line Merge latest unordered container changes. ------------------------------------------------------------------------ r52747 | danieljames | 2009-05-03 11:15:35 +0100 (Sun, 03 May 2009) | 4 lines Put the C++0x emplace implementations before the non-C++0x versions. I'm going to change the non-C++0x to be macro heavy emulations of the C++0x versions, so this will put the readable version first. ------------------------------------------------------------------------ r52748 | danieljames | 2009-05-03 11:15:44 +0100 (Sun, 03 May 2009) | 1 line Refactor the unordered implementation a tad, to make implementing emplace less painful. ------------------------------------------------------------------------ [SVN r52884] --- .../unordered/detail/hash_table_impl.hpp | 233 +++++++++--------- 1 file changed, 119 insertions(+), 114 deletions(-) diff --git a/include/boost/unordered/detail/hash_table_impl.hpp b/include/boost/unordered/detail/hash_table_impl.hpp index 5d8f2f32..ece2615e 100644 --- a/include/boost/unordered/detail/hash_table_impl.hpp +++ b/include/boost/unordered/detail/hash_table_impl.hpp @@ -181,9 +181,7 @@ namespace boost { } } -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) - template - void construct(Args&&... args) + void construct_preamble() { BOOST_ASSERT(!node_); node_constructed_ = false; @@ -194,6 +192,13 @@ namespace boost { allocators_.node_alloc_.construct(node_, node()); node_constructed_ = true; + } + +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) + template + void construct(Args&&... args) + { + construct_preamble(); new(node_->address()) value_type(std::forward(args)...); value_constructed_ = true; } @@ -201,15 +206,7 @@ namespace boost { template void construct(V const& v) { - BOOST_ASSERT(!node_); - node_constructed_ = false; - value_constructed_ = false; - - node_ = allocators_.node_alloc_.allocate(1); - - allocators_.node_alloc_.construct(node_, node()); - node_constructed_ = true; - + construct_preamble(); new(node_->address()) value_type(v); value_constructed_ = true; } @@ -1599,36 +1596,7 @@ namespace boost { #if BOOST_UNORDERED_EQUIVALENT_KEYS -#if !(defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)) - // Insert (equivalent key containers) - - // if hash function throws, basic exception safety - // strong otherwise - iterator_base emplace(value_type const& v) - { - // Create the node before rehashing in case it throws an - // exception (need strong safety in such a case). - node_constructor a(data_.allocators_); - a.construct(v); - - return emplace_impl(a); - } - - // Insert (equivalent key containers) - - // if hash function throws, basic exception safety - // strong otherwise - iterator_base emplace_hint(iterator_base const& it, value_type const& v) - { - // Create the node before rehashing in case it throws an - // exception (need strong safety in such a case). - node_constructor a(data_.allocators_); - a.construct(v); - - return emplace_hint_impl(it, a); - } - -#else +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) // Emplace (equivalent key containers) // (I'm using an overloaded emplace for both 'insert' and 'emplace') @@ -1646,7 +1614,7 @@ namespace boost { return emplace_impl(a); } - // Insert (equivalent key containers) + // Emplace (equivalent key containers) // (I'm using an overloaded emplace for both 'insert' and 'emplace') // if hash function throws, basic exception safety @@ -1662,6 +1630,36 @@ namespace boost { return emplace_hint_impl(it, a); } +#else + + // Emplace (equivalent key containers) + + // if hash function throws, basic exception safety + // strong otherwise + iterator_base emplace(value_type const& v) + { + // Create the node before rehashing in case it throws an + // exception (need strong safety in such a case). + node_constructor a(data_.allocators_); + a.construct(v); + + return emplace_impl(a); + } + + // Emplace (equivalent key containers) + + // if hash function throws, basic exception safety + // strong otherwise + iterator_base emplace_hint(iterator_base const& it, value_type const& v) + { + // Create the node before rehashing in case it throws an + // exception (need strong safety in such a case). + node_constructor a(data_.allocators_); + a.construct(v); + + return emplace_hint_impl(it, a); + } + #endif iterator_base emplace_impl(node_constructor& a) @@ -1689,13 +1687,13 @@ namespace boost { { // equal can throw, but with no effects if (it == data_.end() || !equal(extract_key(a.get()->value()), *it)) { - // Use the standard insert if the iterator doesn't point + // Use the standard emplace if the iterator doesn't point // to a matching key. return emplace_impl(a); } else { // Find the first node in the group - so that the node - // will be inserted at the end of the group. + // will be added at the end of the group. link_ptr start(it.node_); while(data_.prev_in_group(start)->next_ == start) @@ -1803,64 +1801,10 @@ namespace boost { } } -#if !(defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)) +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) - // Insert (unique keys) - - // if hash function throws, basic exception safety - // strong otherwise - std::pair emplace(value_type const& v) - { - // No side effects in this initial code - key_type const& k = extract_key(v); - size_type hash_value = hash_function()(k); - bucket_ptr bucket = data_.bucket_ptr_from_hash(hash_value); - link_ptr pos = find_iterator(bucket, k); - - if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { - // Found an existing key, return it (no throw). - return std::pair( - iterator_base(bucket, pos), false); - - } else { - // Doesn't already exist, add to bucket. - // Side effects only in this block. - - // Create the node before rehashing in case it throws an - // exception (need strong safety in such a case). - node_constructor a(data_.allocators_); - a.construct(v); - - // reserve has basic exception safety if the hash function - // throws, strong otherwise. - if(reserve_for_insert(size() + 1)) - bucket = data_.bucket_ptr_from_hash(hash_value); - - // Nothing after this point can throw. - - link_ptr n = data_.link_node_in_bucket(a, bucket); - - return std::pair( - iterator_base(bucket, n), true); - } - } - - // Insert (unique keys) - - // if hash function throws, basic exception safety - // strong otherwise - iterator_base emplace_hint(iterator_base const& it, value_type const& v) - { - if(it != data_.end() && equal(extract_key(v), *it)) - return it; - else - return emplace(v).first; - } - -#else - - // Insert (unique keys) - // (I'm using an overloaded insert for both 'insert' and 'emplace') + // Emplace (unique keys) + // (I'm using an overloaded emplace for both 'insert' and 'emplace') // // TODO: // For sets: create a local key without creating the node? @@ -1876,6 +1820,20 @@ namespace boost { std::forward(args)...); } + // Insert (unique keys) + // (I'm using an overloaded emplace for both 'insert' and 'emplace') + // I'm just ignoring hints here for now. + + // if hash function throws, basic exception safety + // strong otherwise + template + iterator_base emplace_hint(iterator_base const&, Args&&... args) + { + return emplace_impl( + extract_key(std::forward(args)...), + std::forward(args)...).first; + } + template std::pair emplace_impl(key_type const& k, Args&&... args) { @@ -1917,7 +1875,66 @@ namespace boost { // It will be discarded if it isn't used node_constructor a(data_.allocators_); a.construct(std::forward(args)...); + return emplace_impl_with_node(a); + } +#else + // Emplace (unique keys) + + // if hash function throws, basic exception safety + // strong otherwise + std::pair emplace(value_type const& v) + { + // No side effects in this initial code + key_type const& k = extract_key(v); + size_type hash_value = hash_function()(k); + bucket_ptr bucket = data_.bucket_ptr_from_hash(hash_value); + link_ptr pos = find_iterator(bucket, k); + + if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { + // Found an existing key, return it (no throw). + return std::pair( + iterator_base(bucket, pos), false); + + } else { + // Doesn't already exist, add to bucket. + // Side effects only in this block. + + // Create the node before rehashing in case it throws an + // exception (need strong safety in such a case). + node_constructor a(data_.allocators_); + a.construct(v); + + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + if(reserve_for_insert(size() + 1)) + bucket = data_.bucket_ptr_from_hash(hash_value); + + // Nothing after this point can throw. + + link_ptr n = data_.link_node_in_bucket(a, bucket); + + return std::pair( + iterator_base(bucket, n), true); + } + } + + // Emplace (unique keys) + + // if hash function throws, basic exception safety + // strong otherwise + iterator_base emplace_hint(iterator_base const& it, value_type const& v) + { + if(it != data_.end() && equal(extract_key(v), *it)) + return it; + else + return emplace(v).first; + } + +#endif + + std::pair emplace_impl_with_node(node_constructor& a) + { // No side effects in this initial code key_type const& k = extract_key(a.get()->value()); size_type hash_value = hash_function()(k); @@ -1941,18 +1958,6 @@ namespace boost { } } - // Insert (unique keys) - // (I'm using an overloaded insert for both 'insert' and 'emplace') - - // if hash function throws, basic exception safety - // strong otherwise - template - iterator_base emplace_hint(iterator_base const&, Args&&... args) - { - // Life is complicated - just call the normal implementation. - return emplace(std::forward(args)...).first; - } -#endif // Insert from iterators (unique keys) From 09b239ed287e6b959d4739f047b4137fcafe08bc Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 10 May 2009 21:25:09 +0000 Subject: [PATCH 068/471] Merge emplace support for sandbox - but without move support. [SVN r52885] --- include/boost/unordered/detail/hash_table.hpp | 20 + .../unordered/detail/hash_table_impl.hpp | 392 +++++++++++++----- include/boost/unordered/unordered_map.hpp | 88 ++++ include/boost/unordered/unordered_set.hpp | 87 ++++ test/unordered/compile_tests.hpp | 8 - test/unordered/unnecessary_copy_tests.cpp | 62 ++- 6 files changed, 519 insertions(+), 138 deletions(-) diff --git a/include/boost/unordered/detail/hash_table.hpp b/include/boost/unordered/detail/hash_table.hpp index b6bd9aa6..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 @@ -32,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +45,21 @@ #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) #define BOOST_UNORDERED_BORLAND_BOOL(x) (bool)(x) #else diff --git a/include/boost/unordered/detail/hash_table_impl.hpp b/include/boost/unordered/detail/hash_table_impl.hpp index ece2615e..81327302 100644 --- a/include/boost/unordered/detail/hash_table_impl.hpp +++ b/include/boost/unordered/detail/hash_table_impl.hpp @@ -183,15 +183,19 @@ namespace boost { void 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; + 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) @@ -202,32 +206,134 @@ namespace boost { 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) { construct_preamble(); - new(node_->address()) value_type(v); + 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_); @@ -1424,19 +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&) {} }; - // no throw - + + // 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); @@ -1454,6 +1570,9 @@ 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 @@ -1462,6 +1581,9 @@ namespace boost { 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_< @@ -1478,9 +1600,10 @@ namespace boost { return v.first; } -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) + // For maps if there is more than one argument, the key can be the first argument. - template +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) + template static BOOST_DEDUCED_TYPENAME boost::mpl::if_< boost::mpl::and_< @@ -1488,7 +1611,21 @@ namespace boost { boost::is_same >, key_type const&, no_key - >::type extract_key(Arg const& k, Args const&...) + >::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; } @@ -1632,34 +1769,39 @@ namespace boost { #else - // Emplace (equivalent key containers) - - // if hash function throws, basic exception safety - // strong otherwise - iterator_base emplace(value_type const& v) - { - // Create the node before rehashing in case it throws an - // exception (need strong safety in such a case). - node_constructor a(data_.allocators_); - a.construct(v); - - return emplace_impl(a); +#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); \ } - // Emplace (equivalent key containers) - - // if hash function throws, basic exception safety - // strong otherwise - iterator_base emplace_hint(iterator_base const& it, value_type const& v) - { - // Create the node before rehashing in case it throws an - // exception (need strong safety in such a case). - node_constructor a(data_.allocators_); - a.construct(v); - - return emplace_hint_impl(it, a); - } + 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) @@ -1788,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. @@ -1805,10 +1947,6 @@ namespace boost { // Emplace (unique keys) // (I'm using an overloaded emplace for both 'insert' and 'emplace') - // - // TODO: - // For sets: create a local key without creating the node? - // For maps: use the first argument as the key. // if hash function throws, basic exception safety // strong otherwise @@ -1878,59 +2016,97 @@ namespace boost { return emplace_impl_with_node(a); } #else - - // Emplace (unique keys) - - // if hash function throws, basic exception safety - // strong otherwise - std::pair emplace(value_type const& v) + template + std::pair emplace(Arg0 const& arg0) { - // 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); - } + return emplace_impl(extract_key(arg0), arg0); } - // Emplace (unique keys) - - // if hash function throws, basic exception safety - // strong otherwise - iterator_base emplace_hint(iterator_base const& it, value_type const& v) + template + iterator_base emplace_hint(iterator_base const& it, Arg0 const& arg0) { - if(it != data_.end() && equal(extract_key(v), *it)) - return it; - else - return emplace(v).first; + 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) @@ -1958,7 +2134,6 @@ namespace boost { } } - // Insert from iterators (unique keys) template @@ -2137,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 4d3f7a53..a7ebd691 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -232,6 +232,50 @@ namespace boost { 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) @@ -638,6 +682,50 @@ namespace boost { 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) diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index a99db075..f39a76df 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -231,6 +231,50 @@ namespace boost 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) @@ -607,6 +651,49 @@ namespace boost { 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) 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 d2ab8629..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; @@ -194,8 +213,10 @@ namespace unnecessary_copy_tests // 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); } @@ -232,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 @@ -269,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 20c93605288ad8f89e2416416f54b78839f75326 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 20 May 2009 06:43:38 +0000 Subject: [PATCH 069/471] Better configuration for boost.unordered. [SVN r53127] --- include/boost/unordered/detail/config.hpp | 8 ++++++++ include/boost/unordered/detail/hash_table.hpp | 3 ++- include/boost/unordered/detail/hash_table_impl.hpp | 8 ++++---- include/boost/unordered/unordered_map.hpp | 12 ++++++++---- include/boost/unordered/unordered_set.hpp | 12 ++++++++---- test/objects/exception.hpp | 2 +- test/objects/minimal.hpp | 2 +- test/objects/test.hpp | 2 +- 8 files changed, 33 insertions(+), 16 deletions(-) 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..bc842dc8 100644 --- a/include/boost/unordered/detail/hash_table_impl.hpp +++ b/include/boost/unordered/detail/hash_table_impl.hpp @@ -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) { @@ -1602,7 +1602,7 @@ namespace boost { // 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) +#if defined(BOOST_UNORDERED_STD_FORWARD) template static BOOST_DEDUCED_TYPENAME boost::mpl::if_< @@ -1733,7 +1733,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 +1943,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..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,7 +223,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) { @@ -585,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(), @@ -670,7 +674,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) { diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index f39a76df..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,7 +221,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) { @@ -555,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(), @@ -639,7 +643,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) { 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)...); From cfc134b8717159f095b2fb900bc73511b9a6dd56 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 25 May 2009 19:14:07 +0000 Subject: [PATCH 070/471] Add explicit destructors to the unordered containers. Refs #2908. Isn't really needed but it doesn't hurt. [SVN r53253] --- include/boost/unordered/unordered_map.hpp | 4 ++++ include/boost/unordered/unordered_set.hpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 5a282879..85bb9254 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -108,6 +108,8 @@ namespace boost { } + ~unordered_map() {} + #if defined(BOOST_HAS_RVALUE_REFS) unordered_map(unordered_map&& other) : base(other.base, boost::unordered_detail::move_tag()) @@ -558,6 +560,8 @@ namespace boost { } + ~unordered_multimap() {} + #if defined(BOOST_HAS_RVALUE_REFS) unordered_multimap(unordered_multimap&& other) : base(other.base, boost::unordered_detail::move_tag()) diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index cfe6c9b7..18d92ccc 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -105,6 +105,8 @@ namespace boost : base(f, l, n, hf, eql, a) { } + + ~unordered_set() {} #if defined(BOOST_HAS_RVALUE_REFS) unordered_set(unordered_set&& other) @@ -528,6 +530,8 @@ namespace boost { } + ~unordered_multiset() {} + #if defined(BOOST_HAS_RVALUE_REFS) unordered_multiset(unordered_multiset&& other) : base(other.base, boost::unordered_detail::move_tag()) From 8f70ddf4ef20b8581880b7363c72604428670020 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 25 May 2009 19:45:06 +0000 Subject: [PATCH 071/471] Unordered change log. [SVN r53255] --- doc/changes.qbk | 10 ++++++++++ 1 file changed, 10 insertions(+) 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] From bde5df043c7f10d2e71871b1d48fd0d42296de03 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 25 May 2009 19:45:23 +0000 Subject: [PATCH 072/471] Unordered change log for explicit destructors. [SVN r53256] --- doc/changes.qbk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/changes.qbk b/doc/changes.qbk index a8b81eef..ae66737e 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -79,5 +79,7 @@ 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]: + Add explicit destructors to all containers. [endsect] From 35a3894a88093e275da27335ed5b61d1f8803e7c Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 27 May 2009 17:42:01 +0000 Subject: [PATCH 073/471] Missing changelog entry. [SVN r53311] --- doc/changes.qbk | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changes.qbk b/doc/changes.qbk index ae66737e..956e0eae 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -79,6 +79,7 @@ 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. From 84ff0c322754cd0988f6217eebfaa7cf1e800238 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 27 May 2009 17:43:22 +0000 Subject: [PATCH 074/471] Remove obsolete comment. [SVN r53312] --- test/helpers/memory.hpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/helpers/memory.hpp b/test/helpers/memory.hpp index f4ac8a11..5dc02b70 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; From 04234ceceec446c7b17eafd583aa89f8ced080f4 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 27 May 2009 17:44:09 +0000 Subject: [PATCH 075/471] Use lightweight_test for unordered. [SVN r53314] --- 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/memory.hpp | 18 ++-- test/helpers/test.hpp | 15 +-- test/helpers/tracker.hpp | 4 +- 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 ++++---- 25 files changed, 299 insertions(+), 334 deletions(-) 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/memory.hpp b/test/helpers/memory.hpp index 5dc02b70..6dbec85f 100644 --- a/test/helpers/memory.hpp +++ b/test/helpers/memory.hpp @@ -98,7 +98,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) { @@ -111,9 +111,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); } } } @@ -139,12 +139,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; } @@ -155,7 +155,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/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 46caec7d77d98ba28aa141a4bc029e818fe70781 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 27 May 2009 18:19:32 +0000 Subject: [PATCH 076/471] Some workarounds for old versions of Borland. [SVN r53316] --- include/boost/unordered/detail/hash_table_impl.hpp | 2 +- include/boost/unordered/unordered_map.hpp | 10 ++++++++-- include/boost/unordered/unordered_set.hpp | 14 ++++++++++---- test/helpers/list.hpp | 4 ++-- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/include/boost/unordered/detail/hash_table_impl.hpp b/include/boost/unordered/detail/hash_table_impl.hpp index bc842dc8..10ede2e5 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; } }; diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 85bb9254..d2793c56 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -39,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; @@ -461,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 @@ -491,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; @@ -897,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 18d92ccc..ad0bc36e 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -39,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; @@ -430,10 +433,10 @@ namespace boost base.rehash(n); } -#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) +#if 1 || 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 @@ -463,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; @@ -850,10 +856,10 @@ namespace boost base.rehash(n); } -#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) +#if 1 || 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/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_; } From caa0b7cdf68dbc8bda90340f9f6bb9bbcd891446 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 27 May 2009 18:32:22 +0000 Subject: [PATCH 077/471] Fix a change accidentally included in the last commit. [SVN r53317] --- include/boost/unordered/unordered_set.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index ad0bc36e..07ed746b 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -433,7 +433,7 @@ namespace boost base.rehash(n); } -#if 1 || BOOST_WORKAROUND(BOOST_MSVC, < 1300) +#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) @@ -856,7 +856,7 @@ namespace boost base.rehash(n); } -#if 1 || BOOST_WORKAROUND(BOOST_MSVC, < 1300) +#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) From b83a73ab406917c89f7dbba4da3637c9ccd981fe Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 27 May 2009 18:32:38 +0000 Subject: [PATCH 078/471] Remove an unused function. [SVN r53318] --- include/boost/unordered/detail/hash_table_impl.hpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/include/boost/unordered/detail/hash_table_impl.hpp b/include/boost/unordered/detail/hash_table_impl.hpp index 10ede2e5..cee3e051 100644 --- a/include/boost/unordered/detail/hash_table_impl.hpp +++ b/include/boost/unordered/detail/hash_table_impl.hpp @@ -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 Date: Thu, 28 May 2009 22:06:42 +0000 Subject: [PATCH 079/471] Remove a couple of old uses of BOOST_NO_INITIALIZER_LISTS. [SVN r53367] --- test/unordered/assign_tests.cpp | 2 +- test/unordered/constructor_tests.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 cec18915865e3712800fc7bd08534d8b341cdc60 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 31 May 2009 15:50:56 +0000 Subject: [PATCH 080/471] Disable incorrect Visual C++ 64-bit warnings. Ref #3082. [SVN r53505] --- include/boost/unordered/detail/hash_table.hpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) 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 From 78ea3024b5c0b5c0ef4f1b5542195e4dfff75815 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 1 Jun 2009 06:50:37 +0000 Subject: [PATCH 081/471] Fix tests for when the library has support for initializer lists but the compiler doesn't. [SVN r53525] --- test/unordered/assign_tests.cpp | 15 +++++++++++++++ test/unordered/constructor_tests.cpp | 11 +++++++++++ 2 files changed, 26 insertions(+) diff --git a/test/unordered/assign_tests.cpp b/test/unordered/assign_tests.cpp index efe1c157..8ed2b392 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 2b09a3446754c2329275f61f4c69f12cee3afc7f Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 1 Jun 2009 19:17:49 +0000 Subject: [PATCH 082/471] Get the type of the initializer_list right. [SVN r53550] --- test/unordered/assign_tests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unordered/assign_tests.cpp b/test/unordered/assign_tests.cpp index 8ed2b392..56df1b20 100644 --- a/test/unordered/assign_tests.cpp +++ b/test/unordered/assign_tests.cpp @@ -107,7 +107,7 @@ UNORDERED_TEST(assign_tests2, UNORDERED_AUTO_TEST(assign_default_initializer_list) { std::cerr<<"Initializer List Tests\n"; - std::initializer_list > init; + std::initializer_list > init; boost::unordered_map x1; x1[25] = 3; x1[16] = 10; From 7e1dbc4cb78d8767bd02eafcb1f3f8307994b288 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 1 Jun 2009 19:22:27 +0000 Subject: [PATCH 083/471] Fix the unordered_map declaration in the tutorial. Fixes #3119. [SVN r53552] --- doc/hash_equality.qbk | 2 +- 1 file changed, 1 insertion(+), 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 From 6d1aece43a9612d6ce106a76f3f732e904ea49c9 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 12 Jul 2009 18:03:35 +0000 Subject: [PATCH 084/471] Add constructors to the methods for controlling bucket size in unordered containers. [SVN r54914] --- 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 7bc588d8df44d79c91f62e203abb33781a1a3004 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 22 Jul 2009 22:37:52 +0000 Subject: [PATCH 085/471] Fix the insert tests when there is a small number of buckets. [SVN r55099] --- test/exception/insert_exception_tests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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(), From 3c48fa3818722b9575d90083443abeeee6b6f7c0 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 22 Jul 2009 22:38:08 +0000 Subject: [PATCH 086/471] Adjust the unordered defaults so that emplace takes more parameters and less buckets are created by default. [SVN r55100] --- include/boost/unordered/detail/hash_table.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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) From ca018bfba658bcdead1ea7b3c25ba75b71f57dad Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 23 Jul 2009 17:53:59 +0000 Subject: [PATCH 087/471] Remove the emulation of single argument C++0x std::pair constructor. [SVN r55132] --- .../unordered/detail/hash_table_impl.hpp | 64 +++---------------- test/helpers/input_iterator.hpp | 19 +++++- 2 files changed, 25 insertions(+), 58 deletions(-) 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/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 cf363355df9d54262d50a6498a5888d49ec670fd Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 23 Jul 2009 22:17:20 +0000 Subject: [PATCH 088/471] Try to work around an odd Visual C++ 8 bug. [SVN r55138] --- include/boost/unordered/unordered_map.hpp | 26 +++++++++++++++++++---- include/boost/unordered/unordered_set.hpp | 24 +++++++++++++++++---- 2 files changed, 42 insertions(+), 8 deletions(-) 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) { } From d5dac9bdae5d5cf4087c051310f63d42a7b8076f Mon Sep 17 00:00:00 2001 From: "Troy D. Straszheim" Date: Sun, 26 Jul 2009 00:49:56 +0000 Subject: [PATCH 089/471] Copyrights on CMakeLists.txt to keep them from clogging up the inspect reports. This is essentially the same commit as r55095 on the release branch. [SVN r55159] --- CMakeLists.txt | 6 ++++++ test/CMakeLists.txt | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 20891f58..c1213cbd 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 e164a7bf..a2df088e 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 From 178154082f2b214c32f4b66a33726e29f58581a1 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 26 Jul 2009 18:59:33 +0000 Subject: [PATCH 090/471] Some extra changelog notes. [SVN r55184] --- doc/changes.qbk | 9 +++++++-- 1 file changed, 7 insertions(+), 2 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] From 16325229670f676a25cc865295c7a6b408e4209a Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 26 Jul 2009 19:00:40 +0000 Subject: [PATCH 091/471] Update the reference documentation to mention that emplace is now emulated. [SVN r55185] --- doc/ref.xml | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) 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. From 43506606263ec398caa32d1227429b2fc16ebabe Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 30 Aug 2009 16:33:42 +0000 Subject: [PATCH 092/471] Remove allocator_constructor since it's never used. [SVN r55877] --- .../unordered/detail/allocator_helpers.hpp | 55 ------------------- 1 file changed, 55 deletions(-) diff --git a/include/boost/unordered/detail/allocator_helpers.hpp b/include/boost/unordered/detail/allocator_helpers.hpp index 0c0bd3a5..c96f365d 100644 --- a/include/boost/unordered/detail/allocator_helpers.hpp +++ b/include/boost/unordered/detail/allocator_helpers.hpp @@ -118,61 +118,6 @@ namespace boost { #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 - } - - ~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 { From 386d9f28d76dfdf1eb787a16be59a153aa6fb47c Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 30 Aug 2009 16:42:28 +0000 Subject: [PATCH 093/471] 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. [SVN r55878] --- .../unordered/detail/allocator_helpers.hpp | 202 +- include/boost/unordered/detail/config.hpp | 30 - .../boost/unordered/detail/extract_key.hpp | 156 + include/boost/unordered/detail/fwd.hpp | 625 ++++ include/boost/unordered/detail/hash_table.hpp | 347 --- .../unordered/detail/hash_table_impl.hpp | 2527 ----------------- include/boost/unordered/detail/insert.hpp | 672 +++++ include/boost/unordered/detail/manager.hpp | 270 ++ include/boost/unordered/detail/move.hpp | 17 +- include/boost/unordered/detail/node.hpp | 265 ++ include/boost/unordered/detail/structure.hpp | 220 ++ include/boost/unordered/detail/table.hpp | 561 ++++ include/boost/unordered/detail/util.hpp | 333 +++ include/boost/unordered/unordered_map.hpp | 415 +-- include/boost/unordered/unordered_set.hpp | 396 +-- test/Jamfile.v2 | 2 + test/unordered/copy_tests.cpp | 8 +- test/unordered/move_tests.cpp | 4 +- test/unordered/simple_tests.cpp | 3 +- 19 files changed, 3622 insertions(+), 3431 deletions(-) delete mode 100644 include/boost/unordered/detail/config.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/insert.hpp create mode 100644 include/boost/unordered/detail/manager.hpp create mode 100644 include/boost/unordered/detail/node.hpp create mode 100644 include/boost/unordered/detail/structure.hpp create mode 100644 include/boost/unordered/detail/table.hpp create mode 100644 include/boost/unordered/detail/util.hpp diff --git a/include/boost/unordered/detail/allocator_helpers.hpp b/include/boost/unordered/detail/allocator_helpers.hpp index c96f365d..092e78af 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,159 +23,85 @@ # 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_array_constructor - { - typedef BOOST_DEDUCED_TYPENAME allocator_pointer::type pointer; - - Allocator& alloc_; - pointer ptr_; - pointer constructed_; - std::size_t length_; - - 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 + alloc_.deallocate(ptr_, length_); } + } - ~allocator_array_constructor() { - if (ptr_) { - for(pointer p = ptr_; p != constructed_; ++p) - alloc_.destroy(p); + 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); + } - alloc_.deallocate(ptr_, length_); - } - } + pointer get() const + { + return ptr_; + } - 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/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/extract_key.hpp b/include/boost/unordered/detail/extract_key.hpp new file mode 100644 index 00000000..63dce95e --- /dev/null +++ b/include/boost/unordered/detail/extract_key.hpp @@ -0,0 +1,156 @@ + +// 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 + }; + }; + + 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 + + }; + }; +}} + +#endif diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp new file mode 100644 index 00000000..a4ffdb7c --- /dev/null +++ b/include/boost/unordered/detail/fwd.hpp @@ -0,0 +1,625 @@ + +// 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 + +// 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 + +#include + +#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 + +namespace boost { namespace unordered_detail { + + static const float minimum_max_load_factor = 1e-3f; + static const std::size_t default_initial_bucket_count = 11; + struct move_tag {}; + + // 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_group_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 node); + static void unlink_nodes(bucket& b, node_ptr begin, node_ptr end); + static void unlink_nodes(bucket& b, node_ptr end); + static inline void unlink_group(node_ptr* b); + }; + + 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& group_prev(node_ptr ptr); + 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_group_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 node); + static void unlink_nodes(bucket& b, node_ptr begin, node_ptr end); + static void unlink_nodes(bucket& b, node_ptr end); + static inline void unlink_group(node_ptr* b); + + 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 NodeBase, public value_base + { + typedef ValueType value_type; + typedef BOOST_DEDUCED_TYPENAME NodeBase::node_ptr node_ptr; + public: + static value_type& get_value(node_ptr p) { return static_cast(*p).value(); } + }; + + template + struct hash_structure + { + typedef BOOST_DEDUCED_TYPENAME + G::BOOST_NESTED_TEMPLATE base::type + node_base; + typedef BOOST_DEDUCED_TYPENAME node_base::bucket_allocator bucket_allocator; + typedef BOOST_DEDUCED_TYPENAME node_base::bucket_ptr bucket_ptr; + typedef BOOST_DEDUCED_TYPENAME node_base::node_ptr node_ptr; + + // The actual data structure + + bucket_ptr buckets_; + bucket_ptr cached_begin_bucket_; + std::size_t size_; + std::size_t bucket_count_; + + // Constructor + + hash_structure() : buckets_(), cached_begin_bucket_(), size_() {} + + void swap(hash_structure& other); + + // Buckets + + std::size_t bucket_count() const; + std::size_t bucket_from_hash(std::size_t hashed) const; + bucket_ptr bucket_ptr_from_hash(std::size_t hashed) const; + bucket_ptr buckets_begin() const; + bucket_ptr buckets_end() const; + std::size_t bucket_size(std::size_t index) const; + + // Link a node + + void link_node(node_ptr n, node_ptr position); + void link_node_in_bucket(node_ptr n, bucket_ptr bucket); + void unlink_node(bucket_ptr bucket, node_ptr pos); + void unlink_nodes(bucket_ptr bucket, node_ptr begin, node_ptr end); + void unlink_nodes(bucket_ptr bucket, node_ptr end); + std::size_t unlink_group(node_ptr* pos); + void link_group(node_ptr n, bucket_ptr bucket, std::size_t count); + bucket_ptr get_bucket(std::size_t n) const; + node_ptr bucket_begin(std::size_t n) const; + node_ptr bucket_end(std::size_t) const; + + // 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); + + // 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 + + template + class hash_iterator_base + { + public: + typedef BucketPtr bucket_ptr; + typedef BucketPtr node_ptr; + + bucket_ptr bucket_; + node_ptr node_; + + hash_iterator_base() : bucket_(), node_() {} + explicit hash_iterator_base(bucket_ptr b) : bucket_(b), node_(b->next_) {} + 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_; } + bool is_end() const { return node_ == bucket_; } + node_ptr get() const { return node_; } + void increment(node_ptr node); + void increment(); + }; + + // hash_table_manager + // + // 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 + struct hash_table_manager : + hash_structure + { + // Types + + typedef hash_bucket bucket; + typedef hash_structure structure; + typedef BOOST_DEDUCED_TYPENAME structure::bucket_allocator bucket_allocator; + typedef BOOST_DEDUCED_TYPENAME structure::node_base node_base; + typedef BOOST_DEDUCED_TYPENAME structure::bucket_ptr bucket_ptr; + typedef BOOST_DEDUCED_TYPENAME structure::node_ptr node_ptr; + + typedef A value_allocator; + typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; + + typedef hash_node node; + typedef BOOST_DEDUCED_TYPENAME rebind_wrap::type node_allocator; + typedef BOOST_DEDUCED_TYPENAME node_allocator::pointer real_node_ptr; + + typedef hash_iterator_base iterator_base; + + // Members + + 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(); } + iterator_base begin() const { return iterator_base(this->cached_begin_bucket_); } + iterator_base end() const { return iterator_base(this->buckets_end()); } + std::size_t max_bucket_count() const { + // -1 to account for the sentinel. + return prev_prime(this->bucket_alloc().max_size() - 1); + } + + // Constructors + // + // The copy constructor doesn't copy the buckets. + + hash_table_manager(); + explicit hash_table_manager(value_allocator const& a); + explicit hash_table_manager(hash_table_manager const& h); + hash_table_manager(hash_table_manager& x, move_tag m); + hash_table_manager(hash_table_manager& x, value_allocator const& a, move_tag m); + ~hash_table_manager(); + + // no throw + void move(hash_table_manager& other); + + // Methods + + void create_buckets(std::size_t bucket_count); + + // Alloc/Dealloc + + void destruct_node(node_ptr); + + // + void delete_buckets(); + void clear(); + void clear_bucket(bucket_ptr); + void delete_group(node_ptr first_node); + void delete_nodes(node_ptr begin, node_ptr end); + void delete_to_bucket_end(node_ptr begin); + + // Erase + // + // no throw + + 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); + }; + + template + class hash_table : + public hash_table_manager + + { + public: + typedef H hasher; + typedef P key_equal; + typedef A value_allocator; + typedef G grouped; + typedef K key_extractor; + typedef hash_table_manager manager; + + 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 manager::node node; + typedef BOOST_DEDUCED_TYPENAME manager::bucket bucket; + typedef BOOST_DEDUCED_TYPENAME manager::node_ptr node_ptr; + typedef BOOST_DEDUCED_TYPENAME manager::bucket_ptr bucket_ptr; + + typedef BOOST_DEDUCED_TYPENAME manager::iterator_base iterator_base; + + // Types for storing functions + + typedef boost::compressed_pair functions; + typedef bool functions_ptr; + + typedef BOOST_DEDUCED_TYPENAME boost::aligned_storage< + sizeof(functions), + ::boost::alignment_of::value>::type aligned_function; + + // Members + + bool func_; // The currently active functions. + aligned_function funcs_[2]; + float mlf_; + std::size_t max_load_; + + // Buffered Functions + + functions* get_functions(bool which) { + return static_cast(static_cast(&this->funcs_[which])); + } + functions const* get_functions(bool which) const { + return static_cast(static_cast(&this->funcs_[which])); + } + functions const& current() const { + return *this->get_functions(this->func_); + } + hasher const& hash_function() const { + return this->current().first(); + } + key_equal const& key_eq() const { + return this->current().second(); + } + functions_ptr buffer_functions(hash_table const& x) { + functions_ptr ptr = !func_; + *this->get_functions(ptr) = x.current(); + return ptr; + } + void set_functions(functions_ptr ptr) { + BOOST_ASSERT(ptr != func_); + func_ = ptr; + } + + // Helper methods + + 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; + void calculate_max_load(); + + // Constructors + + hash_table(std::size_t n, hasher const& hf, key_equal const& eq, value_allocator const& a); + hash_table(hash_table const& x); + hash_table(hash_table const& x, value_allocator const& a); + hash_table(hash_table& x, move_tag m); + hash_table(hash_table& x, value_allocator const& a, move_tag m); + ~hash_table(); + hash_table& operator=(hash_table const&); + + // Swap & Move + + void swap(hash_table& x); + void move(hash_table& x); + + // Reserve and rehash + + bool reserve(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(manager& dst); + void copy_buckets_to(manager& dst) const; + + // Misc. key methods + + std::size_t erase_key(key_type const& k); + 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; + std::pair equal_range(key_type const& k) const; + }; + + // 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_table_manager manager; + typedef BOOST_DEDUCED_TYPENAME manager::node_ptr ptr; + typedef BOOST_DEDUCED_TYPENAME manager::node node; + typedef hash_const_local_iterator const_local_iterator; + + friend class hash_const_local_iterator; + ptr ptr_; + + public: + hash_local_iterator() : ptr_() {} + explicit hash_local_iterator(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_ = next_node(ptr_); return *this; } + hash_local_iterator operator++(int) { hash_local_iterator tmp(ptr_); ptr_ = next_node(ptr_); 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_table_manager manager; + typedef BOOST_DEDUCED_TYPENAME manager::node_ptr ptr; + typedef BOOST_DEDUCED_TYPENAME manager::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_ = next_node(ptr_); return *this; } + hash_const_local_iterator operator++(int) { hash_const_local_iterator tmp(ptr_); ptr_ = next_node(ptr_); 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_table_manager manager; + typedef BOOST_DEDUCED_TYPENAME manager::node node; + typedef BOOST_DEDUCED_TYPENAME manager::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 node::get_value(base_.get()); } + value_type* operator->() const { return &node::get_value(base_.get()); } + 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_table_manager manager; + typedef BOOST_DEDUCED_TYPENAME manager::node node; + typedef BOOST_DEDUCED_TYPENAME manager::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 node::get_value(base_.get()); } + value_type const* operator->() const { return &node::get_value(base_.get()); } + 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/insert.hpp b/include/boost/unordered/detail/insert.hpp new file mode 100644 index 00000000..26520015 --- /dev/null +++ b/include/boost/unordered/detail/insert.hpp @@ -0,0 +1,672 @@ + +// 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_INSERT_HPP_INCLUDED +#define BOOST_UNORDERED_DETAIL_INSERT_HPP_INCLUDED + +#include +#include + +namespace boost { namespace unordered_detail { + + //////////////////////////////////////////////////////////////////////////// + // A couple of convenience methods for adding nodes. + + // H = Has Func + // P = Predicate + // A = Value Allocator + // K = Key Extractor + + 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; + + // 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) {} + 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 + + std::pair emplace_impl_with_node(node_constructor& a); + value_type& operator[](key_type const& k); + + // equals + + bool equals(hash_unique_table const&) const; + static bool group_equals(node_ptr it1, node_ptr it2, set_extractor*); + static bool group_equals(node_ptr it1, node_ptr it2, map_extractor*); + + inline node_ptr add_node(node_constructor& a, bucket_ptr bucket) + { + node_ptr n = a.release(); + this->link_node_in_bucket(n, bucket); + return n; + } + +#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( + extractor::extract(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( + extractor::extract(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 + 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 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(*this); + a.construct(std::forward(args)...); + + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + if(reserve_for_insert(this->size_ + 1)) + bucket = this->bucket_ptr_from_hash(hash_value); + + // Nothing after this point can throw. + + return std::pair(iterator_base(bucket, + add_node(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(*this); + a.construct(std::forward(args)...); + return emplace_impl_with_node(a); + } +#else + template + std::pair emplace(Arg0 const& arg0) + { + return emplace_impl(extractor::extract(arg0), arg0); + } + + template + iterator_base emplace_hint(iterator_base const&, Arg0 const& arg0) + { + return emplace_impl(extractor::extract(arg0), arg0).first; + } + +#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ + template \ + std::pair emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + return emplace_impl(extractor::extract(arg0, arg1), \ + BOOST_UNORDERED_CALL_PARAMS(z, n)); \ + } \ + \ + template \ + iterator_base emplace_hint(iterator_base const& it, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + return emplace_impl(extractor::extract(arg0, arg1), \ + BOOST_UNORDERED_CALL_PARAMS(z, n)).first; \ + } \ + BOOST_UNORDERED_INSERT_IMPL2(z, n, _) + +#define BOOST_UNORDERED_INSERT_IMPL2(z, n, _) \ + template \ + std::pair emplace_impl(key_type const& k, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + 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 std::pair( \ + iterator_base(bucket, pos), false); \ + } else { \ + node_constructor a(*this); \ + a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \ + \ + if(reserve_for_insert(this->size_ + 1)) \ + bucket = this->bucket_ptr_from_hash(hash_value); \ + \ + return std::pair(iterator_base(bucket, \ + add_node(a, bucket)), true); \ + } \ + } \ + \ + template \ + std::pair emplace_impl(no_key, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + node_constructor a(*this); \ + 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 + + // 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(extractor::extract(*i), i, j); + } + + template + void insert_range_impl(key_type const&, InputIterator i, InputIterator j) + { + node_constructor a(*this); + + for (; i != j; ++i) { + // No side effects in this initial code + std::size_t hash_value = this->hash_function()(extractor::extract(*i)); + bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); + node_ptr pos = find_iterator(bucket, extractor::extract(*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(this->size_ + 1 >= this->max_load_) { + 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 + void insert_range_impl(no_key, InputIterator i, InputIterator j) + { + node_constructor a(*this); + + for (; i != j; ++i) { + // No side effects in this initial code + a.construct(*i); + emplace_impl_with_node(a); + } + } + }; + + 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 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; + + // 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) {} + 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; + static bool group_equals(node_ptr it1, node_ptr it2, set_extractor*); + static bool group_equals(node_ptr it1, node_ptr it2, map_extractor*); + + inline node_ptr add_node(node_constructor& a, bucket_ptr bucket, node_ptr pos) + { + node_ptr n = a.release(); + if(BOOST_UNORDERED_BORLAND_BOOL(pos)) + this->link_node(n, pos); + else + this->link_node_in_bucket(n, bucket); + return n; + } + + public: + + // Insert functions + // + // basic exception safety, if hash function throws + // strong otherwise. + +#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(*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 + 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(*this); + a.construct(std::forward(args)...); + + return emplace_hint_impl(it, a); + } + +#else + +#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ + template \ + iterator_base emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + node_constructor a(*this); \ + a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \ + return emplace_impl(a); \ + } \ + \ + template \ + iterator_base emplace_hint(iterator_base const& it, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + node_constructor a(*this); \ + 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 + + // 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) + { + std::size_t distance = unordered_detail::distance(i, j); + if(distance == 1) { + emplace(*i); + } + else { + // Only require basic exception safety here + reserve_for_insert(this->size_ + distance); + node_constructor a(*this); + + 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 + void 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); + } + } + + 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); + } + }; + + //////////////////////////////////////////////////////////////////////////// + // Unique insert methods + + template + std::pair< + BOOST_DEDUCED_TYPENAME hash_unique_table::iterator_base, + bool> + hash_unique_table + ::emplace_impl_with_node(node_constructor& a) + { + // No side effects in this initial code + key_type const& k = extractor::extract(a.get()->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 std::pair( + iterator_base(bucket, pos), false); + } else { + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + if(reserve_for_insert(this->size_ + 1)) + bucket = this->bucket_ptr_from_hash(hash_value); + + // Nothing after this point can throw. + + return std::pair(iterator_base(bucket, + add_node(a, bucket)), true); + } + } + + // 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); + 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(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)); + } + } + + //////////////////////////////////////////////////////////////////////////// + // Insert methods + + template + BOOST_DEDUCED_TYPENAME hash_equivalent_table::iterator_base + hash_equivalent_table + ::emplace_impl(node_constructor& a) + { + key_type const& k = extractor::extract(a.get()->value()); + std::size_t hash_value = this->hash_function()(k); + 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(reserve_for_insert(this->size_ + 1)) + bucket = this->bucket_ptr_from_hash(hash_value); + + // I'm relying on node_ptr not being invalidated by + // the rehash here. + return iterator_base(bucket, add_node(a, bucket, position)); + } + + template + 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.is_end() || + !equal(extractor::extract(a.get()->value()), node::get_value(it.get()))) { + // 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(it.node_); + while(node::next_group(start) == start) + start = node::group_prev(start); + + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + bucket_ptr bucket = reserve_for_insert(this->size_ + 1) ? + get_bucket(this->bucket_index( + extractor::extract(a.get()->value()))) : it.bucket_; + + // Nothing after this point can throw + + return iterator_base(bucket, add_node(a, bucket, start)); + } + } + + template + void hash_equivalent_table + ::emplace_impl_no_rehash(node_constructor& a) + { + key_type const& k = extractor::extract(a.get()->value()); + bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); + add_node(a, bucket, find_iterator(bucket, k)); + } + + //////////////////////////////////////////////////////////////////////////// + // Equalilty check + + template + inline bool hash_equivalent_table + ::group_equals(node_ptr it1, node_ptr it2, set_extractor*) + { + return node::group_count(it1) == node::group_count(it2); + } + + template + inline bool hash_equivalent_table + ::group_equals(node_ptr it1, node_ptr it2, map_extractor*) + { + node_ptr end1 = node::next_group(it1); + node_ptr end2 = node::next_group(it2); + + do { + if(node::get_value(it1).second != node::get_value(it2).second) return false; + it1 = next_node(it1); + it2 = next_node(it2); + } while(it1 != end1 && it2 != end2); + return it1 == end1 && it2 == end2; + } + + template + bool hash_equivalent_table + ::equals(hash_equivalent_table const& other) const + { + if(this->size_ != other.size_) return false; + + for(bucket_ptr i = this->cached_begin_bucket_, j = this->buckets_end(); i != j; ++i) + { + for(node_ptr it(i->next_); BOOST_UNORDERED_BORLAND_BOOL(it); it = node::next_group(it)) + { + node_ptr other_pos = other.find_iterator(extractor::extract(node::get_value(it))); + if(!BOOST_UNORDERED_BORLAND_BOOL(other_pos) || + !group_equals(it, other_pos, (K*)0)) + return false; + } + } + + return true; + } + + template + inline bool hash_unique_table + ::group_equals(node_ptr it1, node_ptr it2, set_extractor*) + { + return true; + } + + template + inline bool hash_unique_table + ::group_equals(node_ptr it1, node_ptr it2, map_extractor*) + { + return node::get_value(it1).second == node::get_value(it2).second; + } + + template + bool hash_unique_table + ::equals(hash_unique_table const& other) const + { + if(this->size_ != other.size_) return false; + + for(bucket_ptr i = this->cached_begin_bucket_, j = this->buckets_end(); i != j; ++i) + { + for(node_ptr it(i->next_); BOOST_UNORDERED_BORLAND_BOOL(it); it = node::next_group(it)) + { + node_ptr other_pos = other.find_iterator(extractor::extract(node::get_value(it))); + if(!BOOST_UNORDERED_BORLAND_BOOL(other_pos) || + !group_equals(it, other_pos, (K*)0)) + return false; + } + } + + return true; + } + +}} + +#endif diff --git a/include/boost/unordered/detail/manager.hpp b/include/boost/unordered/detail/manager.hpp new file mode 100644 index 00000000..0da4c674 --- /dev/null +++ b/include/boost/unordered/detail/manager.hpp @@ -0,0 +1,270 @@ + +// 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 { + + //////////////////////////////////////////////////////////////////////////// + // Explicitly call a destructor + +#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 + + // Constructors + + template + hash_table_manager::hash_table_manager() + : structure(), allocators_() {} + + template + hash_table_manager::hash_table_manager(value_allocator const& a) + : structure(), allocators_(a,a) {} + + template + hash_table_manager::hash_table_manager(hash_table_manager const& h) + : structure(), allocators_(h.allocators_) {} + + template + hash_table_manager::hash_table_manager(hash_table_manager& x, move_tag m) + : structure(), allocators_(x.allocators_) + { + this->buckets_ = x.buckets_; + this->cached_begin_bucket_ = x.cached_begin_bucket_; + this->size_ = x.size_; + this->bucket_count_ = x.bucket_count_; + x.buckets_ = bucket_ptr(); + x.cached_begin_bucket_ = bucket_ptr(); + x.size_ = 0; + x.bucket_count_ = 0; + } + + template + hash_table_manager::hash_table_manager(hash_table_manager& x, value_allocator const& a, move_tag m) : + structure(), allocators_(a,a) + { + if(this->node_alloc() == x.node_alloc()) { + this->buckets_ = x.buckets_; + this->cached_begin_bucket_ = x.cached_begin_bucket_; + this->size_ = x.size_; + this->bucket_count_ = x.bucket_count_; + x.buckets_ = bucket_ptr(); + x.cached_begin_bucket_ = bucket_ptr(); + x.size_ = 0; + x.bucket_count_ = 0; + } + } + + template + hash_table_manager::~hash_table_manager() + { + if(this->buckets_) { delete_buckets(); } + } + + // no throw + template + void hash_table_manager::move(hash_table_manager& other) + { + delete_buckets(); + this->buckets_ = other.buckets_; + this->cached_begin_bucket_ = other.cached_begin_bucket_; + this->size_ = other.size_; + this->bucket_count_ = other.bucket_count_; + other.buckets_ = bucket_ptr(); + other.cached_begin_bucket_ = bucket_ptr(); + other.size_ = 0; + other.bucket_count_ = 0; + } + + // Construct/destruct + + template + void hash_table_manager::create_buckets(std::size_t bucket_count) { + BOOST_ASSERT(!this->buckets_ && !this->size_); + + // 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(), bucket_count + 1); + + this->cached_begin_bucket_ = constructor.get() + static_cast(bucket_count); + + // Set up the sentinel (node_ptr cast) + this->cached_begin_bucket_->next_ = this->cached_begin_bucket_; + + // Only release the buckets once everything is successfully + // done. + this->buckets_ = constructor.release(); + this->bucket_count_ = bucket_count; + } + + template + void hash_table_manager::destruct_node(node_ptr b) + { + node* raw_ptr = static_cast(&*b); + BOOST_UNORDERED_DESTRUCT(&raw_ptr->value(), value_type); + real_node_ptr n(node_alloc().address(*raw_ptr)); + node_alloc().destroy(n); + node_alloc().deallocate(n, 1); + } + + // Delete and clear buckets + + template + void hash_table_manager::delete_group(node_ptr first_node) + { + delete_nodes(first_node, node::next_group(first_node)); + } + + template + void hash_table_manager::delete_nodes(node_ptr begin, node_ptr end) + { + while(begin != end) { + node_ptr node = begin; + begin = next_node(begin); + destruct_node(node); + } + } + + template + void hash_table_manager::delete_to_bucket_end(node_ptr begin) + { + while(BOOST_UNORDERED_BORLAND_BOOL(begin)) { + node_ptr node = begin; + begin = next_node(begin); + destruct_node(node); + } + } + + template + void hash_table_manager::clear_bucket(bucket_ptr b) + { + node_ptr node_it = b->next_; + b->next_ = node_ptr(); + + while(node_it) { + node_ptr node_to_destruct = node_it; + node_it = next_node(node_it); + destruct_node(node_to_destruct); + } + } + + template + void hash_table_manager::clear() + { + for(bucket_ptr begin = this->buckets_begin(), end = this->buckets_end(); begin != end; ++begin) { + clear_bucket(begin); + } + + this->cached_begin_bucket_ = this->buckets_end(); + this->size_ = 0; + } + + template + void hash_table_manager::delete_buckets() + { + clear(); + + // Destroy the buckets (including the sentinel bucket). + bucket_ptr end = this->buckets_end(); + ++end; + for(bucket_ptr begin = this->buckets_begin(); begin != end; ++begin) { + bucket_alloc().destroy(begin); + } + + bucket_alloc().deallocate(this->buckets_begin(), this->bucket_count() + 1); + + this->buckets_= bucket_ptr(); + } + + template + BOOST_DEDUCED_TYPENAME hash_table_manager::iterator_base + hash_table_manager::erase(iterator_base r) + { + BOOST_ASSERT(!r.is_end()); + iterator_base next = r; + next.increment(); + this->unlink_node(r.bucket_, r.node_); + destruct_node(r.node_); + // r has been invalidated but its bucket is still valid + this->recompute_begin_bucket(r.bucket_, next.bucket_); + return next; + } + + template + std::size_t hash_table_manager::erase_group(node_ptr* it, bucket_ptr bucket) + { + node_ptr pos = *it; + std::size_t count = this->unlink_group(it); + delete_group(pos); + + this->recompute_begin_bucket(bucket); + + return count; + } + + template + BOOST_DEDUCED_TYPENAME hash_table_manager::iterator_base + hash_table_manager::erase_range(iterator_base r1, iterator_base r2) + { + if(r1 != r2) + { + BOOST_ASSERT(!r1.is_end()); + + if (r1.bucket_ == r2.bucket_) { + this->unlink_nodes(r1.bucket_, r1.node_, r2.node_); + 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 { + BOOST_ASSERT(r1.bucket_ < r2.bucket_); + + this->unlink_nodes(r1.bucket_, r1.node_, node_ptr()); + delete_to_bucket_end(r1.node_); + + bucket_ptr i = r1.bucket_; + for(++i; i != r2.bucket_; ++i) { + this->size_ -= node_count(i->next_, node_ptr()); + clear_bucket(i); + } + + if(!r2.is_end()) { + node_ptr first = r2.bucket_->next_; + this->unlink_nodes(r2.bucket_, r2.node_); + delete_nodes(first, r2.node_); + } + + // r1 has been invalidated but its bucket is still + // valid. + this->recompute_begin_bucket(r1.bucket_, r2.bucket_); + } + } + + return r2; + } + +}} + +#endif diff --git a/include/boost/unordered/detail/move.hpp b/include/boost/unordered/detail/move.hpp index 1376f35b..317b20fd 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 /*************************************************************************************************/ diff --git a/include/boost/unordered/detail/node.hpp b/include/boost/unordered/detail/node.hpp new file mode 100644 index 00000000..0d12aa37 --- /dev/null +++ b/include/boost/unordered/detail/node.hpp @@ -0,0 +1,265 @@ + +// 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 { + + template + static inline BucketPtr& next_node(BucketPtr ptr) + { + return ptr->next_; + } + + template + static inline std::size_t node_count(BucketPtr ptr, BucketPtr end) + { + std::size_t count = 0; + while(ptr != end) { + ++count; + ptr = next_node(ptr); + } + return count; + } + + //////////////////////////////////////////////////////////////////////////// + // ungrouped node implementation + + template + inline BOOST_DEDUCED_TYPENAME ungrouped_node_base::node_ptr& + ungrouped_node_base::next_group(node_ptr ptr) + { + return next_node(ptr); + } + + 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) + { + next_node(n) = b.next_; + b.next_ = n; + } + + template + inline void ungrouped_node_base::add_group_to_bucket(node_ptr n, bucket& b) + { + next_node(n) = b.next_; + b.next_ = n; + } + + template + inline void ungrouped_node_base::add_after_node(node_ptr n, node_ptr position) + { + next_node(n) = next_node(position); + next_node(position) = position; + } + + template + void ungrouped_node_base::unlink_node(bucket& b, node_ptr node) + { + unlink_nodes(b, node, next_node(node)); + } + + template + void ungrouped_node_base::unlink_nodes(bucket& b, node_ptr begin, node_ptr end) + { + node_ptr* pos = &b.next_; + while(*pos != begin) pos = &next_node(*pos); + *pos = end; + } + + template + void ungrouped_node_base::unlink_nodes(bucket& b, node_ptr end) + { + b.next_ = end; + } + + template + inline void ungrouped_node_base::unlink_group(node_ptr* b) + { + *b = next_node(*b); + } + + //////////////////////////////////////////////////////////////////////////// + // grouped node implementation + + template + inline BOOST_DEDUCED_TYPENAME grouped_node_base::node_ptr& + grouped_node_base::group_prev(node_ptr ptr) + { + return get(ptr).group_prev_; + } + + template + inline BOOST_DEDUCED_TYPENAME grouped_node_base::node_ptr& + grouped_node_base::next_group(node_ptr ptr) + { + return next_node(group_prev(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 = group_prev(ptr); + } while(ptr != start); + return size; + } + + template + inline void grouped_node_base::add_to_bucket(node_ptr n, bucket& b) + { + next_node(n) = b.next_; + group_prev(n) = n; + b.next_ = n; + } + + template + inline void grouped_node_base::add_group_to_bucket(node_ptr n, bucket& b) + { + next_group(n) = b.next_; + b.next_ = n; + } + + template + inline void grouped_node_base::add_after_node(node_ptr n, node_ptr position) + { + next_node(n) = next_group(position); + group_prev(n) = group_prev(position); + next_group(position) = n; + group_prev(position) = 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) + { + // If split is at the beginning of the group then there's + // nothing to split. + if(next_node(group_prev(split)) != split) + return split; + + // Find the start of the group. + node_ptr start = split; + do { + start = group_prev(start); + } while(next_node(group_prev(start)) == start); + + node_ptr last = group_prev(start); + group_prev(start) = group_prev(split); + group_prev(split) = last; + + return start; + } + + template + void grouped_node_base::unlink_node(bucket& b, node_ptr node) + { + node_ptr next = next_node(node); + node_ptr* pos = &next_node(group_prev(node)); + + if(*pos != node) { + // The node is at the beginning of a group. + + // Find the previous node pointer: + pos = &b.next_; + while(*pos != node) pos = &next_group(*pos); + + // Remove from group + if(BOOST_UNORDERED_BORLAND_BOOL(next) && group_prev(next) == node) + group_prev(next) = group_prev(node); + } + else if(BOOST_UNORDERED_BORLAND_BOOL(next) && group_prev(next) == node) { + // The deleted node is not at the end of the group, so + // change the link from the next node. + group_prev(next) = group_prev(node); + } + 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 = group_prev(node); + while(group_prev(x) != node) { + x = group_prev(x); + } + group_prev(x) = group_prev(node); + } + *pos = next; + } + + template + void grouped_node_base::unlink_nodes(bucket& b, node_ptr begin, node_ptr end) + { + node_ptr* pos = &next_node(group_prev(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 = group_prev(group1); + node_ptr end2 = group_prev(group2); + group_prev(group1) = end2; + group_prev(group2) = end1; + } + } + } + *pos = end; + } + + template + void grouped_node_base::unlink_nodes(bucket& b, node_ptr end) + { + split_group(end); + b.next_ = end; + } + + template + inline void grouped_node_base::unlink_group(node_ptr* b) + { + *b = next_group(*b); + } +}} + +#endif diff --git a/include/boost/unordered/detail/structure.hpp b/include/boost/unordered/detail/structure.hpp new file mode 100644 index 00000000..d9b5c633 --- /dev/null +++ b/include/boost/unordered/detail/structure.hpp @@ -0,0 +1,220 @@ + +// 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_STRUCTURE_HPP_INCLUDED +#define BOOST_UNORDERED_DETAIL_STRUCTURE_HPP_INCLUDED + +#include + +namespace boost { namespace unordered_detail { + + //////////////////////////////////////////////////////////////////////////// + // hash_structure implementation + + template + void hash_structure::swap(hash_structure& other) + { + std::swap(buckets_, other.buckets_); + std::swap(cached_begin_bucket_, other.cached_begin_bucket_); + std::swap(size_, other.size_); + std::swap(bucket_count_, other.bucket_count_); + } + + template + std::size_t hash_structure::bucket_count() const + { + return bucket_count_; + } + + template + std::size_t hash_structure::bucket_from_hash(std::size_t hashed) const + { + return hashed % bucket_count_; + } + + template + BOOST_DEDUCED_TYPENAME hash_structure::bucket_ptr + hash_structure::bucket_ptr_from_hash(std::size_t hashed) const + { + return buckets_ + static_cast( + bucket_from_hash(hashed)); + } + + template + BOOST_DEDUCED_TYPENAME hash_structure::bucket_ptr + hash_structure::buckets_begin() const + { + return buckets_; + } + + template + BOOST_DEDUCED_TYPENAME hash_structure::bucket_ptr + hash_structure::buckets_end() const + { + return buckets_ + static_cast(bucket_count_); + } + + template + std::size_t hash_structure::bucket_size(std::size_t index) const + { + bucket_ptr ptr = (buckets_ + static_cast(index))->next_; + std::size_t count = 0; + while(ptr) { + ++count; + ptr = next_node(ptr); + } + return count; + } + + // Link a node + + template + void hash_structure::link_node(node_ptr n, node_ptr position) + { + node_base::add_after_node(n, position); + ++size_; + } + + template + void hash_structure::link_node_in_bucket(node_ptr n, bucket_ptr bucket) + { + node_base::add_to_bucket(n, *bucket); + ++size_; + if(bucket < cached_begin_bucket_) cached_begin_bucket_ = bucket; + } + + template + void hash_structure::unlink_node(bucket_ptr bucket, node_ptr pos) + { + --size_; + node_base::unlink_node(*bucket, pos); + } + + template + void hash_structure::unlink_nodes( + bucket_ptr bucket, node_ptr begin, node_ptr end) + { + size_ -= node_count(begin, end); + node_base::unlink_nodes(*bucket, begin, end); + } + + template + void hash_structure::unlink_nodes(bucket_ptr bucket, node_ptr end) + { + size_ -= node_count(bucket->next_, end); + node_base::unlink_nodes(*bucket, end); + } + + template + std::size_t hash_structure::unlink_group(node_ptr* pos) + { + std::size_t count = node_base::group_count(*pos); + size_ -= count; + node_base::unlink_group(pos); + return count; + } + + template + void hash_structure::link_group( + node_ptr n, bucket_ptr bucket, std::size_t count) + { + node_base::add_group_to_bucket(n, *bucket); + size_ += count; + if(bucket < cached_begin_bucket_) cached_begin_bucket_ = bucket; + } + + template + BOOST_DEDUCED_TYPENAME hash_structure::bucket_ptr + hash_structure::get_bucket(std::size_t n) const + { + return buckets_ + static_cast(n); + } + + template + BOOST_DEDUCED_TYPENAME hash_structure::node_ptr + hash_structure::bucket_begin(std::size_t n) const + { + return (buckets_ + static_cast(n))->next_; + } + + template + BOOST_DEDUCED_TYPENAME hash_structure::node_ptr + hash_structure::bucket_end(std::size_t) const + { + return node_ptr(); + } + + // 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 + + template + void hash_structure::recompute_begin_bucket(bucket_ptr b) + { + BOOST_ASSERT(!(b < cached_begin_bucket_)); + + if(b == cached_begin_bucket_) + { + if (size_ != 0) { + while (!cached_begin_bucket_->next_) + ++cached_begin_bucket_; + } else { + cached_begin_bucket_ = buckets_end(); + } + } + } + + // This is called when a range has been erased + // + // no throw + + template + void hash_structure::recompute_begin_bucket(bucket_ptr b1, bucket_ptr b2) + { + BOOST_ASSERT(!(b1 < cached_begin_bucket_) && !(b2 < b1)); + BOOST_ASSERT(BOOST_UNORDERED_BORLAND_BOOL(b2->next_)); + + if(b1 == cached_begin_bucket_ && !b1->next_) + cached_begin_bucket_ = b2; + } + + // no throw + template + inline float hash_structure::load_factor() const + { + BOOST_ASSERT(bucket_count_ != 0); + return static_cast(size_) + / static_cast(bucket_count_); + } + + //////////////////////////////////////////////////////////////////////////// + // hash_iterator_base implementation + + template + inline void hash_iterator_base::increment(node_ptr node) { + while(!node) { + ++bucket_; + node = bucket_->next_; + } + + node_ = node; + } + + template + inline void hash_iterator_base::increment() + { + increment(next_node(node_)); + } +}} + +#endif diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp new file mode 100644 index 00000000..7c9c61eb --- /dev/null +++ b/include/boost/unordered/detail/table.hpp @@ -0,0 +1,561 @@ + +// 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, extractor::extract(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 + 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 + 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 + std::size_t hash_table + ::bucket_index(key_type const& k) const + { + // hash_function can throw: + return this->bucket_from_hash(this->hash_function()(k)); + } + + + template + void hash_table + ::max_load_factor(float z) + { + BOOST_ASSERT(z > 0); + mlf_ = (std::max)(z, minimum_max_load_factor); + this->calculate_max_load(); + } + + // no throw + template + std::size_t hash_table + ::min_buckets_for_size(std::size_t n) 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 double_to_size_t(floor(n / (double) mlf_)) + 1; + } + + // no throw + template + void hash_table + ::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_ * this->bucket_count())); + } + + //////////////////////////////////////////////////////////////////////////// + // Constructors + + template + hash_table + ::hash_table(std::size_t n, hasher const& hf, key_equal const& eq, value_allocator const& a) : + manager(a), func_(false), mlf_(1.0f), max_load_(0) + { + std::uninitialized_fill((functions*)this->funcs_, (functions*)this->funcs_+2, + functions(hf, eq)); + this->create_buckets(next_prime(n)); + this->calculate_max_load(); + } + + template + hash_table + ::hash_table(hash_table const& x) : + manager(x), func_(false), mlf_(x.mlf_), max_load_(0) + { + std::uninitialized_fill((functions*)this->funcs_, (functions*)this->funcs_+2, + x.current()); + this->create_buckets(next_prime(x.min_buckets_for_size(x.size_))); + this->calculate_max_load(); + x.copy_buckets_to(*this); + } + + // Copy Construct with allocator + + template + hash_table + ::hash_table(hash_table const& x, value_allocator const& a) : + manager(a), func_(false), mlf_(x.mlf_), max_load_(0) + { + std::uninitialized_fill((functions*)this->funcs_, (functions*)this->funcs_+2, + x.current()); + this->create_buckets(next_prime(x.min_buckets_for_size(x.size_))); + this->calculate_max_load(); + x.copy_buckets_to(*this); + } + + // Move Construct + + template + hash_table + ::hash_table(hash_table& x, move_tag m) : + manager(x, m), func_(false), mlf_(x.mlf_), max_load_(0) + { + // TODO: Shouldn't I move the functions if poss. + std::uninitialized_fill((functions*)this->funcs_, (functions*)this->funcs_+2, + x.current()); + } + + template + hash_table + ::hash_table(hash_table& x, value_allocator const& a, move_tag m) : + manager(x, a, m), func_(false), mlf_(x.mlf_), max_load_(0) + { + std::uninitialized_fill((functions*)this->funcs_, (functions*)this->funcs_+2, + x.current()); + + this->calculate_max_load(); // no throw + + if(!this->buckets_) { + this->create_buckets(next_prime(x.min_buckets_for_size(x.size_))); + // This can throw, but hash_table_manager's destructor will clean + // up. + x.copy_buckets_to(*this); + } + } + + template + hash_table::~hash_table() + { + BOOST_UNORDERED_DESTRUCT(this->get_functions(false), functions); + BOOST_UNORDERED_DESTRUCT(this->get_functions(true), functions); + } + + template + hash_table& hash_table::operator=(hash_table const& x) + { + if(this != &x) { + this->clear(); // no throw + this->set_functions( + this->buffer_functions(x)); // throws, strong + this->mlf_ = x.mlf_; // no throw + this->calculate_max_load(); // no throw + this->reserve(x.size_); // throws + x.copy_buckets_to(*this); // throws + } + + 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 + void hash_table + ::swap(hash_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 = this->buffer_functions(x); + functions_ptr new_func_that = x.buffer_functions(*this); + + if(this->node_alloc() == x.node_alloc()) { + this->manager::swap(x); // No throw + } + else { + // Create new buckets in separate hash_table_manager objects + // which will clean up if anything throws an exception. + // (all can throw, but with no effect as these are new objects). + + manager new_this(*this); + new_this.create_buckets(x.min_buckets_for_size(x.size_)); + x.copy_buckets_to(new_this); + + manager new_that(x); + new_that.create_buckets(this->min_buckets_for_size(this->size_)); + copy_buckets_to(new_that); + + // Modifying the data, so no throw from now on. + + this->manager::swap(new_this); + x.manager::swap(new_that); + } + + // The rest is no throw. + + std::swap(this->mlf_, x.mlf_); + + this->set_functions(new_func_this); + x.set_functions(new_func_that); + + //TODO: Test that this works: + this->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. + + 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. + functions_ptr new_func_this = this->buffer_functions(x); + + if(this->node_alloc() == x.node_alloc()) { + this->manager::move(x); // 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). + + manager new_this(*this); + new_this.create_buckets(next_prime(x.min_buckets_for_size(x.size_))); + x.copy_buckets_to(new_this); + + // Start updating the data here, no throw from now on. + this->manager::move(new_this); + } + + // We've made it, the rest is no throw. + this->mlf_ = x.mlf_; + this->set_functions(new_func_this); + + this->calculate_max_load(); + } + + //////////////////////////////////////////////////////////////////////////// + // Reserve & Rehash + + // basic exception safety + template + bool hash_table + ::reserve(std::size_t n) + { + bool need_to_reserve = n >= this->max_load_; + // throws - basic: + if (need_to_reserve) rehash_impl(this->min_buckets_for_size(n)); + BOOST_ASSERT(n < this->max_load_ || n > max_size()); + return need_to_reserve; + } + + // basic exception safety + template + bool hash_table + ::reserve_for_insert(std::size_t n) + { + bool need_to_reserve = n >= this->max_load_; + // throws - basic: + if (need_to_reserve) { + std::size_t s = this->size_; + s = s + (s >> 1); + s = s > n ? s : n; + rehash_impl(this->min_buckets_for_size(s)); + } + BOOST_ASSERT(n < this->max_load_ || n > max_size()); + return need_to_reserve; + } + + // if hash function throws, basic exception safety + // strong otherwise. + template + void hash_table + ::rehash(std::size_t n) + { + using namespace std; + + // no throw: + std::size_t min_size = this->min_buckets_for_size(this->size_); + // basic/strong: + rehash_impl(min_size > n ? min_size : n); + + BOOST_ASSERT((float) this->bucket_count() > (float) this->size_ / this->mlf_ + && this->bucket_count() >= n); + } + + // if hash function throws, basic exception safety + // strong otherwise + + template + void hash_table + ::rehash_impl(std::size_t n) + { + n = next_prime(n); // no throw + + if (n == this->bucket_count()) // no throw + return; + + manager new_buckets(*this); // throws, seperate + new_buckets.create_buckets(n); // throws, seperate + move_buckets_to(new_buckets); // basic/no throw + new_buckets.swap(*this); // no throw + this->calculate_max_load(); // no throw + } + + //////////////////////////////////////////////////////////////////////////// + // move_buckets_to & copy_buckets_to + + // move_buckets_to + // + // if the hash function throws, basic excpetion safety + // no throw otherwise + + template + void hash_table + ::move_buckets_to(manager& dst) + { + BOOST_ASSERT(this->node_alloc() == dst.node_alloc()); + BOOST_ASSERT(this->buckets_ && dst.buckets_); + + hasher const& hf = this->hash_function(); + bucket_ptr end = this->buckets_end(); + + for(; this->cached_begin_bucket_ != end; ++this->cached_begin_bucket_) { + bucket_ptr src_bucket = this->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(extractor::extract(node::get_value(src_bucket->next_)))); + + node_ptr n = src_bucket->next_; + std::size_t count = this->unlink_group(&src_bucket->next_); + dst.link_group(n, dst_bucket, count); + } + } + } + + // copy_buckets_to + // + // basic excpetion safety. If an exception is thrown this will + // leave dst partially filled. + + template + void hash_table + ::copy_buckets_to(manager& dst) const + { + BOOST_ASSERT(this->buckets_ && dst.buckets_); + + hasher const& hf = this->hash_function(); + bucket_ptr end = this->buckets_end(); + + hash_node_constructor a(dst); + + // 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(extractor::extract(node::get_value(it)))); + // throws, strong + + node_ptr group_end = node::next_group(it); + + a.construct(node::get_value(it)); + node_ptr n = a.release(); + dst.link_node_in_bucket(n, dst_bucket); + + for(it = next_node(it); it != group_end; it = next_node(it)) { + a.construct(node::get_value(it)); + dst.link_node(a.release(), n); + } + } + } + } + + //////////////////////////////////////////////////////////////////////////// + // Misc. key methods + + // strong exception safety + + template + std::size_t hash_table + ::erase_key(key_type const& k) + { + // No side effects in initial section + bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); + node_ptr* it = find_for_erase(bucket, k); + + // No throw. + return *it ? this->erase_group(it, bucket) : 0; + } + + // 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 + std::pair< + BOOST_DEDUCED_TYPENAME hash_table::iterator_base, + BOOST_DEDUCED_TYPENAME hash_table::iterator_base + > + hash_table + ::equal_range(key_type const& k) const + { + if(!this->size_) + return std::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(node::next_group(second.node_)); + return std::pair(first, second); + } + else { + return std::pair(this->end(), this->end()); + } + } +}} + +#endif diff --git a/include/boost/unordered/detail/util.hpp b/include/boost/unordered/detail/util.hpp new file mode 100644 index 00000000..5b0778ee --- /dev/null +++ b/include/boost/unordered/detail/util.hpp @@ -0,0 +1,333 @@ + +// 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 + +#if !defined(BOOST_UNORDERED_STD_FORWARD) + +#include +#include +#include + +#define BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + BOOST_PP_ENUM_PARAMS_Z(z, n, class 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 + +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 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; + } + + //////////////////////////////////////////////////////////////////////////// + // 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 n = boost::unordered_detail::default_initial_bucket_count) + { + return (std::max)(static_cast(insert_size(i, j)) + 1, n); + } + + //////////////////////////////////////////////////////////////////////////// + // 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, n, _) \ + template < \ + class T, \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + inline void construct_impl( \ + T*, void* address, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + new(address) T( \ + BOOST_UNORDERED_CALL_PARAMS(z, n)); \ + } \ + \ + template \ + inline void construct_impl( \ + std::pair*, void* address, \ + Key const& k, BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + new(address) std::pair(k, \ + Second(BOOST_UNORDERED_CALL_PARAMS(z, n))); \ + } + + 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_table_manager manager; + typedef BOOST_DEDUCED_TYPENAME manager::node node; + typedef BOOST_DEDUCED_TYPENAME manager::real_node_ptr real_node_ptr; + typedef BOOST_DEDUCED_TYPENAME manager::value_type value_type; + + manager& manager_; + real_node_ptr node_; + bool node_constructed_; + bool value_constructed_; + + public: + + hash_node_constructor(manager& m) : + manager_(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, n, _) \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + void construct( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + construct_preamble(); \ + construct_impl( \ + (value_type*) 0, node_->address(), \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + ); \ + 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; + } + + real_node_ptr get() const + { + BOOST_ASSERT(node_); + return node_; + } + + // no throw + BOOST_DEDUCED_TYPENAME manager::node_ptr release() + { + real_node_ptr p = node_; + node_ = real_node_ptr(); + // node_ptr cast + return manager_.bucket_alloc().address(*p); + } + + private: + hash_node_constructor(hash_node_constructor const&); + hash_node_constructor& operator=(hash_node_constructor const&); + }; + + // hash_node_constructor + + template + hash_node_constructor::~hash_node_constructor() + { + if (node_) { + if (value_constructed_) { + BOOST_UNORDERED_DESTRUCT(&node_->value(), value_type); + } + + if (node_constructed_) + manager_.node_alloc().destroy(node_); + + manager_.node_alloc().deallocate(node_, 1); + } + } + + template + void hash_node_constructor::construct_preamble() + { + if(!node_) { + node_constructed_ = false; + value_constructed_ = false; + + node_ = manager_.node_alloc().allocate(1); + manager_.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; + } + } +}} + +#endif diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index b0658bad..a37bc553 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -15,7 +15,8 @@ #include #include -#include +#include +#include #if !defined(BOOST_HAS_RVALUE_REFS) #include @@ -39,38 +40,59 @@ 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; +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) + private: +#endif - 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; + typedef BOOST_DEDUCED_TYPENAME + boost::unordered_detail::rebind_wrap::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 BOOST_DEDUCED_TYPENAME std::size_t size_type; + typedef BOOST_DEDUCED_TYPENAME 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); + } + + public: // construct/destroy/copy @@ -79,26 +101,26 @@ namespace boost const hasher &hf = hasher(), const key_equal &eql = key_equal(), const allocator_type &a = allocator_type()) - : base(n, hf, eql, a) + : table_(n, hf, eql, a) { } explicit unordered_map(allocator_type const& a) - : base(boost::unordered_detail::default_initial_bucket_count, + : table_(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) + : table_(other.table_, a) { } template unordered_map(InputIterator f, InputIterator l) - : base(f, l, boost::unordered_detail::default_initial_bucket_count, - hasher(), key_equal(), allocator_type()) + : table_(boost::unordered_detail::initial_size(f, l), hasher(), key_equal(), allocator_type()) { + table_.insert_range(f, l); } template @@ -106,8 +128,9 @@ namespace boost size_type n, const hasher &hf = hasher(), const key_equal &eql = key_equal()) - : base(f, l, n, hf, eql, allocator_type()) + : table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, allocator_type()) { + table_.insert_range(f, l); } template @@ -116,38 +139,39 @@ namespace boost const hasher &hf, const key_equal &eql, const allocator_type &a) - : base(f, l, n, hf, eql, 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) - : base(other.base, boost::unordered_detail::move_tag()) + : table_(other.table_, boost::unordered_detail::move_tag()) { } unordered_map(unordered_map&& other, allocator_type const& a) - : base(other.base, a, boost::unordered_detail::move_tag()) + : table_(other.table_, a, boost::unordered_detail::move_tag()) { } unordered_map& operator=(unordered_map&& x) { - base.move(x.base); + table_.move(x.table_); return *this; } #else unordered_map(boost::unordered_detail::move_from > other) - : base(other.source.base, boost::unordered_detail::move_tag()) + : table_(other.source.table_, boost::unordered_detail::move_tag()) { } #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) unordered_map& operator=(unordered_map x) { - base.move(x.base); + table_.move(x.table_); return *this; } #endif @@ -159,80 +183,71 @@ namespace boost 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) + : 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) { - base.data_.clear(); - base.insert_range(list.begin(), list.end()); + table_.clear(); + table_.insert_range(list.begin(), list.end()); return *this; } #endif - private: - - BOOST_DEDUCED_TYPENAME implementation::iterator_base const& - get(const_iterator const& it) - { - return boost::unordered_detail::iterator_access::get(it); - } - - public: - 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,25 +257,25 @@ 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) { - return iterator(base.emplace_hint(get(hint), std::forward(args)...)); + return iterator(table_.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)); + table_.emplace(v)); } 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, _) \ @@ -272,7 +287,7 @@ namespace boost ) \ { \ return boost::unordered_detail::pair_cast( \ - base.emplace( \ + table_.emplace( \ BOOST_UNORDERED_CALL_PARAMS(z, n) \ )); \ } \ @@ -284,7 +299,7 @@ namespace boost BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ ) \ { \ - return iterator(base.emplace_hint(get(hint), \ + return iterator(table_.emplace_hint(get(hint), \ BOOST_UNORDERED_CALL_PARAMS(z, n) \ )); \ } @@ -299,175 +314,175 @@ 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_hint(get(hint), obj)); } template void insert(InputIterator first, InputIterator 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)); + table_.equal_range(k)); } std::pair equal_range(const key_type& k) const { return boost::unordered_detail::pair_cast( - base.equal_range(k)); + 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) { - return local_iterator(base.data_.end(n)); + return local_iterator(table_.bucket_end(n)); } const_local_iterator end(size_type n) const { - return const_local_iterator(base.data_.end(n)); + return const_local_iterator(table_.bucket_end(n)); } 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 { - return const_local_iterator(base.data_.end(n)); + return const_local_iterator(table_.bucket_end(n)); } // 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) @@ -483,14 +498,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,38 +518,58 @@ 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; +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) + private: +#endif + typedef BOOST_DEDUCED_TYPENAME + boost::unordered_detail::rebind_wrap::type + value_allocator; - 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; + 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 BOOST_DEDUCED_TYPENAME std::size_t size_type; + typedef BOOST_DEDUCED_TYPENAME 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); + } + + public: // construct/destroy/copy @@ -543,26 +578,26 @@ namespace boost const hasher &hf = hasher(), const key_equal &eql = key_equal(), const allocator_type &a = allocator_type()) - : base(n, hf, eql, a) + : table_(n, hf, eql, a) { } explicit unordered_multimap(allocator_type const& a) - : base(boost::unordered_detail::default_initial_bucket_count, + : table_(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) + : table_(other.table_, a) { } template unordered_multimap(InputIterator f, InputIterator l) - : base(f, l, boost::unordered_detail::default_initial_bucket_count, - hasher(), key_equal(), allocator_type()) + : table_(boost::unordered_detail::initial_size(f, l), hasher(), key_equal(), allocator_type()) { + table_.insert_range(f, l); } template @@ -570,8 +605,9 @@ namespace boost size_type n, const hasher &hf = hasher(), const key_equal &eql = key_equal()) - : base(f, l, n, hf, eql, allocator_type()) + : table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, allocator_type()) { + table_.insert_range(f, l); } template @@ -580,38 +616,39 @@ namespace boost const hasher &hf, const key_equal &eql, const allocator_type &a) - : base(f, l, n, hf, eql, 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) - : base(other.base, boost::unordered_detail::move_tag()) + : table_(other.table_, boost::unordered_detail::move_tag()) { } unordered_multimap(unordered_multimap&& other, allocator_type const& a) - : base(other.base, a, boost::unordered_detail::move_tag()) + : table_(other.table_, a, boost::unordered_detail::move_tag()) { } unordered_multimap& operator=(unordered_multimap&& x) { - base.move(x.base); + table_.move(x.table_); return *this; } #else unordered_multimap(boost::unordered_detail::move_from > other) - : base(other.source.base, boost::unordered_detail::move_tag()) + : table_(other.source.table_, boost::unordered_detail::move_tag()) { } #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) unordered_multimap& operator=(unordered_multimap x) { - base.move(x.base); + table_.move(x.table_); return *this; } #endif @@ -623,81 +660,71 @@ namespace boost 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) + : 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) { - base.data_.clear(); - base.insert_range(list.begin(), list.end()); + table_.clear(); + table_.insert_range(list.begin(), list.end()); return *this; } #endif - - private: - - BOOST_DEDUCED_TYPENAME implementation::iterator_base const& - get(const_iterator const& it) - { - return boost::unordered_detail::iterator_access::get(it); - } - - public: - 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,24 +733,24 @@ 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()) { - return iterator(base.emplace_hint(get(hint), v)); + return iterator(table_.emplace_hint(get(hint), v)); } @@ -736,7 +763,7 @@ namespace boost ) \ { \ return iterator( \ - base.emplace( \ + table_.emplace( \ BOOST_UNORDERED_CALL_PARAMS(z, n) \ )); \ } \ @@ -748,7 +775,7 @@ namespace boost BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ ) \ { \ - return iterator(base.emplace_hint(get(hint), \ + return iterator(table_.emplace_hint(get(hint), \ BOOST_UNORDERED_CALL_PARAMS(z, n) \ )); \ } @@ -762,160 +789,160 @@ 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) { - 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)); + table_.equal_range(k)); } std::pair equal_range(const key_type& k) const { return boost::unordered_detail::pair_cast( - base.equal_range(k)); + 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) { - return local_iterator(base.data_.end(n)); + return local_iterator(table_.bucket_end(n)); } const_local_iterator end(size_type n) const { - return const_local_iterator(base.data_.end(n)); + return const_local_iterator(table_.bucket_end(n)); } 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 { - return const_local_iterator(base.data_.end(n)); + return const_local_iterator(table_.bucket_end(n)); } // 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) @@ -931,14 +958,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..f63ad587 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -15,7 +15,8 @@ #include #include -#include +#include +#include #if !defined(BOOST_HAS_RVALUE_REFS) #include @@ -39,37 +40,56 @@ 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; +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) + private: +#endif - 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; + typedef BOOST_DEDUCED_TYPENAME + boost::unordered_detail::rebind_wrap::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 BOOST_DEDUCED_TYPENAME std::size_t size_type; + typedef BOOST_DEDUCED_TYPENAME 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); + } + + public: // construct/destroy/copy @@ -78,34 +98,35 @@ namespace boost const hasher &hf = hasher(), const key_equal &eql = key_equal(), const allocator_type &a = allocator_type()) - : base(n, hf, eql, a) + : table_(n, hf, eql, a) { } explicit unordered_set(allocator_type const& a) - : base(boost::unordered_detail::default_initial_bucket_count, + : table_(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) + : table_(other.table_, a) { } template unordered_set(InputIterator f, InputIterator l) - : base(f, l, boost::unordered_detail::default_initial_bucket_count, - hasher(), key_equal(), allocator_type()) + : table_(boost::unordered_detail::initial_size(f, l), hasher(), key_equal(), allocator_type()) { + table_.insert_range(f, l); } 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()) + : table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, allocator_type()) { + table_.insert_range(f, l); } template @@ -113,38 +134,39 @@ namespace boost const hasher &hf, const key_equal &eql, const allocator_type &a) - : base(f, l, n, hf, eql, 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) - : base(other.base, boost::unordered_detail::move_tag()) + : table_(other.table_, boost::unordered_detail::move_tag()) { } unordered_set(unordered_set&& other, allocator_type const& a) - : base(other.base, a, boost::unordered_detail::move_tag()) + : table_(other.table_, a, boost::unordered_detail::move_tag()) { } unordered_set& operator=(unordered_set&& x) { - base.move(x.base); + table_.move(x.table_); return *this; } #else unordered_set(boost::unordered_detail::move_from > other) - : base(other.source.base, boost::unordered_detail::move_tag()) + : table_(other.source.table_, boost::unordered_detail::move_tag()) { } #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) unordered_set& operator=(unordered_set x) { - base.move(x.base); + table_.move(x.table_); return *this; } #endif @@ -156,80 +178,71 @@ namespace boost 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) + : 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) { - base.data_.clear(); - base.insert_range(list.begin(), list.end()); + table_.clear(); + table_.insert_range(list.begin(), list.end()); return *this; } #endif - private: - - BOOST_DEDUCED_TYPENAME implementation::iterator_base const& - get(const_iterator const& it) - { - return boost::unordered_detail::iterator_access::get(it); - } - - public: - 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,26 +252,26 @@ 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) { return iterator( - base.emplace_hint(get(hint), std::forward(args)...)); + table_.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)); + table_.emplace(v)); } 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, _) \ @@ -270,7 +283,7 @@ namespace boost ) \ { \ return boost::unordered_detail::pair_cast( \ - base.emplace( \ + table_.emplace( \ BOOST_UNORDERED_CALL_PARAMS(z, n) \ )); \ } \ @@ -282,7 +295,7 @@ namespace boost BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ ) \ { \ - return iterator(base.emplace_hint(get(hint), \ + return iterator(table_.emplace_hint(get(hint), \ BOOST_UNORDERED_CALL_PARAMS(z, n) \ )); \ } @@ -297,148 +310,148 @@ 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_hint(get(hint), obj)); } template void insert(InputIterator first, InputIterator 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)); + 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) { - return local_iterator(base.data_.end(n)); + return local_iterator(table_.bucket_end(n)); } const_local_iterator end(size_type n) const { - return const_local_iterator(base.data_.end(n)); + return const_local_iterator(table_.bucket_end(n)); } 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 { - return const_local_iterator(base.data_.end(n)); + return const_local_iterator(table_.bucket_end(n)); } // 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) @@ -454,14 +467,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,37 +487,55 @@ 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; +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) + private: +#endif + typedef BOOST_DEDUCED_TYPENAME + boost::unordered_detail::rebind_wrap::type + value_allocator; - 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; + 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 BOOST_DEDUCED_TYPENAME std::size_t size_type; + typedef BOOST_DEDUCED_TYPENAME 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); + } + + public: // construct/destroy/copy @@ -513,34 +544,35 @@ namespace boost const hasher &hf = hasher(), const key_equal &eql = key_equal(), const allocator_type &a = allocator_type()) - : base(n, hf, eql, a) + : table_(n, hf, eql, a) { } explicit unordered_multiset(allocator_type const& a) - : base(boost::unordered_detail::default_initial_bucket_count, + : table_(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) + : table_(other.table_, a) { } template unordered_multiset(InputIterator f, InputIterator l) - : base(f, l, boost::unordered_detail::default_initial_bucket_count, - hasher(), key_equal(), allocator_type()) + : table_(boost::unordered_detail::initial_size(f, l), hasher(), key_equal(), allocator_type()) { + table_.insert_range(f, l); } 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()) + : table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, allocator_type()) { + table_.insert_range(f, l); } template @@ -548,38 +580,39 @@ namespace boost const hasher &hf, const key_equal &eql, const allocator_type &a) - : base(f, l, n, hf, eql, 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) - : base(other.base, boost::unordered_detail::move_tag()) + : table_(other.table_, boost::unordered_detail::move_tag()) { } unordered_multiset(unordered_multiset&& other, allocator_type const& a) - : base(other.base, a, boost::unordered_detail::move_tag()) + : table_(other.table_, a, boost::unordered_detail::move_tag()) { } unordered_multiset& operator=(unordered_multiset&& x) { - base.move(x.base); + table_.move(x.table_); return *this; } #else unordered_multiset(boost::unordered_detail::move_from > other) - : base(other.source.base, boost::unordered_detail::move_tag()) + : table_(other.source.table_, boost::unordered_detail::move_tag()) { } #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) unordered_multiset& operator=(unordered_multiset x) { - base.move(x.base); + table_.move(x.table_); return *this; } #endif @@ -591,80 +624,71 @@ namespace boost 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) + : 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) { - base.data_.clear(); - base.insert_range(list.begin(), list.end()); + table_.clear(); + table_.insert_range(list.begin(), list.end()); return *this; } #endif - private: - - BOOST_DEDUCED_TYPENAME implementation::iterator_base const& - get(const_iterator const& it) - { - return boost::unordered_detail::iterator_access::get(it); - } - - public: - 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,24 +697,24 @@ 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()) { - return iterator(base.emplace_hint(get(hint), v)); + return iterator(table_.emplace_hint(get(hint), v)); } #define BOOST_UNORDERED_EMPLACE(z, n, _) \ @@ -702,9 +726,7 @@ namespace boost ) \ { \ return iterator( \ - base.emplace( \ - BOOST_UNORDERED_CALL_PARAMS(z, n) \ - )); \ + table_.emplace(BOOST_UNORDERED_CALL_PARAMS(z, n))); \ } \ \ template < \ @@ -714,7 +736,7 @@ namespace boost BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ ) \ { \ - return iterator(base.emplace_hint(get(hint), \ + return iterator(table_.emplace_hint(get(hint), \ BOOST_UNORDERED_CALL_PARAMS(z, n) \ )); \ } @@ -728,148 +750,148 @@ 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) { - 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)); + 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) { - return local_iterator(base.data_.end(n)); + return local_iterator(table_.bucket_end(n)); } const_local_iterator end(size_type n) const { - return const_local_iterator(base.data_.end(n)); + return const_local_iterator(table_.bucket_end(n)); } 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 { - return const_local_iterator(base.data_.end(n)); + return const_local_iterator(table_.bucket_end(n)); } // 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) @@ -885,14 +907,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/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/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 c40cb50fe56087c211a488b7ede03720500061ff Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 31 Aug 2009 10:39:25 +0000 Subject: [PATCH 094/471] Detab. [SVN r55901] --- include/boost/unordered/detail/insert.hpp | 34 +++++++++++----------- include/boost/unordered/detail/manager.hpp | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/include/boost/unordered/detail/insert.hpp b/include/boost/unordered/detail/insert.hpp index 26520015..74702429 100644 --- a/include/boost/unordered/detail/insert.hpp +++ b/include/boost/unordered/detail/insert.hpp @@ -67,13 +67,13 @@ namespace boost { namespace unordered_detail { static bool group_equals(node_ptr it1, node_ptr it2, set_extractor*); static bool group_equals(node_ptr it1, node_ptr it2, map_extractor*); - inline node_ptr add_node(node_constructor& a, bucket_ptr bucket) - { - node_ptr n = a.release(); - this->link_node_in_bucket(n, bucket); - return n; - } - + inline node_ptr add_node(node_constructor& a, bucket_ptr bucket) + { + node_ptr n = a.release(); + this->link_node_in_bucket(n, bucket); + return n; + } + #if defined(BOOST_UNORDERED_STD_FORWARD) // Emplace (unique keys) @@ -325,15 +325,15 @@ namespace boost { namespace unordered_detail { static bool group_equals(node_ptr it1, node_ptr it2, set_extractor*); static bool group_equals(node_ptr it1, node_ptr it2, map_extractor*); - inline node_ptr add_node(node_constructor& a, bucket_ptr bucket, node_ptr pos) - { - node_ptr n = a.release(); - if(BOOST_UNORDERED_BORLAND_BOOL(pos)) - this->link_node(n, pos); - else - this->link_node_in_bucket(n, bucket); - return n; - } + inline node_ptr add_node(node_constructor& a, bucket_ptr bucket, node_ptr pos) + { + node_ptr n = a.release(); + if(BOOST_UNORDERED_BORLAND_BOOL(pos)) + this->link_node(n, pos); + else + this->link_node_in_bucket(n, bucket); + return n; + } public: @@ -585,7 +585,7 @@ namespace boost { namespace unordered_detail { { key_type const& k = extractor::extract(a.get()->value()); bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); - add_node(a, bucket, find_iterator(bucket, k)); + add_node(a, bucket, find_iterator(bucket, k)); } //////////////////////////////////////////////////////////////////////////// diff --git a/include/boost/unordered/detail/manager.hpp b/include/boost/unordered/detail/manager.hpp index 0da4c674..36775f75 100644 --- a/include/boost/unordered/detail/manager.hpp +++ b/include/boost/unordered/detail/manager.hpp @@ -120,7 +120,7 @@ namespace boost { namespace unordered_detail { void hash_table_manager::destruct_node(node_ptr b) { node* raw_ptr = static_cast(&*b); - BOOST_UNORDERED_DESTRUCT(&raw_ptr->value(), value_type); + BOOST_UNORDERED_DESTRUCT(&raw_ptr->value(), value_type); real_node_ptr n(node_alloc().address(*raw_ptr)); node_alloc().destroy(n); node_alloc().deallocate(n, 1); From ccc88ecf0a5de5c42e411fe9a08d2ad626b9b4b4 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 31 Aug 2009 10:39:40 +0000 Subject: [PATCH 095/471] Remove unnecessary BOOST_DEDUCED_TYPENAMEs [SVN r55902] --- include/boost/unordered/unordered_map.hpp | 8 ++++---- include/boost/unordered/unordered_set.hpp | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index a37bc553..5eb0eae5 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -68,8 +68,8 @@ namespace boost typedef BOOST_DEDUCED_TYPENAME value_allocator::reference reference; typedef BOOST_DEDUCED_TYPENAME value_allocator::const_reference const_reference; - typedef BOOST_DEDUCED_TYPENAME std::size_t size_type; - typedef BOOST_DEDUCED_TYPENAME std::ptrdiff_t difference_type; + 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; @@ -545,8 +545,8 @@ namespace boost typedef BOOST_DEDUCED_TYPENAME value_allocator::reference reference; typedef BOOST_DEDUCED_TYPENAME value_allocator::const_reference const_reference; - typedef BOOST_DEDUCED_TYPENAME std::size_t size_type; - typedef BOOST_DEDUCED_TYPENAME std::ptrdiff_t difference_type; + 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; diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index f63ad587..942f3516 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -67,8 +67,8 @@ namespace boost typedef BOOST_DEDUCED_TYPENAME value_allocator::reference reference; typedef BOOST_DEDUCED_TYPENAME value_allocator::const_reference const_reference; - typedef BOOST_DEDUCED_TYPENAME std::size_t size_type; - typedef BOOST_DEDUCED_TYPENAME std::ptrdiff_t difference_type; + 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; @@ -513,8 +513,8 @@ namespace boost typedef BOOST_DEDUCED_TYPENAME value_allocator::reference reference; typedef BOOST_DEDUCED_TYPENAME value_allocator::const_reference const_reference; - typedef BOOST_DEDUCED_TYPENAME std::size_t size_type; - typedef BOOST_DEDUCED_TYPENAME std::ptrdiff_t difference_type; + 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; From 848b73f99f7192131f3288b1affb160c7c1b9991 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 31 Aug 2009 15:33:28 +0000 Subject: [PATCH 096/471] Remove a few unused parameters. [SVN r55921] --- include/boost/unordered/detail/insert.hpp | 2 +- include/boost/unordered/detail/manager.hpp | 4 ++-- test/unordered/Jamfile.v2 | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/boost/unordered/detail/insert.hpp b/include/boost/unordered/detail/insert.hpp index 74702429..211df518 100644 --- a/include/boost/unordered/detail/insert.hpp +++ b/include/boost/unordered/detail/insert.hpp @@ -635,7 +635,7 @@ namespace boost { namespace unordered_detail { template inline bool hash_unique_table - ::group_equals(node_ptr it1, node_ptr it2, set_extractor*) + ::group_equals(node_ptr, node_ptr, set_extractor*) { return true; } diff --git a/include/boost/unordered/detail/manager.hpp b/include/boost/unordered/detail/manager.hpp index 36775f75..ae69bf1f 100644 --- a/include/boost/unordered/detail/manager.hpp +++ b/include/boost/unordered/detail/manager.hpp @@ -41,7 +41,7 @@ namespace boost { namespace unordered_detail { : structure(), allocators_(h.allocators_) {} template - hash_table_manager::hash_table_manager(hash_table_manager& x, move_tag m) + hash_table_manager::hash_table_manager(hash_table_manager& x, move_tag) : structure(), allocators_(x.allocators_) { this->buckets_ = x.buckets_; @@ -55,7 +55,7 @@ namespace boost { namespace unordered_detail { } template - hash_table_manager::hash_table_manager(hash_table_manager& x, value_allocator const& a, move_tag m) : + hash_table_manager::hash_table_manager(hash_table_manager& x, value_allocator const& a, move_tag) : structure(), allocators_(a,a) { if(this->node_alloc() == x.node_alloc()) { 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 From 1743ed118dc5bcc8ebf4de6d43d144a3bec8ca9c Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 31 Aug 2009 15:33:49 +0000 Subject: [PATCH 097/471] Remove 'static' from next_node and node_count. Will hopefully make vacpp happy. [SVN r55922] --- include/boost/unordered/detail/node.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/node.hpp b/include/boost/unordered/detail/node.hpp index 0d12aa37..d6e95a49 100644 --- a/include/boost/unordered/detail/node.hpp +++ b/include/boost/unordered/detail/node.hpp @@ -25,13 +25,13 @@ namespace boost { namespace unordered_detail { template - static inline BucketPtr& next_node(BucketPtr ptr) + inline BucketPtr& next_node(BucketPtr ptr) { return ptr->next_; } template - static inline std::size_t node_count(BucketPtr ptr, BucketPtr end) + inline std::size_t node_count(BucketPtr ptr, BucketPtr end) { std::size_t count = 0; while(ptr != end) { From 7fe53ef5a32051a3779ea7b098970e8f03b82d11 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 3 Sep 2009 07:36:21 +0000 Subject: [PATCH 098/471] Combine hash_structure and hash_table_manager. [SVN r55990] --- include/boost/unordered/detail/fwd.hpp | 121 ++++------ include/boost/unordered/detail/insert.hpp | 16 +- include/boost/unordered/detail/manager.hpp | 190 ++++++++++++++-- include/boost/unordered/detail/node.hpp | 6 +- include/boost/unordered/detail/structure.hpp | 220 ------------------- include/boost/unordered/detail/table.hpp | 19 +- 6 files changed, 241 insertions(+), 331 deletions(-) delete mode 100644 include/boost/unordered/detail/structure.hpp diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index a4ffdb7c..2d18775a 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -152,76 +152,13 @@ namespace boost { namespace unordered_detail { template class hash_node : public NodeBase, public value_base { + public: typedef ValueType value_type; typedef BOOST_DEDUCED_TYPENAME NodeBase::node_ptr node_ptr; - public: + static value_type& get_value(node_ptr p) { return static_cast(*p).value(); } }; - template - struct hash_structure - { - typedef BOOST_DEDUCED_TYPENAME - G::BOOST_NESTED_TEMPLATE base::type - node_base; - typedef BOOST_DEDUCED_TYPENAME node_base::bucket_allocator bucket_allocator; - typedef BOOST_DEDUCED_TYPENAME node_base::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME node_base::node_ptr node_ptr; - - // The actual data structure - - bucket_ptr buckets_; - bucket_ptr cached_begin_bucket_; - std::size_t size_; - std::size_t bucket_count_; - - // Constructor - - hash_structure() : buckets_(), cached_begin_bucket_(), size_() {} - - void swap(hash_structure& other); - - // Buckets - - std::size_t bucket_count() const; - std::size_t bucket_from_hash(std::size_t hashed) const; - bucket_ptr bucket_ptr_from_hash(std::size_t hashed) const; - bucket_ptr buckets_begin() const; - bucket_ptr buckets_end() const; - std::size_t bucket_size(std::size_t index) const; - - // Link a node - - void link_node(node_ptr n, node_ptr position); - void link_node_in_bucket(node_ptr n, bucket_ptr bucket); - void unlink_node(bucket_ptr bucket, node_ptr pos); - void unlink_nodes(bucket_ptr bucket, node_ptr begin, node_ptr end); - void unlink_nodes(bucket_ptr bucket, node_ptr end); - std::size_t unlink_group(node_ptr* pos); - void link_group(node_ptr n, bucket_ptr bucket, std::size_t count); - bucket_ptr get_bucket(std::size_t n) const; - node_ptr bucket_begin(std::size_t n) const; - node_ptr bucket_end(std::size_t) const; - - // 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); - - // 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 template @@ -256,22 +193,22 @@ namespace boost { namespace unordered_detail { // methods (other than getters and setters). template - struct hash_table_manager : - hash_structure + struct hash_table_manager { // Types - typedef hash_bucket bucket; - typedef hash_structure structure; - typedef BOOST_DEDUCED_TYPENAME structure::bucket_allocator bucket_allocator; - typedef BOOST_DEDUCED_TYPENAME structure::node_base node_base; - typedef BOOST_DEDUCED_TYPENAME structure::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME structure::node_ptr node_ptr; - typedef A value_allocator; typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; + typedef hash_bucket bucket; + typedef BOOST_DEDUCED_TYPENAME G::BOOST_NESTED_TEMPLATE base::type + node_base; typedef hash_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; @@ -279,6 +216,10 @@ namespace boost { namespace unordered_detail { // Members + bucket_ptr buckets_; + bucket_ptr cached_begin_bucket_; + std::size_t size_; + std::size_t bucket_count_; boost::compressed_pair allocators_; // Data access @@ -306,11 +247,21 @@ namespace boost { namespace unordered_detail { ~hash_table_manager(); // no throw + void swap(hash_table_manager& other); void move(hash_table_manager& other); - // Methods - + // Buckets + void create_buckets(std::size_t bucket_count); + std::size_t bucket_count() const; + std::size_t bucket_from_hash(std::size_t hashed) const; + bucket_ptr bucket_ptr_from_hash(std::size_t hashed) const; + bucket_ptr buckets_begin() const; + bucket_ptr buckets_end() const; + std::size_t bucket_size(std::size_t index) const; + bucket_ptr get_bucket(std::size_t n) const; + node_ptr bucket_begin(std::size_t n) const; + node_ptr bucket_end(std::size_t) const; // Alloc/Dealloc @@ -331,6 +282,24 @@ namespace boost { namespace unordered_detail { 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 + // + // 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; }; template diff --git a/include/boost/unordered/detail/insert.hpp b/include/boost/unordered/detail/insert.hpp index 211df518..28c27eb4 100644 --- a/include/boost/unordered/detail/insert.hpp +++ b/include/boost/unordered/detail/insert.hpp @@ -70,7 +70,9 @@ namespace boost { namespace unordered_detail { inline node_ptr add_node(node_constructor& a, bucket_ptr bucket) { node_ptr n = a.release(); - this->link_node_in_bucket(n, bucket); + node::add_to_bucket(n, *bucket); + ++this->size_; + if(bucket < this->cached_begin_bucket_) this->cached_begin_bucket_ = bucket; return n; } @@ -328,10 +330,14 @@ namespace boost { namespace unordered_detail { inline node_ptr add_node(node_constructor& a, bucket_ptr bucket, node_ptr pos) { node_ptr n = a.release(); - if(BOOST_UNORDERED_BORLAND_BOOL(pos)) - this->link_node(n, pos); - else - this->link_node_in_bucket(n, bucket); + 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; } diff --git a/include/boost/unordered/detail/manager.hpp b/include/boost/unordered/detail/manager.hpp index ae69bf1f..5b9d7383 100644 --- a/include/boost/unordered/detail/manager.hpp +++ b/include/boost/unordered/detail/manager.hpp @@ -9,7 +9,7 @@ #include #include -#include +#include namespace boost { namespace unordered_detail { @@ -30,19 +30,19 @@ namespace boost { namespace unordered_detail { template hash_table_manager::hash_table_manager() - : structure(), allocators_() {} + : buckets_(), cached_begin_bucket_(), size_(), allocators_() {} template hash_table_manager::hash_table_manager(value_allocator const& a) - : structure(), allocators_(a,a) {} + : buckets_(), cached_begin_bucket_(), size_(), allocators_(a,a) {} template hash_table_manager::hash_table_manager(hash_table_manager const& h) - : structure(), allocators_(h.allocators_) {} + : buckets_(), cached_begin_bucket_(), size_(), allocators_(h.allocators_) {} template hash_table_manager::hash_table_manager(hash_table_manager& x, move_tag) - : structure(), allocators_(x.allocators_) + : buckets_(), cached_begin_bucket_(), size_(), allocators_(x.allocators_) { this->buckets_ = x.buckets_; this->cached_begin_bucket_ = x.cached_begin_bucket_; @@ -56,7 +56,7 @@ namespace boost { namespace unordered_detail { template hash_table_manager::hash_table_manager(hash_table_manager& x, value_allocator const& a, move_tag) : - structure(), allocators_(a,a) + buckets_(), cached_begin_bucket_(), size_(), allocators_(a,a) { if(this->node_alloc() == x.node_alloc()) { this->buckets_ = x.buckets_; @@ -78,8 +78,9 @@ namespace boost { namespace unordered_detail { // no throw template - void hash_table_manager::move(hash_table_manager& other) + inline void hash_table_manager::move(hash_table_manager& other) { + BOOST_ASSERT(node_alloc() == other.node_alloc()); delete_buckets(); this->buckets_ = other.buckets_; this->cached_begin_bucket_ = other.cached_begin_bucket_; @@ -91,6 +92,131 @@ namespace boost { namespace unordered_detail { other.bucket_count_ = 0; } + template + inline void hash_table_manager::swap(hash_table_manager& other) + { + BOOST_ASSERT(node_alloc() == other.node_alloc()); + std::swap(buckets_, other.buckets_); + std::swap(cached_begin_bucket_, other.cached_begin_bucket_); + std::swap(size_, other.size_); + std::swap(bucket_count_, other.bucket_count_); + } + + // Buckets + + template + inline std::size_t hash_table_manager::bucket_count() const + { + return bucket_count_; + } + + template + inline std::size_t hash_table_manager::bucket_from_hash(std::size_t hashed) const + { + return hashed % bucket_count_; + } + + template + inline BOOST_DEDUCED_TYPENAME hash_table_manager::bucket_ptr + hash_table_manager::bucket_ptr_from_hash(std::size_t hashed) const + { + return buckets_ + static_cast( + bucket_from_hash(hashed)); + } + + template + inline BOOST_DEDUCED_TYPENAME hash_table_manager::bucket_ptr + hash_table_manager::buckets_begin() const + { + return buckets_; + } + + template + inline BOOST_DEDUCED_TYPENAME hash_table_manager::bucket_ptr + hash_table_manager::buckets_end() const + { + return buckets_ + static_cast(bucket_count_); + } + + template + inline std::size_t hash_table_manager::bucket_size(std::size_t index) const + { + bucket_ptr ptr = (buckets_ + static_cast(index))->next_; + std::size_t count = 0; + while(ptr) { + ++count; + ptr = next_node(ptr); + } + return count; + } + + template + inline BOOST_DEDUCED_TYPENAME hash_table_manager::bucket_ptr + hash_table_manager::get_bucket(std::size_t n) const + { + return buckets_ + static_cast(n); + } + + template + inline BOOST_DEDUCED_TYPENAME hash_table_manager::node_ptr + hash_table_manager::bucket_begin(std::size_t n) const + { + return (buckets_ + static_cast(n))->next_; + } + + template + inline BOOST_DEDUCED_TYPENAME hash_table_manager::node_ptr + hash_table_manager::bucket_end(std::size_t) const + { + return node_ptr(); + } + + // 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 + + template + inline void hash_table_manager::recompute_begin_bucket(bucket_ptr b) + { + BOOST_ASSERT(!(b < cached_begin_bucket_)); + + if(b == cached_begin_bucket_) + { + if (size_ != 0) { + while (!cached_begin_bucket_->next_) + ++cached_begin_bucket_; + } else { + cached_begin_bucket_ = buckets_end(); + } + } + } + + // This is called when a range has been erased + // + // no throw + + template + inline void hash_table_manager::recompute_begin_bucket(bucket_ptr b1, bucket_ptr b2) + { + BOOST_ASSERT(!(b1 < cached_begin_bucket_) && !(b2 < b1)); + BOOST_ASSERT(BOOST_UNORDERED_BORLAND_BOOL(b2->next_)); + + if(b1 == cached_begin_bucket_ && !b1->next_) + cached_begin_bucket_ = b2; + } + + // no throw + template + inline float hash_table_manager::load_factor() const + { + BOOST_ASSERT(bucket_count_ != 0); + return static_cast(size_) + / static_cast(bucket_count_); + } + // Construct/destruct template @@ -117,7 +243,7 @@ namespace boost { namespace unordered_detail { } template - void hash_table_manager::destruct_node(node_ptr b) + inline void hash_table_manager::destruct_node(node_ptr b) { node* raw_ptr = static_cast(&*b); BOOST_UNORDERED_DESTRUCT(&raw_ptr->value(), value_type); @@ -129,13 +255,13 @@ namespace boost { namespace unordered_detail { // Delete and clear buckets template - void hash_table_manager::delete_group(node_ptr first_node) + inline void hash_table_manager::delete_group(node_ptr first_node) { delete_nodes(first_node, node::next_group(first_node)); } template - void hash_table_manager::delete_nodes(node_ptr begin, node_ptr end) + inline void hash_table_manager::delete_nodes(node_ptr begin, node_ptr end) { while(begin != end) { node_ptr node = begin; @@ -145,7 +271,7 @@ namespace boost { namespace unordered_detail { } template - void hash_table_manager::delete_to_bucket_end(node_ptr begin) + inline void hash_table_manager::delete_to_bucket_end(node_ptr begin) { while(BOOST_UNORDERED_BORLAND_BOOL(begin)) { node_ptr node = begin; @@ -155,7 +281,7 @@ namespace boost { namespace unordered_detail { } template - void hash_table_manager::clear_bucket(bucket_ptr b) + inline void hash_table_manager::clear_bucket(bucket_ptr b) { node_ptr node_it = b->next_; b->next_ = node_ptr(); @@ -179,7 +305,7 @@ namespace boost { namespace unordered_detail { } template - void hash_table_manager::delete_buckets() + inline void hash_table_manager::delete_buckets() { clear(); @@ -202,7 +328,8 @@ namespace boost { namespace unordered_detail { BOOST_ASSERT(!r.is_end()); iterator_base next = r; next.increment(); - this->unlink_node(r.bucket_, r.node_); + --this->size_; + node::unlink_node(*r.bucket_, r.node_); destruct_node(r.node_); // r has been invalidated but its bucket is still valid this->recompute_begin_bucket(r.bucket_, next.bucket_); @@ -210,14 +337,14 @@ namespace boost { namespace unordered_detail { } template - std::size_t hash_table_manager::erase_group(node_ptr* it, bucket_ptr bucket) + inline std::size_t hash_table_manager::erase_group(node_ptr* it, bucket_ptr bucket) { node_ptr pos = *it; - std::size_t count = this->unlink_group(it); + std::size_t count = node::group_count(*it); + this->size_ -= count; + node::unlink_group(it); delete_group(pos); - this->recompute_begin_bucket(bucket); - return count; } @@ -230,7 +357,8 @@ namespace boost { namespace unordered_detail { BOOST_ASSERT(!r1.is_end()); if (r1.bucket_ == r2.bucket_) { - this->unlink_nodes(r1.bucket_, r1.node_, r2.node_); + this->size_ -= node_count(r1.node_, r2.node_); + node::unlink_nodes(*r1.bucket_, r1.node_, r2.node_); delete_nodes(r1.node_, r2.node_); // No need to call recompute_begin_bucket because @@ -241,7 +369,8 @@ namespace boost { namespace unordered_detail { else { BOOST_ASSERT(r1.bucket_ < r2.bucket_); - this->unlink_nodes(r1.bucket_, r1.node_, node_ptr()); + this->size_ -= node_count(r1.node_, node_ptr()); + node::unlink_nodes(*r1.bucket_, r1.node_, node_ptr()); delete_to_bucket_end(r1.node_); bucket_ptr i = r1.bucket_; @@ -252,7 +381,8 @@ namespace boost { namespace unordered_detail { if(!r2.is_end()) { node_ptr first = r2.bucket_->next_; - this->unlink_nodes(r2.bucket_, r2.node_); + this->size_ -= node_count(r2.bucket_->next_, r2.node_); + node::unlink_nodes(*r2.bucket_, r2.node_); delete_nodes(first, r2.node_); } @@ -265,6 +395,24 @@ namespace boost { namespace unordered_detail { return r2; } + //////////////////////////////////////////////////////////////////////////// + // hash_iterator_base implementation + + template + inline void hash_iterator_base::increment(node_ptr node) { + while(!node) { + ++bucket_; + node = bucket_->next_; + } + + node_ = node; + } + + template + inline void hash_iterator_base::increment() + { + increment(next_node(node_)); + } }} #endif diff --git a/include/boost/unordered/detail/node.hpp b/include/boost/unordered/detail/node.hpp index d6e95a49..90099f46 100644 --- a/include/boost/unordered/detail/node.hpp +++ b/include/boost/unordered/detail/node.hpp @@ -79,13 +79,13 @@ namespace boost { namespace unordered_detail { } template - void ungrouped_node_base::unlink_node(bucket& b, node_ptr node) + inline void ungrouped_node_base::unlink_node(bucket& b, node_ptr node) { unlink_nodes(b, node, next_node(node)); } template - void ungrouped_node_base::unlink_nodes(bucket& b, node_ptr begin, node_ptr end) + inline void ungrouped_node_base::unlink_nodes(bucket& b, node_ptr begin, node_ptr end) { node_ptr* pos = &b.next_; while(*pos != begin) pos = &next_node(*pos); @@ -93,7 +93,7 @@ namespace boost { namespace unordered_detail { } template - void ungrouped_node_base::unlink_nodes(bucket& b, node_ptr end) + inline void ungrouped_node_base::unlink_nodes(bucket& b, node_ptr end) { b.next_ = end; } diff --git a/include/boost/unordered/detail/structure.hpp b/include/boost/unordered/detail/structure.hpp deleted file mode 100644 index d9b5c633..00000000 --- a/include/boost/unordered/detail/structure.hpp +++ /dev/null @@ -1,220 +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) - -// 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_STRUCTURE_HPP_INCLUDED -#define BOOST_UNORDERED_DETAIL_STRUCTURE_HPP_INCLUDED - -#include - -namespace boost { namespace unordered_detail { - - //////////////////////////////////////////////////////////////////////////// - // hash_structure implementation - - template - void hash_structure::swap(hash_structure& other) - { - std::swap(buckets_, other.buckets_); - std::swap(cached_begin_bucket_, other.cached_begin_bucket_); - std::swap(size_, other.size_); - std::swap(bucket_count_, other.bucket_count_); - } - - template - std::size_t hash_structure::bucket_count() const - { - return bucket_count_; - } - - template - std::size_t hash_structure::bucket_from_hash(std::size_t hashed) const - { - return hashed % bucket_count_; - } - - template - BOOST_DEDUCED_TYPENAME hash_structure::bucket_ptr - hash_structure::bucket_ptr_from_hash(std::size_t hashed) const - { - return buckets_ + static_cast( - bucket_from_hash(hashed)); - } - - template - BOOST_DEDUCED_TYPENAME hash_structure::bucket_ptr - hash_structure::buckets_begin() const - { - return buckets_; - } - - template - BOOST_DEDUCED_TYPENAME hash_structure::bucket_ptr - hash_structure::buckets_end() const - { - return buckets_ + static_cast(bucket_count_); - } - - template - std::size_t hash_structure::bucket_size(std::size_t index) const - { - bucket_ptr ptr = (buckets_ + static_cast(index))->next_; - std::size_t count = 0; - while(ptr) { - ++count; - ptr = next_node(ptr); - } - return count; - } - - // Link a node - - template - void hash_structure::link_node(node_ptr n, node_ptr position) - { - node_base::add_after_node(n, position); - ++size_; - } - - template - void hash_structure::link_node_in_bucket(node_ptr n, bucket_ptr bucket) - { - node_base::add_to_bucket(n, *bucket); - ++size_; - if(bucket < cached_begin_bucket_) cached_begin_bucket_ = bucket; - } - - template - void hash_structure::unlink_node(bucket_ptr bucket, node_ptr pos) - { - --size_; - node_base::unlink_node(*bucket, pos); - } - - template - void hash_structure::unlink_nodes( - bucket_ptr bucket, node_ptr begin, node_ptr end) - { - size_ -= node_count(begin, end); - node_base::unlink_nodes(*bucket, begin, end); - } - - template - void hash_structure::unlink_nodes(bucket_ptr bucket, node_ptr end) - { - size_ -= node_count(bucket->next_, end); - node_base::unlink_nodes(*bucket, end); - } - - template - std::size_t hash_structure::unlink_group(node_ptr* pos) - { - std::size_t count = node_base::group_count(*pos); - size_ -= count; - node_base::unlink_group(pos); - return count; - } - - template - void hash_structure::link_group( - node_ptr n, bucket_ptr bucket, std::size_t count) - { - node_base::add_group_to_bucket(n, *bucket); - size_ += count; - if(bucket < cached_begin_bucket_) cached_begin_bucket_ = bucket; - } - - template - BOOST_DEDUCED_TYPENAME hash_structure::bucket_ptr - hash_structure::get_bucket(std::size_t n) const - { - return buckets_ + static_cast(n); - } - - template - BOOST_DEDUCED_TYPENAME hash_structure::node_ptr - hash_structure::bucket_begin(std::size_t n) const - { - return (buckets_ + static_cast(n))->next_; - } - - template - BOOST_DEDUCED_TYPENAME hash_structure::node_ptr - hash_structure::bucket_end(std::size_t) const - { - return node_ptr(); - } - - // 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 - - template - void hash_structure::recompute_begin_bucket(bucket_ptr b) - { - BOOST_ASSERT(!(b < cached_begin_bucket_)); - - if(b == cached_begin_bucket_) - { - if (size_ != 0) { - while (!cached_begin_bucket_->next_) - ++cached_begin_bucket_; - } else { - cached_begin_bucket_ = buckets_end(); - } - } - } - - // This is called when a range has been erased - // - // no throw - - template - void hash_structure::recompute_begin_bucket(bucket_ptr b1, bucket_ptr b2) - { - BOOST_ASSERT(!(b1 < cached_begin_bucket_) && !(b2 < b1)); - BOOST_ASSERT(BOOST_UNORDERED_BORLAND_BOOL(b2->next_)); - - if(b1 == cached_begin_bucket_ && !b1->next_) - cached_begin_bucket_ = b2; - } - - // no throw - template - inline float hash_structure::load_factor() const - { - BOOST_ASSERT(bucket_count_ != 0); - return static_cast(size_) - / static_cast(bucket_count_); - } - - //////////////////////////////////////////////////////////////////////////// - // hash_iterator_base implementation - - template - inline void hash_iterator_base::increment(node_ptr node) { - while(!node) { - ++bucket_; - node = bucket_->next_; - } - - node_ = node; - } - - template - inline void hash_iterator_base::increment() - { - increment(next_node(node_)); - } -}} - -#endif diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 7c9c61eb..f36e691c 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -327,7 +327,7 @@ namespace boost { namespace unordered_detail { // basic exception safety template - bool hash_table + inline bool hash_table ::reserve(std::size_t n) { bool need_to_reserve = n >= this->max_load_; @@ -339,7 +339,7 @@ namespace boost { namespace unordered_detail { // basic exception safety template - bool hash_table + inline bool hash_table ::reserve_for_insert(std::size_t n) { bool need_to_reserve = n >= this->max_load_; @@ -419,8 +419,12 @@ namespace boost { namespace unordered_detail { hf(extractor::extract(node::get_value(src_bucket->next_)))); node_ptr n = src_bucket->next_; - std::size_t count = this->unlink_group(&src_bucket->next_); - dst.link_group(n, dst_bucket, count); + std::size_t count = node::group_count(src_bucket->next_); + this->size_ -= count; + dst.size_ += count; + node::unlink_group(&src_bucket->next_); + node::add_group_to_bucket(n, *dst_bucket); + if(dst_bucket < dst.cached_begin_bucket_) dst.cached_begin_bucket_ = dst_bucket; } } } @@ -454,11 +458,14 @@ namespace boost { namespace unordered_detail { a.construct(node::get_value(it)); node_ptr n = a.release(); - dst.link_node_in_bucket(n, dst_bucket); + node::add_to_bucket(n, *dst_bucket); + ++dst.size_; + if(dst_bucket < dst.cached_begin_bucket_) dst.cached_begin_bucket_ = dst_bucket; for(it = next_node(it); it != group_end; it = next_node(it)) { a.construct(node::get_value(it)); - dst.link_node(a.release(), n); + node::add_after_node(a.release(), n); + ++dst.size_; } } } From 6a8506d9591824bffce1b8ab9d9d240ed895a8be Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 3 Sep 2009 07:37:14 +0000 Subject: [PATCH 099/471] Remove some old Visual C++ workarounds. [SVN r55991] --- include/boost/unordered/unordered_map.hpp | 10 ++-------- include/boost/unordered/unordered_set.hpp | 10 ++-------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 5eb0eae5..8880a029 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -485,10 +485,7 @@ namespace boost 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) +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) friend bool operator==(unordered_map const&, unordered_map const&); friend bool operator!=(unordered_map const&, unordered_map const&); #endif @@ -945,10 +942,7 @@ namespace boost 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) +#if !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 942f3516..c6ef5fc7 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -454,10 +454,7 @@ namespace boost 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) +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) friend bool operator==(unordered_set const&, unordered_set const&); friend bool operator!=(unordered_set const&, unordered_set const&); #endif @@ -894,10 +891,7 @@ namespace boost 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) +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) friend bool operator==(unordered_multiset const&, unordered_multiset const&); friend bool operator!=(unordered_multiset const&, unordered_multiset const&); #endif From 7598d0d49bb5ba6d9c598af295df781303f25902 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 3 Sep 2009 07:37:30 +0000 Subject: [PATCH 100/471] Add a small test to see if the tested compilers support out of line template methods. [SVN r55992] --- test/unordered/Jamfile.v2 | 1 + test/unordered/out_of_line.cpp | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 test/unordered/out_of_line.cpp diff --git a/test/unordered/Jamfile.v2 b/test/unordered/Jamfile.v2 index ee1505f7..5a4696f6 100644 --- a/test/unordered/Jamfile.v2 +++ b/test/unordered/Jamfile.v2 @@ -38,4 +38,5 @@ test-suite unordered [ run rehash_tests.cpp ] [ run equality_tests.cpp ] [ run swap_tests.cpp : : : BOOST_UNORDERED_SWAP_METHOD=2 ] + [ run out_of_line.cpp ] ; diff --git a/test/unordered/out_of_line.cpp b/test/unordered/out_of_line.cpp new file mode 100644 index 00000000..b8d24e1f --- /dev/null +++ b/test/unordered/out_of_line.cpp @@ -0,0 +1,21 @@ +// Just a little test to see if out of line template methods are supported: + +#include + +template +struct foo { + template + bool bar(U x); +}; + +template +template +bool foo::bar(U x) { return x; } + +int main() { + foo x; + BOOST_TEST(x.bar(1)); + BOOST_TEST(!x.bar(0)); + + return boost::report_errors(); +} \ No newline at end of file From 9ec148aec58b8d9ed658c7539e5fd580588caf95 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 4 Sep 2009 07:02:28 +0000 Subject: [PATCH 101/471] Fix link to n2691. [SVN r56009] --- doc/ref.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 From 491fa330f6f5700d97043fe2fc44578772cb8600 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 4 Sep 2009 07:03:04 +0000 Subject: [PATCH 102/471] Move size_ and cached_begin_bucket_ into table, rename hash_table_manager hash_buckets. [SVN r56010] --- include/boost/unordered/detail/buckets.hpp | 262 +++++++++++++ include/boost/unordered/detail/fwd.hpp | 133 +++---- include/boost/unordered/detail/manager.hpp | 418 --------------------- include/boost/unordered/detail/table.hpp | 304 +++++++++++---- include/boost/unordered/detail/util.hpp | 28 +- 5 files changed, 580 insertions(+), 565 deletions(-) create mode 100644 include/boost/unordered/detail/buckets.hpp delete mode 100644 include/boost/unordered/detail/manager.hpp diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp new file mode 100644 index 00000000..29fedd29 --- /dev/null +++ b/include/boost/unordered/detail/buckets.hpp @@ -0,0 +1,262 @@ + +// 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 { + + //////////////////////////////////////////////////////////////////////////// + // Explicitly call a destructor + +#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 + + // Constructors + + template + hash_buckets::hash_buckets(node_allocator const& a, std::size_t bucket_count) + : buckets_(), allocators_(a,a) + { + // 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(), bucket_count + 1); + + // Set up the sentinel (node_ptr cast) + bucket_ptr sentinel = constructor.get() + static_cast(bucket_count); + sentinel->next_ = sentinel; + + // Only release the buckets once everything is successfully + // done. + this->buckets_ = constructor.release(); + this->bucket_count_ = bucket_count; + } + + template + hash_buckets::hash_buckets(hash_buckets& x, move_tag) + : buckets_(), allocators_(x.allocators_) + { + this->buckets_ = x.buckets_; + this->bucket_count_ = x.bucket_count_; + x.buckets_ = bucket_ptr(); + x.bucket_count_ = 0; + } + + template + hash_buckets::hash_buckets(hash_buckets& x, value_allocator const& a, move_tag) : + buckets_(), allocators_(a,a) + { + if(this->node_alloc() == x.node_alloc()) { + this->buckets_ = x.buckets_; + this->bucket_count_ = x.bucket_count_; + x.buckets_ = bucket_ptr(); + x.bucket_count_ = 0; + } + } + + template + hash_buckets::~hash_buckets() + { + if(this->buckets_) { delete_buckets(); } + } + + // no throw + template + inline void hash_buckets::move(hash_buckets& other) + { + BOOST_ASSERT(node_alloc() == other.node_alloc()); + 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_); + } + + // Buckets + + template + inline std::size_t hash_buckets::bucket_count() const + { + return bucket_count_; + } + + template + inline std::size_t hash_buckets::bucket_from_hash(std::size_t hashed) const + { + return hashed % bucket_count_; + } + + template + inline BOOST_DEDUCED_TYPENAME hash_buckets::bucket_ptr + hash_buckets::bucket_ptr_from_hash(std::size_t hashed) const + { + return buckets_ + static_cast( + bucket_from_hash(hashed)); + } + + template + inline BOOST_DEDUCED_TYPENAME hash_buckets::bucket_ptr + hash_buckets::buckets_begin() const + { + return buckets_; + } + + template + inline BOOST_DEDUCED_TYPENAME hash_buckets::bucket_ptr + hash_buckets::buckets_end() const + { + return buckets_ + static_cast(bucket_count_); + } + + template + inline std::size_t hash_buckets::bucket_size(std::size_t index) const + { + bucket_ptr ptr = (buckets_ + static_cast(index))->next_; + std::size_t count = 0; + while(ptr) { + ++count; + ptr = next_node(ptr); + } + return count; + } + + template + inline BOOST_DEDUCED_TYPENAME hash_buckets::bucket_ptr + hash_buckets::get_bucket(std::size_t n) const + { + return buckets_ + static_cast(n); + } + + template + inline BOOST_DEDUCED_TYPENAME hash_buckets::node_ptr + hash_buckets::bucket_begin(std::size_t n) const + { + return (buckets_ + static_cast(n))->next_; + } + + template + inline BOOST_DEDUCED_TYPENAME hash_buckets::node_ptr + hash_buckets::bucket_end(std::size_t) const + { + return node_ptr(); + } + + // Construct/destruct + + template + inline void hash_buckets::destruct_node(node_ptr b) + { + node* raw_ptr = static_cast(&*b); + BOOST_UNORDERED_DESTRUCT(&raw_ptr->value(), value_type); + real_node_ptr n(node_alloc().address(*raw_ptr)); + node_alloc().destroy(n); + node_alloc().deallocate(n, 1); + } + + // Delete and clear buckets + + template + inline void hash_buckets::delete_group(node_ptr first_node) + { + delete_nodes(first_node, node::next_group(first_node)); + } + + template + inline void hash_buckets::delete_nodes(node_ptr begin, node_ptr end) + { + while(begin != end) { + node_ptr node = begin; + begin = next_node(begin); + destruct_node(node); + } + } + + template + inline void hash_buckets::delete_to_bucket_end(node_ptr begin) + { + while(BOOST_UNORDERED_BORLAND_BOOL(begin)) { + node_ptr node = begin; + begin = next_node(begin); + destruct_node(node); + } + } + + 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_destruct = node_it; + node_it = next_node(node_it); + destruct_node(node_to_destruct); + } + } + + template + inline void hash_buckets::delete_buckets() + { + for(bucket_ptr begin = this->buckets_begin(), end = this->buckets_end(); begin != end; ++begin) { + clear_bucket(begin); + } + + // Destroy the buckets (including the sentinel bucket). + bucket_ptr end = this->buckets_end(); + ++end; + for(bucket_ptr begin = this->buckets_begin(); begin != end; ++begin) { + bucket_alloc().destroy(begin); + } + + bucket_alloc().deallocate(this->buckets_begin(), this->bucket_count() + 1); + + this->buckets_ = bucket_ptr(); + } + + //////////////////////////////////////////////////////////////////////////// + // hash_iterator_base implementation + + template + inline void hash_iterator_base::increment(node_ptr node) { + while(!node) { + ++bucket_; + node = bucket_->next_; + } + + node_ = node; + } + + template + inline void hash_iterator_base::increment() + { + increment(next_node(node_)); + } +}} + +#endif diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index 2d18775a..7cd56174 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -183,7 +183,7 @@ namespace boost { namespace unordered_detail { void increment(); }; - // hash_table_manager + // hash_buckets // // This is responsible for allocating and deallocating buckets and nodes. // @@ -193,8 +193,11 @@ namespace boost { namespace unordered_detail { // methods (other than getters and setters). template - struct hash_table_manager + class hash_buckets { + hash_buckets(hash_buckets const&); + hash_buckets& operator=(hash_buckets const&); + public: // Types typedef A value_allocator; @@ -217,8 +220,6 @@ namespace boost { namespace unordered_detail { // Members bucket_ptr buckets_; - bucket_ptr cached_begin_bucket_; - std::size_t size_; std::size_t bucket_count_; boost::compressed_pair allocators_; @@ -228,8 +229,6 @@ namespace boost { namespace unordered_detail { node_allocator const& node_alloc() const { return allocators_.second(); } bucket_allocator& bucket_alloc() { return allocators_.first(); } node_allocator& node_alloc() { return allocators_.second(); } - iterator_base begin() const { return iterator_base(this->cached_begin_bucket_); } - iterator_base end() const { return iterator_base(this->buckets_end()); } std::size_t max_bucket_count() const { // -1 to account for the sentinel. return prev_prime(this->bucket_alloc().max_size() - 1); @@ -239,20 +238,17 @@ namespace boost { namespace unordered_detail { // // The copy constructor doesn't copy the buckets. - hash_table_manager(); - explicit hash_table_manager(value_allocator const& a); - explicit hash_table_manager(hash_table_manager const& h); - hash_table_manager(hash_table_manager& x, move_tag m); - hash_table_manager(hash_table_manager& x, value_allocator const& a, move_tag m); - ~hash_table_manager(); + hash_buckets(node_allocator const& a, std::size_t n); + hash_buckets(hash_buckets& x, move_tag m); + hash_buckets(hash_buckets& x, value_allocator const& a, move_tag m); + ~hash_buckets(); // no throw - void swap(hash_table_manager& other); - void move(hash_table_manager& other); + void swap(hash_buckets& other); + void move(hash_buckets& other); // Buckets - void create_buckets(std::size_t bucket_count); std::size_t bucket_count() const; std::size_t bucket_from_hash(std::size_t hashed) const; bucket_ptr bucket_ptr_from_hash(std::size_t hashed) const; @@ -269,42 +265,15 @@ namespace boost { namespace unordered_detail { // void delete_buckets(); - void clear(); void clear_bucket(bucket_ptr); void delete_group(node_ptr first_node); void delete_nodes(node_ptr begin, node_ptr end); void delete_to_bucket_end(node_ptr begin); - - // Erase - // - // no throw - - 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 - // - // 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; }; template class hash_table : - public hash_table_manager + public hash_buckets { public: @@ -313,19 +282,19 @@ namespace boost { namespace unordered_detail { typedef A value_allocator; typedef G grouped; typedef K key_extractor; - typedef hash_table_manager manager; + 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 manager::node node; - typedef BOOST_DEDUCED_TYPENAME manager::bucket bucket; - typedef BOOST_DEDUCED_TYPENAME manager::node_ptr node_ptr; - typedef BOOST_DEDUCED_TYPENAME manager::bucket_ptr bucket_ptr; + 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 manager::iterator_base iterator_base; + typedef BOOST_DEDUCED_TYPENAME buckets::iterator_base iterator_base; // Types for storing functions @@ -340,6 +309,8 @@ namespace boost { namespace unordered_detail { bool func_; // The currently active functions. aligned_function funcs_[2]; + bucket_ptr cached_begin_bucket_; + std::size_t size_; float mlf_; std::size_t max_load_; @@ -395,6 +366,11 @@ namespace boost { namespace unordered_detail { ~hash_table(); hash_table& operator=(hash_table const&); + // Iterators + + iterator_base begin() const { return iterator_base(this->cached_begin_bucket_); } + iterator_base end() const { return iterator_base(this->buckets_end()); } + // Swap & Move void swap(hash_table& x); @@ -409,16 +385,45 @@ namespace boost { namespace unordered_detail { // Move/copy buckets - void move_buckets_to(manager& dst); - void copy_buckets_to(manager& dst) const; + void move_buckets_to(buckets& dst); + void copy_buckets_to(buckets& dst) const; // Misc. key methods - std::size_t erase_key(key_type const& k); 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; std::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 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); + + // 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 Access @@ -456,9 +461,9 @@ namespace boost { namespace unordered_detail { typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; private: - typedef hash_table_manager manager; - typedef BOOST_DEDUCED_TYPENAME manager::node_ptr ptr; - typedef BOOST_DEDUCED_TYPENAME manager::node node; + typedef hash_buckets buckets; + typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr ptr; + typedef BOOST_DEDUCED_TYPENAME buckets::node node; typedef hash_const_local_iterator const_local_iterator; friend class hash_const_local_iterator; @@ -491,9 +496,9 @@ namespace boost { namespace unordered_detail { typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; private: - typedef hash_table_manager manager; - typedef BOOST_DEDUCED_TYPENAME manager::node_ptr ptr; - typedef BOOST_DEDUCED_TYPENAME manager::node node; + 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_; @@ -531,9 +536,9 @@ namespace boost { namespace unordered_detail { typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; private: - typedef hash_table_manager manager; - typedef BOOST_DEDUCED_TYPENAME manager::node node; - typedef BOOST_DEDUCED_TYPENAME manager::iterator_base base; + 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_; @@ -566,9 +571,9 @@ namespace boost { namespace unordered_detail { typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; private: - typedef hash_table_manager manager; - typedef BOOST_DEDUCED_TYPENAME manager::node node; - typedef BOOST_DEDUCED_TYPENAME manager::iterator_base base; + 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; diff --git a/include/boost/unordered/detail/manager.hpp b/include/boost/unordered/detail/manager.hpp deleted file mode 100644 index 5b9d7383..00000000 --- a/include/boost/unordered/detail/manager.hpp +++ /dev/null @@ -1,418 +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_MANAGER_HPP_INCLUDED -#define BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED - -#include -#include -#include - -namespace boost { namespace unordered_detail { - - //////////////////////////////////////////////////////////////////////////// - // Explicitly call a destructor - -#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 - - // Constructors - - template - hash_table_manager::hash_table_manager() - : buckets_(), cached_begin_bucket_(), size_(), allocators_() {} - - template - hash_table_manager::hash_table_manager(value_allocator const& a) - : buckets_(), cached_begin_bucket_(), size_(), allocators_(a,a) {} - - template - hash_table_manager::hash_table_manager(hash_table_manager const& h) - : buckets_(), cached_begin_bucket_(), size_(), allocators_(h.allocators_) {} - - template - hash_table_manager::hash_table_manager(hash_table_manager& x, move_tag) - : buckets_(), cached_begin_bucket_(), size_(), allocators_(x.allocators_) - { - this->buckets_ = x.buckets_; - this->cached_begin_bucket_ = x.cached_begin_bucket_; - this->size_ = x.size_; - this->bucket_count_ = x.bucket_count_; - x.buckets_ = bucket_ptr(); - x.cached_begin_bucket_ = bucket_ptr(); - x.size_ = 0; - x.bucket_count_ = 0; - } - - template - hash_table_manager::hash_table_manager(hash_table_manager& x, value_allocator const& a, move_tag) : - buckets_(), cached_begin_bucket_(), size_(), allocators_(a,a) - { - if(this->node_alloc() == x.node_alloc()) { - this->buckets_ = x.buckets_; - this->cached_begin_bucket_ = x.cached_begin_bucket_; - this->size_ = x.size_; - this->bucket_count_ = x.bucket_count_; - x.buckets_ = bucket_ptr(); - x.cached_begin_bucket_ = bucket_ptr(); - x.size_ = 0; - x.bucket_count_ = 0; - } - } - - template - hash_table_manager::~hash_table_manager() - { - if(this->buckets_) { delete_buckets(); } - } - - // no throw - template - inline void hash_table_manager::move(hash_table_manager& other) - { - BOOST_ASSERT(node_alloc() == other.node_alloc()); - delete_buckets(); - this->buckets_ = other.buckets_; - this->cached_begin_bucket_ = other.cached_begin_bucket_; - this->size_ = other.size_; - this->bucket_count_ = other.bucket_count_; - other.buckets_ = bucket_ptr(); - other.cached_begin_bucket_ = bucket_ptr(); - other.size_ = 0; - other.bucket_count_ = 0; - } - - template - inline void hash_table_manager::swap(hash_table_manager& other) - { - BOOST_ASSERT(node_alloc() == other.node_alloc()); - std::swap(buckets_, other.buckets_); - std::swap(cached_begin_bucket_, other.cached_begin_bucket_); - std::swap(size_, other.size_); - std::swap(bucket_count_, other.bucket_count_); - } - - // Buckets - - template - inline std::size_t hash_table_manager::bucket_count() const - { - return bucket_count_; - } - - template - inline std::size_t hash_table_manager::bucket_from_hash(std::size_t hashed) const - { - return hashed % bucket_count_; - } - - template - inline BOOST_DEDUCED_TYPENAME hash_table_manager::bucket_ptr - hash_table_manager::bucket_ptr_from_hash(std::size_t hashed) const - { - return buckets_ + static_cast( - bucket_from_hash(hashed)); - } - - template - inline BOOST_DEDUCED_TYPENAME hash_table_manager::bucket_ptr - hash_table_manager::buckets_begin() const - { - return buckets_; - } - - template - inline BOOST_DEDUCED_TYPENAME hash_table_manager::bucket_ptr - hash_table_manager::buckets_end() const - { - return buckets_ + static_cast(bucket_count_); - } - - template - inline std::size_t hash_table_manager::bucket_size(std::size_t index) const - { - bucket_ptr ptr = (buckets_ + static_cast(index))->next_; - std::size_t count = 0; - while(ptr) { - ++count; - ptr = next_node(ptr); - } - return count; - } - - template - inline BOOST_DEDUCED_TYPENAME hash_table_manager::bucket_ptr - hash_table_manager::get_bucket(std::size_t n) const - { - return buckets_ + static_cast(n); - } - - template - inline BOOST_DEDUCED_TYPENAME hash_table_manager::node_ptr - hash_table_manager::bucket_begin(std::size_t n) const - { - return (buckets_ + static_cast(n))->next_; - } - - template - inline BOOST_DEDUCED_TYPENAME hash_table_manager::node_ptr - hash_table_manager::bucket_end(std::size_t) const - { - return node_ptr(); - } - - // 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 - - template - inline void hash_table_manager::recompute_begin_bucket(bucket_ptr b) - { - BOOST_ASSERT(!(b < cached_begin_bucket_)); - - if(b == cached_begin_bucket_) - { - if (size_ != 0) { - while (!cached_begin_bucket_->next_) - ++cached_begin_bucket_; - } else { - cached_begin_bucket_ = buckets_end(); - } - } - } - - // This is called when a range has been erased - // - // no throw - - template - inline void hash_table_manager::recompute_begin_bucket(bucket_ptr b1, bucket_ptr b2) - { - BOOST_ASSERT(!(b1 < cached_begin_bucket_) && !(b2 < b1)); - BOOST_ASSERT(BOOST_UNORDERED_BORLAND_BOOL(b2->next_)); - - if(b1 == cached_begin_bucket_ && !b1->next_) - cached_begin_bucket_ = b2; - } - - // no throw - template - inline float hash_table_manager::load_factor() const - { - BOOST_ASSERT(bucket_count_ != 0); - return static_cast(size_) - / static_cast(bucket_count_); - } - - // Construct/destruct - - template - void hash_table_manager::create_buckets(std::size_t bucket_count) { - BOOST_ASSERT(!this->buckets_ && !this->size_); - - // 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(), bucket_count + 1); - - this->cached_begin_bucket_ = constructor.get() + static_cast(bucket_count); - - // Set up the sentinel (node_ptr cast) - this->cached_begin_bucket_->next_ = this->cached_begin_bucket_; - - // Only release the buckets once everything is successfully - // done. - this->buckets_ = constructor.release(); - this->bucket_count_ = bucket_count; - } - - template - inline void hash_table_manager::destruct_node(node_ptr b) - { - node* raw_ptr = static_cast(&*b); - BOOST_UNORDERED_DESTRUCT(&raw_ptr->value(), value_type); - real_node_ptr n(node_alloc().address(*raw_ptr)); - node_alloc().destroy(n); - node_alloc().deallocate(n, 1); - } - - // Delete and clear buckets - - template - inline void hash_table_manager::delete_group(node_ptr first_node) - { - delete_nodes(first_node, node::next_group(first_node)); - } - - template - inline void hash_table_manager::delete_nodes(node_ptr begin, node_ptr end) - { - while(begin != end) { - node_ptr node = begin; - begin = next_node(begin); - destruct_node(node); - } - } - - template - inline void hash_table_manager::delete_to_bucket_end(node_ptr begin) - { - while(BOOST_UNORDERED_BORLAND_BOOL(begin)) { - node_ptr node = begin; - begin = next_node(begin); - destruct_node(node); - } - } - - template - inline void hash_table_manager::clear_bucket(bucket_ptr b) - { - node_ptr node_it = b->next_; - b->next_ = node_ptr(); - - while(node_it) { - node_ptr node_to_destruct = node_it; - node_it = next_node(node_it); - destruct_node(node_to_destruct); - } - } - - template - void hash_table_manager::clear() - { - for(bucket_ptr begin = this->buckets_begin(), end = this->buckets_end(); begin != end; ++begin) { - clear_bucket(begin); - } - - this->cached_begin_bucket_ = this->buckets_end(); - this->size_ = 0; - } - - template - inline void hash_table_manager::delete_buckets() - { - clear(); - - // Destroy the buckets (including the sentinel bucket). - bucket_ptr end = this->buckets_end(); - ++end; - for(bucket_ptr begin = this->buckets_begin(); begin != end; ++begin) { - bucket_alloc().destroy(begin); - } - - bucket_alloc().deallocate(this->buckets_begin(), this->bucket_count() + 1); - - this->buckets_= bucket_ptr(); - } - - template - BOOST_DEDUCED_TYPENAME hash_table_manager::iterator_base - hash_table_manager::erase(iterator_base r) - { - BOOST_ASSERT(!r.is_end()); - iterator_base next = r; - next.increment(); - --this->size_; - node::unlink_node(*r.bucket_, r.node_); - destruct_node(r.node_); - // r has been invalidated but its bucket is still valid - this->recompute_begin_bucket(r.bucket_, next.bucket_); - return next; - } - - template - inline std::size_t hash_table_manager::erase_group(node_ptr* it, bucket_ptr bucket) - { - node_ptr pos = *it; - std::size_t count = node::group_count(*it); - this->size_ -= count; - node::unlink_group(it); - delete_group(pos); - this->recompute_begin_bucket(bucket); - return count; - } - - template - BOOST_DEDUCED_TYPENAME hash_table_manager::iterator_base - hash_table_manager::erase_range(iterator_base r1, iterator_base r2) - { - if(r1 != r2) - { - BOOST_ASSERT(!r1.is_end()); - - if (r1.bucket_ == r2.bucket_) { - this->size_ -= node_count(r1.node_, r2.node_); - node::unlink_nodes(*r1.bucket_, r1.node_, r2.node_); - 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 { - BOOST_ASSERT(r1.bucket_ < r2.bucket_); - - this->size_ -= node_count(r1.node_, node_ptr()); - node::unlink_nodes(*r1.bucket_, r1.node_, node_ptr()); - delete_to_bucket_end(r1.node_); - - bucket_ptr i = r1.bucket_; - for(++i; i != r2.bucket_; ++i) { - this->size_ -= node_count(i->next_, node_ptr()); - clear_bucket(i); - } - - if(!r2.is_end()) { - node_ptr first = r2.bucket_->next_; - this->size_ -= node_count(r2.bucket_->next_, r2.node_); - node::unlink_nodes(*r2.bucket_, r2.node_); - delete_nodes(first, r2.node_); - } - - // r1 has been invalidated but its bucket is still - // valid. - this->recompute_begin_bucket(r1.bucket_, r2.bucket_); - } - } - - return r2; - } - - //////////////////////////////////////////////////////////////////////////// - // hash_iterator_base implementation - - template - inline void hash_iterator_base::increment(node_ptr node) { - while(!node) { - ++bucket_; - node = bucket_->next_; - } - - node_ = node; - } - - template - inline void hash_iterator_base::increment() - { - increment(next_node(node_)); - } -}} - -#endif diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index f36e691c..c3afb6b7 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -13,7 +13,7 @@ #include #include -#include +#include #include namespace boost { namespace unordered_detail { @@ -135,24 +135,25 @@ namespace boost { namespace unordered_detail { template hash_table ::hash_table(std::size_t n, hasher const& hf, key_equal const& eq, value_allocator const& a) : - manager(a), func_(false), mlf_(1.0f), max_load_(0) + buckets(a, next_prime(n)), func_(false), cached_begin_bucket_(), size_(), mlf_(1.0f), max_load_(0) { std::uninitialized_fill((functions*)this->funcs_, (functions*)this->funcs_+2, functions(hf, eq)); - this->create_buckets(next_prime(n)); + this->cached_begin_bucket_ = this->buckets_end(); this->calculate_max_load(); } template hash_table ::hash_table(hash_table const& x) : - manager(x), func_(false), mlf_(x.mlf_), max_load_(0) + buckets(x.node_alloc(), next_prime(x.min_buckets_for_size(x.size_))), func_(false), cached_begin_bucket_(), size_(), mlf_(x.mlf_), max_load_(0) { std::uninitialized_fill((functions*)this->funcs_, (functions*)this->funcs_+2, x.current()); - this->create_buckets(next_prime(x.min_buckets_for_size(x.size_))); this->calculate_max_load(); x.copy_buckets_to(*this); + this->size_ = x.size_; + this->recompute_begin_bucket(); } // Copy Construct with allocator @@ -160,13 +161,15 @@ namespace boost { namespace unordered_detail { template hash_table ::hash_table(hash_table const& x, value_allocator const& a) : - manager(a), func_(false), mlf_(x.mlf_), max_load_(0) + buckets(a, next_prime(x.min_buckets_for_size(x.size_))), func_(false), cached_begin_bucket_(), size_(), mlf_(x.mlf_), max_load_(0) { std::uninitialized_fill((functions*)this->funcs_, (functions*)this->funcs_+2, x.current()); - this->create_buckets(next_prime(x.min_buckets_for_size(x.size_))); + this->cached_begin_bucket_ = this->buckets_end(); this->calculate_max_load(); x.copy_buckets_to(*this); + this->size_ = x.size_; + this->recompute_begin_bucket(); } // Move Construct @@ -174,8 +177,13 @@ namespace boost { namespace unordered_detail { template hash_table ::hash_table(hash_table& x, move_tag m) : - manager(x, m), func_(false), mlf_(x.mlf_), max_load_(0) + buckets(x, m), func_(false), cached_begin_bucket_(), size_(), mlf_(x.mlf_), max_load_(0) { + this->cached_begin_bucket_ = x.cached_begin_bucket_; + this->size_ = x.size_; + x.cached_begin_bucket_ = bucket_ptr(); + x.size_ = 0; + // TODO: Shouldn't I move the functions if poss. std::uninitialized_fill((functions*)this->funcs_, (functions*)this->funcs_+2, x.current()); @@ -184,7 +192,7 @@ namespace boost { namespace unordered_detail { template hash_table ::hash_table(hash_table& x, value_allocator const& a, move_tag m) : - manager(x, a, m), func_(false), mlf_(x.mlf_), max_load_(0) + buckets(x, a, m), func_(false), cached_begin_bucket_(), size_(), mlf_(x.mlf_), max_load_(0) { std::uninitialized_fill((functions*)this->funcs_, (functions*)this->funcs_+2, x.current()); @@ -192,10 +200,17 @@ namespace boost { namespace unordered_detail { this->calculate_max_load(); // no throw if(!this->buckets_) { - this->create_buckets(next_prime(x.min_buckets_for_size(x.size_))); - // This can throw, but hash_table_manager's destructor will clean - // up. - x.copy_buckets_to(*this); + buckets new_buckets(this->node_alloc(), x.min_buckets_for_size(x.size_)); + x.copy_buckets_to(new_buckets); + new_buckets.swap(*this); + this->size_ = x.size_; + this->recompute_begin_bucket(); + } + else { + this->cached_begin_bucket_ = x.cached_begin_bucket_; + this->size_ = x.size_; + x.cached_begin_bucket_ = bucket_ptr(); + x.size_ = 0; } } @@ -205,7 +220,8 @@ namespace boost { namespace unordered_detail { BOOST_UNORDERED_DESTRUCT(this->get_functions(false), functions); BOOST_UNORDERED_DESTRUCT(this->get_functions(true), functions); } - + + // TODO: Reuse current nodes amd buckets? template hash_table& hash_table::operator=(hash_table const& x) { @@ -214,11 +230,14 @@ namespace boost { namespace unordered_detail { this->set_functions( this->buffer_functions(x)); // throws, strong this->mlf_ = x.mlf_; // no throw + buckets new_buckets(this->node_alloc(), x.min_buckets_for_size(x.size_)); + x.copy_buckets_to(new_buckets); + new_buckets.swap(*this); this->calculate_max_load(); // no throw - this->reserve(x.size_); // throws - x.copy_buckets_to(*this); // throws + this->size_ = x.size_; + this->recompute_begin_bucket(); } - + return *this; } @@ -250,25 +269,28 @@ namespace boost { namespace unordered_detail { functions_ptr new_func_that = x.buffer_functions(*this); if(this->node_alloc() == x.node_alloc()) { - this->manager::swap(x); // No throw + this->buckets::swap(x); // No throw + std::swap(this->cached_begin_bucket_, x.cached_begin_bucket_); + std::swap(this->size_, x.size_); } else { - // Create new buckets in separate hash_table_manager objects + // 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). - manager new_this(*this); - new_this.create_buckets(x.min_buckets_for_size(x.size_)); + buckets new_this(this->node_alloc(), x.min_buckets_for_size(x.size_)); x.copy_buckets_to(new_this); - manager new_that(x); - new_that.create_buckets(this->min_buckets_for_size(this->size_)); + buckets new_that(x.node_alloc(), this->min_buckets_for_size(this->size_)); copy_buckets_to(new_that); // Modifying the data, so no throw from now on. - this->manager::swap(new_this); - x.manager::swap(new_that); + this->buckets::swap(new_this); + x.buckets::swap(new_that); + std::swap(this->size_, x.size_); + this->recompute_begin_bucket(); + x.recompute_begin_bucket(); } // The rest is no throw. @@ -300,19 +322,24 @@ namespace boost { namespace unordered_detail { functions_ptr new_func_this = this->buffer_functions(x); if(this->node_alloc() == x.node_alloc()) { - this->manager::move(x); // no throw + this->buckets::move(x); // no throw + this->size_ = x.size_; + this->cached_begin_bucket_ = x.cached_begin_bucket_; + x.size_ = 0; + x.cached_begin_bucket_ = bucket_ptr(); } 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). - manager new_this(*this); - new_this.create_buckets(next_prime(x.min_buckets_for_size(x.size_))); + buckets new_this(this->node_alloc(), next_prime(x.min_buckets_for_size(x.size_))); x.copy_buckets_to(new_this); // Start updating the data here, no throw from now on. - this->manager::move(new_this); + this->buckets::move(new_this); + this->size_ = x.size_; + this->recompute_begin_bucket(); } // We've made it, the rest is no throw. @@ -383,28 +410,13 @@ namespace boost { namespace unordered_detail { if (n == this->bucket_count()) // no throw return; - manager new_buckets(*this); // throws, seperate - new_buckets.create_buckets(n); // throws, seperate - move_buckets_to(new_buckets); // basic/no throw - new_buckets.swap(*this); // no throw - this->calculate_max_load(); // no throw - } + // Save the size to restore it if successful + std::size_t size = this->size_; - //////////////////////////////////////////////////////////////////////////// - // move_buckets_to & copy_buckets_to - - // move_buckets_to - // - // if the hash function throws, basic excpetion safety - // no throw otherwise - - template - void hash_table - ::move_buckets_to(manager& dst) - { - BOOST_ASSERT(this->node_alloc() == dst.node_alloc()); - BOOST_ASSERT(this->buckets_ && dst.buckets_); + // Create another buckets to move the nodes into. + buckets dst(this->node_alloc(), n);// throws, separate + // Move the nodes to dst. hasher const& hf = this->hash_function(); bucket_ptr end = this->buckets_end(); @@ -418,17 +430,25 @@ namespace boost { namespace unordered_detail { bucket_ptr dst_bucket = dst.bucket_ptr_from_hash( hf(extractor::extract(node::get_value(src_bucket->next_)))); + node_ptr n = src_bucket->next_; - std::size_t count = node::group_count(src_bucket->next_); - this->size_ -= count; - dst.size_ += count; + this->size_ -= node::group_count(n); node::unlink_group(&src_bucket->next_); node::add_group_to_bucket(n, *dst_bucket); - if(dst_bucket < dst.cached_begin_bucket_) dst.cached_begin_bucket_ = dst_bucket; } } + + // Swap the new nodes back into the container and setup the local + // variables. + dst.swap(*this); // no throw + this->size_ = size; + this->recompute_begin_bucket(); // no throw + this->calculate_max_load(); // no throw } + //////////////////////////////////////////////////////////////////////////// + // copy_buckets_to + // copy_buckets_to // // basic excpetion safety. If an exception is thrown this will @@ -436,7 +456,7 @@ namespace boost { namespace unordered_detail { template void hash_table - ::copy_buckets_to(manager& dst) const + ::copy_buckets_to(buckets& dst) const { BOOST_ASSERT(this->buckets_ && dst.buckets_); @@ -459,13 +479,10 @@ namespace boost { namespace unordered_detail { a.construct(node::get_value(it)); node_ptr n = a.release(); node::add_to_bucket(n, *dst_bucket); - ++dst.size_; - if(dst_bucket < dst.cached_begin_bucket_) dst.cached_begin_bucket_ = dst_bucket; for(it = next_node(it); it != group_end; it = next_node(it)) { a.construct(node::get_value(it)); node::add_after_node(a.release(), n); - ++dst.size_; } } } @@ -476,18 +493,6 @@ namespace boost { namespace unordered_detail { // strong exception safety - template - std::size_t hash_table - ::erase_key(key_type const& k) - { - // No side effects in initial section - bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); - node_ptr* it = find_for_erase(bucket, k); - - // No throw. - return *it ? this->erase_group(it, bucket) : 0; - } - // count // // strong exception safety, no side effects @@ -563,6 +568,167 @@ namespace boost { namespace unordered_detail { return std::pair(this->end(), this->end()); } } + + //////////////////////////////////////////////////////////////////////////// + // Erase methods + + template + void hash_table::clear() + { + for(bucket_ptr begin = this->buckets_begin(), end = this->buckets_end(); begin != end; ++begin) { + this->clear_bucket(begin); + } + + this->cached_begin_bucket_ = this->buckets_end(); + this->size_ = 0; + } + + template + std::size_t hash_table + ::erase_key(key_type const& k) + { + // 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.is_end()); + iterator_base next = r; + next.increment(); + --this->size_; + node::unlink_node(*r.bucket_, r.node_); + this->destruct_node(r.node_); + // r has been invalidated but its bucket is still valid + this->recompute_begin_bucket(r.bucket_, next.bucket_); + return next; + } + + template + inline std::size_t hash_table::erase_group(node_ptr* it, bucket_ptr bucket) + { + node_ptr pos = *it; + std::size_t count = node::group_count(*it); + this->size_ -= count; + node::unlink_group(it); + this->delete_group(pos); + this->recompute_begin_bucket(bucket); + return count; + } + + template + BOOST_DEDUCED_TYPENAME hash_table::iterator_base + hash_table::erase_range(iterator_base r1, iterator_base r2) + { + if(r1 != r2) + { + BOOST_ASSERT(!r1.is_end()); + + if (r1.bucket_ == r2.bucket_) { + this->size_ -= node_count(r1.node_, r2.node_); + node::unlink_nodes(*r1.bucket_, r1.node_, r2.node_); + 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 { + BOOST_ASSERT(r1.bucket_ < r2.bucket_); + + this->size_ -= node_count(r1.node_, node_ptr()); + node::unlink_nodes(*r1.bucket_, r1.node_, node_ptr()); + this->delete_to_bucket_end(r1.node_); + + bucket_ptr i = r1.bucket_; + for(++i; i != r2.bucket_; ++i) { + this->size_ -= node_count(i->next_, node_ptr()); + this->clear_bucket(i); + } + + if(!r2.is_end()) { + node_ptr first = r2.bucket_->next_; + this->size_ -= node_count(r2.bucket_->next_, r2.node_); + node::unlink_nodes(*r2.bucket_, r2.node_); + this->delete_nodes(first, r2.node_); + } + + // r1 has been invalidated but its bucket is still + // valid. + this->recompute_begin_bucket(r1.bucket_, r2.bucket_); + } + } + + return r2; + } + + + template + inline void hash_table::recompute_begin_bucket() + { + if (this->size_ != 0) { + this->cached_begin_bucket_ = this->buckets_begin(); + while (!this->cached_begin_bucket_->next_) + ++this->cached_begin_bucket_; + } else { + this->cached_begin_bucket_ = this->buckets_end(); + } + } + + // 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 + + 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->buckets_end(); + } + } + } + + // 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_); + } + }} #endif diff --git a/include/boost/unordered/detail/util.hpp b/include/boost/unordered/detail/util.hpp index 5b0778ee..b6827b27 100644 --- a/include/boost/unordered/detail/util.hpp +++ b/include/boost/unordered/detail/util.hpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #if !defined(BOOST_UNORDERED_STD_FORWARD) @@ -210,20 +210,20 @@ namespace boost { namespace unordered_detail { template class hash_node_constructor { - typedef hash_table_manager manager; - typedef BOOST_DEDUCED_TYPENAME manager::node node; - typedef BOOST_DEDUCED_TYPENAME manager::real_node_ptr real_node_ptr; - typedef BOOST_DEDUCED_TYPENAME manager::value_type value_type; + 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; - manager& manager_; + buckets& buckets_; real_node_ptr node_; bool node_constructed_; bool value_constructed_; public: - hash_node_constructor(manager& m) : - manager_(m), + hash_node_constructor(buckets& m) : + buckets_(m), node_(), node_constructed_(false), value_constructed_(false) @@ -281,12 +281,12 @@ namespace boost { namespace unordered_detail { } // no throw - BOOST_DEDUCED_TYPENAME manager::node_ptr release() + BOOST_DEDUCED_TYPENAME buckets::node_ptr release() { real_node_ptr p = node_; node_ = real_node_ptr(); // node_ptr cast - return manager_.bucket_alloc().address(*p); + return buckets_.bucket_alloc().address(*p); } private: @@ -305,9 +305,9 @@ namespace boost { namespace unordered_detail { } if (node_constructed_) - manager_.node_alloc().destroy(node_); + buckets_.node_alloc().destroy(node_); - manager_.node_alloc().deallocate(node_, 1); + buckets_.node_alloc().deallocate(node_, 1); } } @@ -318,8 +318,8 @@ namespace boost { namespace unordered_detail { node_constructed_ = false; value_constructed_ = false; - node_ = manager_.node_alloc().allocate(1); - manager_.node_alloc().construct(node_, node()); + node_ = buckets_.node_alloc().allocate(1); + buckets_.node_alloc().construct(node_, node()); node_constructed_ = true; } else { From 78b078f41d10f89127a08f60aaaef44c6540a551 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 20 Sep 2009 21:55:15 +0000 Subject: [PATCH 103/471] Since all the compilers support out of line template members use them and lots of other things. [SVN r56329] --- .../unordered/detail/allocator_helpers.hpp | 3 +- include/boost/unordered/detail/buckets.hpp | 325 ++--- include/boost/unordered/detail/equivalent.hpp | 271 ++++ .../boost/unordered/detail/extract_key.hpp | 25 +- include/boost/unordered/detail/fwd.hpp | 715 +++++++--- include/boost/unordered/detail/insert.hpp | 678 ---------- include/boost/unordered/detail/move.hpp | 2 + include/boost/unordered/detail/node.hpp | 157 +-- include/boost/unordered/detail/table.hpp | 1176 +++++++++-------- include/boost/unordered/detail/unique.hpp | 431 ++++++ include/boost/unordered/detail/util.hpp | 108 +- include/boost/unordered/unordered_map.hpp | 320 +++-- include/boost/unordered/unordered_set.hpp | 295 +++-- test/helpers/list.hpp | 13 +- test/unordered/erase_equiv_tests.cpp | 2 +- test/unordered/out_of_line.cpp | 2 +- 16 files changed, 2462 insertions(+), 2061 deletions(-) create mode 100644 include/boost/unordered/detail/equivalent.hpp delete mode 100644 include/boost/unordered/detail/insert.hpp create mode 100644 include/boost/unordered/detail/unique.hpp diff --git a/include/boost/unordered/detail/allocator_helpers.hpp b/include/boost/unordered/detail/allocator_helpers.hpp index 092e78af..2c642231 100644 --- a/include/boost/unordered/detail/allocator_helpers.hpp +++ b/include/boost/unordered/detail/allocator_helpers.hpp @@ -99,7 +99,8 @@ namespace boost { namespace unordered_detail { } private: allocator_array_constructor(allocator_array_constructor const&); - allocator_array_constructor& operator=(allocator_array_constructor const&); + allocator_array_constructor& operator=( + allocator_array_constructor const&); }; }} diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index 29fedd29..fed14388 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -14,23 +14,123 @@ namespace boost { namespace unordered_detail { //////////////////////////////////////////////////////////////////////////// - // Explicitly call a destructor - -#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(); + // Buckets + // TODO: Are these needed? + + template + inline BOOST_DEDUCED_TYPENAME hash_buckets::bucket_ptr + hash_buckets::get_bucket(std::size_t n) const + { + return buckets_ + static_cast(n); } -#endif - - // Constructors template - hash_buckets::hash_buckets(node_allocator const& a, std::size_t bucket_count) - : buckets_(), allocators_(a,a) + 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 n) const + { + return buckets_ ? get_bucket(n)->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 node = begin; + begin = begin->next_; + delete_node(node); + ++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. @@ -38,52 +138,27 @@ namespace boost { namespace unordered_detail { constructor(bucket_alloc()); // Creates an extra bucket to act as a sentinel. - constructor.construct(bucket(), bucket_count + 1); + constructor.construct(bucket(), this->bucket_count_ + 1); // Set up the sentinel (node_ptr cast) - bucket_ptr sentinel = constructor.get() + static_cast(bucket_count); + 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(); - this->bucket_count_ = bucket_count; } - template - hash_buckets::hash_buckets(hash_buckets& x, move_tag) - : buckets_(), allocators_(x.allocators_) - { - this->buckets_ = x.buckets_; - this->bucket_count_ = x.bucket_count_; - x.buckets_ = bucket_ptr(); - x.bucket_count_ = 0; - } - - template - hash_buckets::hash_buckets(hash_buckets& x, value_allocator const& a, move_tag) : - buckets_(), allocators_(a,a) - { - if(this->node_alloc() == x.node_alloc()) { - this->buckets_ = x.buckets_; - this->bucket_count_ = x.bucket_count_; - x.buckets_ = bucket_ptr(); - x.bucket_count_ = 0; - } - } - - template - hash_buckets::~hash_buckets() - { - if(this->buckets_) { delete_buckets(); } - } + //////////////////////////////////////////////////////////////////////////// + // Constructors and Destructors // no throw template inline void hash_buckets::move(hash_buckets& other) { BOOST_ASSERT(node_alloc() == other.node_alloc()); - delete_buckets(); + if(this->buckets_) { this->delete_buckets(); } this->buckets_ = other.buckets_; this->bucket_count_ = other.bucket_count_; other.buckets_ = bucket_ptr(); @@ -97,166 +172,6 @@ namespace boost { namespace unordered_detail { std::swap(buckets_, other.buckets_); std::swap(bucket_count_, other.bucket_count_); } - - // Buckets - - template - inline std::size_t hash_buckets::bucket_count() const - { - return bucket_count_; - } - - template - inline std::size_t hash_buckets::bucket_from_hash(std::size_t hashed) const - { - return hashed % bucket_count_; - } - - template - inline BOOST_DEDUCED_TYPENAME hash_buckets::bucket_ptr - hash_buckets::bucket_ptr_from_hash(std::size_t hashed) const - { - return buckets_ + static_cast( - bucket_from_hash(hashed)); - } - - template - inline BOOST_DEDUCED_TYPENAME hash_buckets::bucket_ptr - hash_buckets::buckets_begin() const - { - return buckets_; - } - - template - inline BOOST_DEDUCED_TYPENAME hash_buckets::bucket_ptr - hash_buckets::buckets_end() const - { - return buckets_ + static_cast(bucket_count_); - } - - template - inline std::size_t hash_buckets::bucket_size(std::size_t index) const - { - bucket_ptr ptr = (buckets_ + static_cast(index))->next_; - std::size_t count = 0; - while(ptr) { - ++count; - ptr = next_node(ptr); - } - return count; - } - - template - inline BOOST_DEDUCED_TYPENAME hash_buckets::bucket_ptr - hash_buckets::get_bucket(std::size_t n) const - { - return buckets_ + static_cast(n); - } - - template - inline BOOST_DEDUCED_TYPENAME hash_buckets::node_ptr - hash_buckets::bucket_begin(std::size_t n) const - { - return (buckets_ + static_cast(n))->next_; - } - - template - inline BOOST_DEDUCED_TYPENAME hash_buckets::node_ptr - hash_buckets::bucket_end(std::size_t) const - { - return node_ptr(); - } - - // Construct/destruct - - template - inline void hash_buckets::destruct_node(node_ptr b) - { - node* raw_ptr = static_cast(&*b); - BOOST_UNORDERED_DESTRUCT(&raw_ptr->value(), value_type); - real_node_ptr n(node_alloc().address(*raw_ptr)); - node_alloc().destroy(n); - node_alloc().deallocate(n, 1); - } - - // Delete and clear buckets - - template - inline void hash_buckets::delete_group(node_ptr first_node) - { - delete_nodes(first_node, node::next_group(first_node)); - } - - template - inline void hash_buckets::delete_nodes(node_ptr begin, node_ptr end) - { - while(begin != end) { - node_ptr node = begin; - begin = next_node(begin); - destruct_node(node); - } - } - - template - inline void hash_buckets::delete_to_bucket_end(node_ptr begin) - { - while(BOOST_UNORDERED_BORLAND_BOOL(begin)) { - node_ptr node = begin; - begin = next_node(begin); - destruct_node(node); - } - } - - 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_destruct = node_it; - node_it = next_node(node_it); - destruct_node(node_to_destruct); - } - } - - template - inline void hash_buckets::delete_buckets() - { - for(bucket_ptr begin = this->buckets_begin(), end = this->buckets_end(); begin != end; ++begin) { - clear_bucket(begin); - } - - // Destroy the buckets (including the sentinel bucket). - bucket_ptr end = this->buckets_end(); - ++end; - for(bucket_ptr begin = this->buckets_begin(); begin != end; ++begin) { - bucket_alloc().destroy(begin); - } - - bucket_alloc().deallocate(this->buckets_begin(), this->bucket_count() + 1); - - this->buckets_ = bucket_ptr(); - } - - //////////////////////////////////////////////////////////////////////////// - // hash_iterator_base implementation - - template - inline void hash_iterator_base::increment(node_ptr node) { - while(!node) { - ++bucket_; - node = bucket_->next_; - } - - node_ = node; - } - - template - inline void hash_iterator_base::increment() - { - increment(next_node(node_)); - } }} #endif diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp new file mode 100644 index 00000000..efb3a688 --- /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, n, _) \ + template \ + template \ + BOOST_DEDUCED_TYPENAME hash_equivalent_table::iterator_base \ + hash_equivalent_table \ + ::emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + node_constructor a(*this); \ + a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \ + 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, n)) \ + { \ + node_constructor a(*this); \ + 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 + + //////////////////////////////////////////////////////////////////////////// + // 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 index 63dce95e..cba889eb 100644 --- a/include/boost/unordered/detail/extract_key.hpp +++ b/include/boost/unordered/detail/extract_key.hpp @@ -66,6 +66,11 @@ namespace unordered_detail { return no_key(); } #endif + + static bool compare_mapped(value_type const&, value_type const&) + { + return true; + } }; }; @@ -75,7 +80,9 @@ namespace unordered_detail { struct apply { typedef ValueType value_type; - typedef BOOST_DEDUCED_TYPENAME remove_const::type key_type; + typedef BOOST_DEDUCED_TYPENAME + remove_const::type + key_type; static key_type const& extract(value_type const& v) { @@ -94,19 +101,22 @@ namespace unordered_detail { } template - static key_type const& extract(std::pair const& v) + static key_type const& extract( + std::pair const& v) { return v.first; } /* template - static key_type const& extract(std::pair const& v) + static key_type const& extract( + std::pair const& v) { return v.first; } template - static key_type const& extract(std::pair const& v) + static key_type const& extract( + std::pair const& v) { return v.first; } @@ -114,7 +124,8 @@ namespace unordered_detail { #if defined(BOOST_UNORDERED_STD_FORWARD) template - static key_type const& extract(key_type const& k, Arg1 const&, Args const&...) + static key_type const& extract(key_type const& k, + Arg1 const&, Args const&...) { return k; } @@ -149,6 +160,10 @@ namespace unordered_detail { } #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 7cd56174..15924676 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -18,6 +18,7 @@ #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 @@ -31,8 +32,6 @@ // G = Grouped/Ungrouped // K = Key Extractor -#include - #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. @@ -45,12 +44,51 @@ #define BOOST_UNORDERED_EMPLACE_LIMIT 10 #endif +#if !defined(BOOST_UNORDERED_STD_FORWARD) + +#include +#include +#include + +#define BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + BOOST_PP_ENUM_PARAMS_Z(z, n, class 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 + namespace boost { namespace unordered_detail { static const float minimum_max_load_factor = 1e-3f; - static const std::size_t default_initial_bucket_count = 11; + 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 @@ -70,8 +108,11 @@ namespace boost { namespace unordered_detail { hash_bucket() : next_() {} // Only copy construct when allocating. - hash_bucket(hash_bucket const& x) : next_() - { BOOST_ASSERT(!x.next_); } + hash_bucket(hash_bucket const& x) + : next_() + { + BOOST_ASSERT(!x.next_); + } }; template @@ -84,12 +125,10 @@ namespace boost { namespace unordered_detail { 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_group_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 node); static void unlink_nodes(bucket& b, node_ptr begin, node_ptr end); static void unlink_nodes(bucket& b, node_ptr end); - static inline void unlink_group(node_ptr* b); }; template @@ -102,21 +141,20 @@ namespace boost { namespace unordered_detail { node_ptr group_prev_; grouped_node_base() : bucket(), group_prev_() {} - static inline node_ptr& group_prev(node_ptr ptr); 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_group_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 node); static void unlink_nodes(bucket& b, node_ptr begin, node_ptr end); static void unlink_nodes(bucket& b, node_ptr end); - static inline void unlink_group(node_ptr* b); private: static inline node_ptr split_group(node_ptr split); - static inline grouped_node_base& get(node_ptr ptr) - { return static_cast(*ptr); } + static inline grouped_node_base& get(node_ptr ptr) { + return static_cast(*ptr); + } }; struct ungrouped @@ -143,44 +181,73 @@ namespace boost { namespace unordered_detail { sizeof(value_type), ::boost::alignment_of::value>::type data_; - void* address() { return this; } - value_type& value() { return *(ValueType*) this; } + void* address() { + return this; + } + value_type& value() { + return *(ValueType*) this; + } }; // Node - - template - class hash_node : public NodeBase, public value_base + + template + class hash_node : + public G::BOOST_NESTED_TEMPLATE base::type, + public value_base { public: - typedef ValueType value_type; - typedef BOOST_DEDUCED_TYPENAME NodeBase::node_ptr node_ptr; + 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(); } + static value_type& get_value(node_ptr p) { + return static_cast(*p).value(); + } }; // Iterator Base - template + template class hash_iterator_base { public: - typedef BucketPtr bucket_ptr; - typedef BucketPtr node_ptr; + 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->next_) {} - hash_iterator_base(bucket_ptr b, node_ptr n) : bucket_(b), node_(n) {} + 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_; } - bool is_end() const { return node_ == bucket_; } - node_ptr get() const { return node_; } - void increment(node_ptr node); - void increment(); + 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 node) { + while(!node) { + ++bucket_; + node = bucket_->next_; + } + node_ = bucket_ == node ? node_ptr() : node; + } + + void increment() { + increment_bucket(node_->next_); + } }; // hash_buckets @@ -188,9 +255,10 @@ namespace boost { namespace unordered_detail { // 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). + // 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 @@ -201,22 +269,19 @@ namespace boost { namespace unordered_detail { // Types typedef A value_allocator; - typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; - typedef hash_bucket bucket; - typedef BOOST_DEDUCED_TYPENAME G::BOOST_NESTED_TEMPLATE base::type - node_base; - typedef hash_node node; + 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 rebind_wrap::type + node_allocator; typedef BOOST_DEDUCED_TYPENAME node_allocator::pointer real_node_ptr; - typedef hash_iterator_base iterator_base; - // Members bucket_ptr buckets_; @@ -225,124 +290,194 @@ namespace boost { namespace unordered_detail { // 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(); } + 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 - // - // The copy constructor doesn't copy the buckets. hash_buckets(node_allocator const& a, std::size_t n); - hash_buckets(hash_buckets& x, move_tag m); - hash_buckets(hash_buckets& x, value_allocator const& a, move_tag m); + void create_buckets(); ~hash_buckets(); // no throw void swap(hash_buckets& other); void move(hash_buckets& other); - // Buckets + // For the remaining functions, buckets_ must not be null. - std::size_t bucket_count() const; - std::size_t bucket_from_hash(std::size_t hashed) const; - bucket_ptr bucket_ptr_from_hash(std::size_t hashed) const; - bucket_ptr buckets_begin() const; - bucket_ptr buckets_end() const; - std::size_t bucket_size(std::size_t index) const; 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; - node_ptr bucket_end(std::size_t) const; // Alloc/Dealloc - void destruct_node(node_ptr); + void delete_node(node_ptr); // void delete_buckets(); void clear_bucket(bucket_ptr); - void delete_group(node_ptr first_node); - void delete_nodes(node_ptr begin, node_ptr end); - void delete_to_bucket_end(node_ptr begin); + 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_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 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; - - // Types for storing functions - - typedef boost::compressed_pair functions; - typedef bool functions_ptr; - - typedef BOOST_DEDUCED_TYPENAME boost::aligned_storage< - sizeof(functions), - ::boost::alignment_of::value>::type aligned_function; + typedef BOOST_DEDUCED_TYPENAME buckets::node_allocator node_allocator; + typedef hash_node_constructor node_constructor; + typedef std::pair iterator_pair; // Members - bool func_; // The currently active functions. - aligned_function funcs_[2]; - bucket_ptr cached_begin_bucket_; std::size_t size_; float mlf_; + // Cached data - invalid if !this->buckets_ + bucket_ptr cached_begin_bucket_; std::size_t max_load_; - - // Buffered Functions - - functions* get_functions(bool which) { - return static_cast(static_cast(&this->funcs_[which])); - } - functions const* get_functions(bool which) const { - return static_cast(static_cast(&this->funcs_[which])); - } - functions const& current() const { - return *this->get_functions(this->func_); - } - hasher const& hash_function() const { - return this->current().first(); - } - key_equal const& key_eq() const { - return this->current().second(); - } - functions_ptr buffer_functions(hash_table const& x) { - functions_ptr ptr = !func_; - *this->get_functions(ptr) = x.current(); - return ptr; - } - void set_functions(functions_ptr ptr) { - BOOST_ASSERT(ptr != func_); - func_ = ptr; - } // 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; @@ -354,31 +489,40 @@ namespace boost { namespace unordered_detail { 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; - void calculate_max_load(); + std::size_t calculate_max_load(); // Constructors - hash_table(std::size_t n, hasher const& hf, key_equal const& eq, value_allocator const& a); - hash_table(hash_table const& x); - hash_table(hash_table const& x, value_allocator const& a); + 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, value_allocator const& a, move_tag m); - ~hash_table(); + 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 iterator_base(this->cached_begin_bucket_); } - iterator_base end() const { return iterator_base(this->buckets_end()); } + 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 - bool reserve(std::size_t n); + 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); @@ -393,7 +537,7 @@ namespace boost { namespace unordered_detail { 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; - std::pair equal_range(key_type const& k) const; + iterator_pair equal_range(key_type const& k) const; // Erase // @@ -407,7 +551,7 @@ namespace boost { namespace unordered_detail { // recompute_begin_bucket - void 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 @@ -424,6 +568,203 @@ namespace boost { namespace unordered_detail { // 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 + iterator_base emplace_hint(iterator_base const&, 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 + template + emplace_return emplace(Arg0 const& arg0); + template + iterator_base emplace_hint(iterator_base const&, Arg0 const& arg0); + +#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ + template \ + emplace_return emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \ + template \ + iterator_base emplace_hint(iterator_base const& it, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \ + BOOST_UNORDERED_INSERT_IMPL2(z, n, _) + +#define BOOST_UNORDERED_INSERT_IMPL2(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_UNORDERED_INSERT_IMPL2(1, 1, _) + + BOOST_PP_REPEAT_FROM_TO(2, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_INSERT_IMPL, _) + +#undef BOOST_UNORDERED_INSERT_IMPL +#undef BOOST_UNORDERED_INSERT_IMPL2 + +#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 @@ -432,7 +773,9 @@ namespace boost { namespace unordered_detail { { public: template - static BOOST_DEDUCED_TYPENAME Iterator::base const& get(Iterator const& it) { + static BOOST_DEDUCED_TYPENAME Iterator::base const& + get(Iterator const& it) + { return it.base_; } }; @@ -462,25 +805,39 @@ namespace boost { namespace unordered_detail { private: typedef hash_buckets buckets; - typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr ptr; + 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; - ptr ptr_; + node_ptr ptr_; public: hash_local_iterator() : ptr_() {} - explicit hash_local_iterator(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_ = next_node(ptr_); return *this; } - hash_local_iterator operator++(int) { hash_local_iterator tmp(ptr_); ptr_ = next_node(ptr_); 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_; } + 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 @@ -508,14 +865,30 @@ namespace boost { namespace unordered_detail { 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_ = next_node(ptr_); return *this; } - hash_const_local_iterator operator++(int) { hash_const_local_iterator tmp(ptr_); ptr_ = next_node(ptr_); 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_; } + 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 @@ -547,15 +920,30 @@ namespace boost { namespace unordered_detail { hash_iterator() : base_() {} explicit hash_iterator(base const& x) : base_(x) {} - BOOST_DEDUCED_TYPENAME A::reference - operator*() const { return node::get_value(base_.get()); } - value_type* operator->() const { return &node::get_value(base_.get()); } - 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_; } + 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 @@ -584,15 +972,30 @@ namespace boost { namespace unordered_detail { 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 node::get_value(base_.get()); } - value_type const* operator->() const { return &node::get_value(base_.get()); } - 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_; } + 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_; + } }; }} diff --git a/include/boost/unordered/detail/insert.hpp b/include/boost/unordered/detail/insert.hpp deleted file mode 100644 index 28c27eb4..00000000 --- a/include/boost/unordered/detail/insert.hpp +++ /dev/null @@ -1,678 +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_INSERT_HPP_INCLUDED -#define BOOST_UNORDERED_DETAIL_INSERT_HPP_INCLUDED - -#include -#include - -namespace boost { namespace unordered_detail { - - //////////////////////////////////////////////////////////////////////////// - // A couple of convenience methods for adding nodes. - - // H = Has Func - // P = Predicate - // A = Value Allocator - // K = Key Extractor - - 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; - - // 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) {} - 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 - - std::pair emplace_impl_with_node(node_constructor& a); - value_type& operator[](key_type const& k); - - // equals - - bool equals(hash_unique_table const&) const; - static bool group_equals(node_ptr it1, node_ptr it2, set_extractor*); - static bool group_equals(node_ptr it1, node_ptr it2, map_extractor*); - - inline node_ptr 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; - } - -#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( - extractor::extract(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( - extractor::extract(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 - 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 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(*this); - a.construct(std::forward(args)...); - - // reserve has basic exception safety if the hash function - // throws, strong otherwise. - if(reserve_for_insert(this->size_ + 1)) - bucket = this->bucket_ptr_from_hash(hash_value); - - // Nothing after this point can throw. - - return std::pair(iterator_base(bucket, - add_node(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(*this); - a.construct(std::forward(args)...); - return emplace_impl_with_node(a); - } -#else - template - std::pair emplace(Arg0 const& arg0) - { - return emplace_impl(extractor::extract(arg0), arg0); - } - - template - iterator_base emplace_hint(iterator_base const&, Arg0 const& arg0) - { - return emplace_impl(extractor::extract(arg0), arg0).first; - } - -#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ - template \ - std::pair emplace( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - return emplace_impl(extractor::extract(arg0, arg1), \ - BOOST_UNORDERED_CALL_PARAMS(z, n)); \ - } \ - \ - template \ - iterator_base emplace_hint(iterator_base const& it, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - return emplace_impl(extractor::extract(arg0, arg1), \ - BOOST_UNORDERED_CALL_PARAMS(z, n)).first; \ - } \ - BOOST_UNORDERED_INSERT_IMPL2(z, n, _) - -#define BOOST_UNORDERED_INSERT_IMPL2(z, n, _) \ - template \ - std::pair emplace_impl(key_type const& k, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - 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 std::pair( \ - iterator_base(bucket, pos), false); \ - } else { \ - node_constructor a(*this); \ - a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \ - \ - if(reserve_for_insert(this->size_ + 1)) \ - bucket = this->bucket_ptr_from_hash(hash_value); \ - \ - return std::pair(iterator_base(bucket, \ - add_node(a, bucket)), true); \ - } \ - } \ - \ - template \ - std::pair emplace_impl(no_key, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ - { \ - node_constructor a(*this); \ - 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 - - // 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(extractor::extract(*i), i, j); - } - - template - void insert_range_impl(key_type const&, InputIterator i, InputIterator j) - { - node_constructor a(*this); - - for (; i != j; ++i) { - // No side effects in this initial code - std::size_t hash_value = this->hash_function()(extractor::extract(*i)); - bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); - node_ptr pos = find_iterator(bucket, extractor::extract(*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(this->size_ + 1 >= this->max_load_) { - 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 - void insert_range_impl(no_key, InputIterator i, InputIterator j) - { - node_constructor a(*this); - - for (; i != j; ++i) { - // No side effects in this initial code - a.construct(*i); - emplace_impl_with_node(a); - } - } - }; - - 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 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; - - // 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) {} - 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; - static bool group_equals(node_ptr it1, node_ptr it2, set_extractor*); - static bool group_equals(node_ptr it1, node_ptr it2, map_extractor*); - - inline node_ptr 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; - } - - public: - - // Insert functions - // - // basic exception safety, if hash function throws - // strong otherwise. - -#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(*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 - 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(*this); - a.construct(std::forward(args)...); - - return emplace_hint_impl(it, a); - } - -#else - -#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ - template \ - iterator_base emplace( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - node_constructor a(*this); \ - a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \ - return emplace_impl(a); \ - } \ - \ - template \ - iterator_base emplace_hint(iterator_base const& it, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - node_constructor a(*this); \ - 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 - - // 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) - { - std::size_t distance = unordered_detail::distance(i, j); - if(distance == 1) { - emplace(*i); - } - else { - // Only require basic exception safety here - reserve_for_insert(this->size_ + distance); - node_constructor a(*this); - - 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 - void 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); - } - } - - 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); - } - }; - - //////////////////////////////////////////////////////////////////////////// - // Unique insert methods - - template - std::pair< - BOOST_DEDUCED_TYPENAME hash_unique_table::iterator_base, - bool> - hash_unique_table - ::emplace_impl_with_node(node_constructor& a) - { - // No side effects in this initial code - key_type const& k = extractor::extract(a.get()->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 std::pair( - iterator_base(bucket, pos), false); - } else { - // reserve has basic exception safety if the hash function - // throws, strong otherwise. - if(reserve_for_insert(this->size_ + 1)) - bucket = this->bucket_ptr_from_hash(hash_value); - - // Nothing after this point can throw. - - return std::pair(iterator_base(bucket, - add_node(a, bucket)), true); - } - } - - // 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); - 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(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)); - } - } - - //////////////////////////////////////////////////////////////////////////// - // Insert methods - - template - BOOST_DEDUCED_TYPENAME hash_equivalent_table::iterator_base - hash_equivalent_table - ::emplace_impl(node_constructor& a) - { - key_type const& k = extractor::extract(a.get()->value()); - std::size_t hash_value = this->hash_function()(k); - 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(reserve_for_insert(this->size_ + 1)) - bucket = this->bucket_ptr_from_hash(hash_value); - - // I'm relying on node_ptr not being invalidated by - // the rehash here. - return iterator_base(bucket, add_node(a, bucket, position)); - } - - template - 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.is_end() || - !equal(extractor::extract(a.get()->value()), node::get_value(it.get()))) { - // 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(it.node_); - while(node::next_group(start) == start) - start = node::group_prev(start); - - // reserve has basic exception safety if the hash function - // throws, strong otherwise. - bucket_ptr bucket = reserve_for_insert(this->size_ + 1) ? - get_bucket(this->bucket_index( - extractor::extract(a.get()->value()))) : it.bucket_; - - // Nothing after this point can throw - - return iterator_base(bucket, add_node(a, bucket, start)); - } - } - - template - void hash_equivalent_table - ::emplace_impl_no_rehash(node_constructor& a) - { - key_type const& k = extractor::extract(a.get()->value()); - bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); - add_node(a, bucket, find_iterator(bucket, k)); - } - - //////////////////////////////////////////////////////////////////////////// - // Equalilty check - - template - inline bool hash_equivalent_table - ::group_equals(node_ptr it1, node_ptr it2, set_extractor*) - { - return node::group_count(it1) == node::group_count(it2); - } - - template - inline bool hash_equivalent_table - ::group_equals(node_ptr it1, node_ptr it2, map_extractor*) - { - node_ptr end1 = node::next_group(it1); - node_ptr end2 = node::next_group(it2); - - do { - if(node::get_value(it1).second != node::get_value(it2).second) return false; - it1 = next_node(it1); - it2 = next_node(it2); - } while(it1 != end1 && it2 != end2); - return it1 == end1 && it2 == end2; - } - - template - bool hash_equivalent_table - ::equals(hash_equivalent_table const& other) const - { - if(this->size_ != other.size_) return false; - - for(bucket_ptr i = this->cached_begin_bucket_, j = this->buckets_end(); i != j; ++i) - { - for(node_ptr it(i->next_); BOOST_UNORDERED_BORLAND_BOOL(it); it = node::next_group(it)) - { - node_ptr other_pos = other.find_iterator(extractor::extract(node::get_value(it))); - if(!BOOST_UNORDERED_BORLAND_BOOL(other_pos) || - !group_equals(it, other_pos, (K*)0)) - return false; - } - } - - return true; - } - - template - inline bool hash_unique_table - ::group_equals(node_ptr, node_ptr, set_extractor*) - { - return true; - } - - template - inline bool hash_unique_table - ::group_equals(node_ptr it1, node_ptr it2, map_extractor*) - { - return node::get_value(it1).second == node::get_value(it2).second; - } - - template - bool hash_unique_table - ::equals(hash_unique_table const& other) const - { - if(this->size_ != other.size_) return false; - - for(bucket_ptr i = this->cached_begin_bucket_, j = this->buckets_end(); i != j; ++i) - { - for(node_ptr it(i->next_); BOOST_UNORDERED_BORLAND_BOOL(it); it = node::next_group(it)) - { - node_ptr other_pos = other.find_iterator(extractor::extract(node::get_value(it))); - if(!BOOST_UNORDERED_BORLAND_BOOL(other_pos) || - !group_equals(it, other_pos, (K*)0)) - return false; - } - } - - return true; - } - -}} - -#endif diff --git a/include/boost/unordered/detail/move.hpp b/include/boost/unordered/detail/move.hpp index 317b20fd..16fd9212 100644 --- a/include/boost/unordered/detail/move.hpp +++ b/include/boost/unordered/detail/move.hpp @@ -109,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 index 90099f46..21645105 100644 --- a/include/boost/unordered/detail/node.hpp +++ b/include/boost/unordered/detail/node.hpp @@ -24,23 +24,6 @@ namespace boost { namespace unordered_detail { - template - inline BucketPtr& next_node(BucketPtr ptr) - { - return ptr->next_; - } - - template - inline std::size_t node_count(BucketPtr ptr, BucketPtr end) - { - std::size_t count = 0; - while(ptr != end) { - ++count; - ptr = next_node(ptr); - } - return count; - } - //////////////////////////////////////////////////////////////////////////// // ungrouped node implementation @@ -48,7 +31,7 @@ namespace boost { namespace unordered_detail { inline BOOST_DEDUCED_TYPENAME ungrouped_node_base::node_ptr& ungrouped_node_base::next_group(node_ptr ptr) { - return next_node(ptr); + return ptr->next_; } template @@ -60,35 +43,24 @@ namespace boost { namespace unordered_detail { template inline void ungrouped_node_base::add_to_bucket(node_ptr n, bucket& b) { - next_node(n) = b.next_; + n->next_ = b.next_; b.next_ = n; } template - inline void ungrouped_node_base::add_group_to_bucket(node_ptr n, bucket& b) + inline void ungrouped_node_base::add_after_node(node_ptr n, + node_ptr position) { - next_node(n) = b.next_; - b.next_ = n; - } - - template - inline void ungrouped_node_base::add_after_node(node_ptr n, node_ptr position) - { - next_node(n) = next_node(position); - next_node(position) = position; + n->next_ = position->next_; + position->next_ = position; } template - inline void ungrouped_node_base::unlink_node(bucket& b, node_ptr node) - { - unlink_nodes(b, node, next_node(node)); - } - - template - inline void ungrouped_node_base::unlink_nodes(bucket& b, node_ptr begin, node_ptr end) + inline void ungrouped_node_base::unlink_nodes(bucket& b, + node_ptr begin, node_ptr end) { node_ptr* pos = &b.next_; - while(*pos != begin) pos = &next_node(*pos); + while(*pos != begin) pos = &(*pos)->next_; *pos = end; } @@ -99,26 +71,30 @@ namespace boost { namespace unordered_detail { } template - inline void ungrouped_node_base::unlink_group(node_ptr* b) + inline void ungrouped_node_base::unlink_node(bucket& b, node_ptr node) { - *b = next_node(*b); + unlink_nodes(b, node, node->next_); } //////////////////////////////////////////////////////////////////////////// // grouped node implementation - template - inline BOOST_DEDUCED_TYPENAME grouped_node_base::node_ptr& - grouped_node_base::group_prev(node_ptr ptr) - { - return get(ptr).group_prev_; - } - + // 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 next_node(group_prev(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 @@ -128,7 +104,7 @@ namespace boost { namespace unordered_detail { std::size_t size = 0; do { ++size; - ptr = group_prev(ptr); + ptr = get(ptr).group_prev_; } while(ptr != start); return size; } @@ -136,25 +112,18 @@ namespace boost { namespace unordered_detail { template inline void grouped_node_base::add_to_bucket(node_ptr n, bucket& b) { - next_node(n) = b.next_; - group_prev(n) = n; + n->next_ = b.next_; + get(n).group_prev_ = n; b.next_ = n; } template - inline void grouped_node_base::add_group_to_bucket(node_ptr n, bucket& b) + inline void grouped_node_base::add_after_node(node_ptr n, node_ptr pos) { - next_group(n) = b.next_; - b.next_ = n; - } - - template - inline void grouped_node_base::add_after_node(node_ptr n, node_ptr position) - { - next_node(n) = next_group(position); - group_prev(n) = group_prev(position); - next_group(position) = n; - group_prev(position) = n; + 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 @@ -164,29 +133,21 @@ namespace boost { namespace unordered_detail { inline BOOST_DEDUCED_TYPENAME grouped_node_base::node_ptr grouped_node_base::split_group(node_ptr split) { - // If split is at the beginning of the group then there's - // nothing to split. - if(next_node(group_prev(split)) != split) - return split; + node_ptr first = first_in_group(split); + if(first == split) return split; - // Find the start of the group. - node_ptr start = split; - do { - start = group_prev(start); - } while(next_node(group_prev(start)) == start); + node_ptr last = get(first).group_prev_; + get(first).group_prev_ = get(split).group_prev_; + get(split).group_prev_ = last; - node_ptr last = group_prev(start); - group_prev(start) = group_prev(split); - group_prev(split) = last; - - return start; + return first; } template void grouped_node_base::unlink_node(bucket& b, node_ptr node) { - node_ptr next = next_node(node); - node_ptr* pos = &next_node(group_prev(node)); + node_ptr next = node->next_; + node_ptr* pos = &next_group(node); if(*pos != node) { // The node is at the beginning of a group. @@ -196,31 +157,37 @@ namespace boost { namespace unordered_detail { while(*pos != node) pos = &next_group(*pos); // Remove from group - if(BOOST_UNORDERED_BORLAND_BOOL(next) && group_prev(next) == node) - group_prev(next) = group_prev(node); + if(BOOST_UNORDERED_BORLAND_BOOL(next) && + get(next).group_prev_ == node) + { + get(next).group_prev_ = get(node).group_prev_; + } } - else if(BOOST_UNORDERED_BORLAND_BOOL(next) && group_prev(next) == node) { + else if(BOOST_UNORDERED_BORLAND_BOOL(next) && + get(next).group_prev_ == node) + { // The deleted node is not at the end of the group, so // change the link from the next node. - group_prev(next) = group_prev(node); + get(next).group_prev_ = get(node).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 = group_prev(node); - while(group_prev(x) != node) { - x = group_prev(x); + node_ptr x = get(node).group_prev_; + while(get(x).group_prev_ != node) { + x = get(x).group_prev_; } - group_prev(x) = group_prev(node); + get(x).group_prev_ = get(node).group_prev_; } *pos = next; } template - void grouped_node_base::unlink_nodes(bucket& b, node_ptr begin, node_ptr end) + void grouped_node_base::unlink_nodes(bucket& b, + node_ptr begin, node_ptr end) { - node_ptr* pos = &next_node(group_prev(begin)); + node_ptr* pos = &next_group(begin); if(*pos != begin) { // The node is at the beginning of a group. @@ -238,10 +205,10 @@ namespace boost { namespace unordered_detail { node_ptr group2 = split_group(end); if(begin == group2) { - node_ptr end1 = group_prev(group1); - node_ptr end2 = group_prev(group2); - group_prev(group1) = end2; - group_prev(group2) = end1; + node_ptr end1 = get(group1).group_prev_; + node_ptr end2 = get(group2).group_prev_; + get(group1).group_prev_ = end2; + get(group2).group_prev_ = end1; } } } @@ -254,12 +221,6 @@ namespace boost { namespace unordered_detail { split_group(end); b.next_ = end; } - - template - inline void grouped_node_base::unlink_group(node_ptr* b) - { - *b = next_group(*b); - } }} #endif diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index c3afb6b7..eb18926f 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -23,20 +23,22 @@ namespace boost { namespace unordered_detail { // strong exception safety, no side effects template - inline bool hash_table - ::equal(key_type const& k, value_type const& v) const + inline bool hash_table::equal( + key_type const& k, value_type const& v) const { - return this->key_eq()(k, extractor::extract(v)); + 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 + 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))) { + while (BOOST_UNORDERED_BORLAND_BOOL(it) && + !equal(k, node::get_value(it))) + { it = node::next_group(it); } @@ -44,23 +46,26 @@ 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 + 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 - BOOST_DEDUCED_TYPENAME hash_table::node_ptr* - hash_table - ::find_for_erase(bucket_ptr bucket, key_type const& k) const + 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))) + while(BOOST_UNORDERED_BORLAND_BOOL(*it) && + !equal(k, node::get_value(*it))) + { it = &node::next_group(*it); + } return it; } @@ -70,8 +75,7 @@ namespace boost { namespace unordered_detail { // no throw template - std::size_t hash_table - ::max_size() const + std::size_t hash_table::max_size() const { using namespace std; @@ -82,27 +86,37 @@ namespace boost { namespace unordered_detail { // strong safety template - std::size_t hash_table - ::bucket_index(key_type const& k) const + inline std::size_t hash_table::bucket_index( + key_type const& k) const { // hash_function can throw: - return this->bucket_from_hash(this->hash_function()(k)); + return this->hash_function()(k) % this->bucket_count_; } + // no throw template - void hash_table - ::max_load_factor(float z) + 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->calculate_max_load(); + this->max_load_ = this->calculate_max_load(); } // no throw template - std::size_t hash_table - ::min_buckets_for_size(std::size_t n) const + inline std::size_t hash_table::min_buckets_for_size( + std::size_t n) const { BOOST_ASSERT(this->mlf_ != 0); @@ -114,577 +128,27 @@ namespace boost { namespace unordered_detail { // // Or from rehash post-condition: // count > size / mlf_ - return double_to_size_t(floor(n / (double) mlf_)) + 1; - } - - // no throw - template - void hash_table - ::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_ * this->bucket_count())); + return next_prime(double_to_size_t(floor(n / (double) mlf_)) + 1); } //////////////////////////////////////////////////////////////////////////// - // Constructors + // recompute_begin_bucket + + // init_buckets template - hash_table - ::hash_table(std::size_t n, hasher const& hf, key_equal const& eq, value_allocator const& a) : - buckets(a, next_prime(n)), func_(false), cached_begin_bucket_(), size_(), mlf_(1.0f), max_load_(0) + inline void hash_table::init_buckets() { - std::uninitialized_fill((functions*)this->funcs_, (functions*)this->funcs_+2, - functions(hf, eq)); - this->cached_begin_bucket_ = this->buckets_end(); - this->calculate_max_load(); - } - - template - hash_table - ::hash_table(hash_table const& x) : - buckets(x.node_alloc(), next_prime(x.min_buckets_for_size(x.size_))), func_(false), cached_begin_bucket_(), size_(), mlf_(x.mlf_), max_load_(0) - { - std::uninitialized_fill((functions*)this->funcs_, (functions*)this->funcs_+2, - x.current()); - this->calculate_max_load(); - x.copy_buckets_to(*this); - this->size_ = x.size_; - this->recompute_begin_bucket(); - } - - // Copy Construct with allocator - - template - hash_table - ::hash_table(hash_table const& x, value_allocator const& a) : - buckets(a, next_prime(x.min_buckets_for_size(x.size_))), func_(false), cached_begin_bucket_(), size_(), mlf_(x.mlf_), max_load_(0) - { - std::uninitialized_fill((functions*)this->funcs_, (functions*)this->funcs_+2, - x.current()); - this->cached_begin_bucket_ = this->buckets_end(); - this->calculate_max_load(); - x.copy_buckets_to(*this); - this->size_ = x.size_; - this->recompute_begin_bucket(); - } - - // Move Construct - - template - hash_table - ::hash_table(hash_table& x, move_tag m) : - buckets(x, m), func_(false), cached_begin_bucket_(), size_(), mlf_(x.mlf_), max_load_(0) - { - this->cached_begin_bucket_ = x.cached_begin_bucket_; - this->size_ = x.size_; - x.cached_begin_bucket_ = bucket_ptr(); - x.size_ = 0; - - // TODO: Shouldn't I move the functions if poss. - std::uninitialized_fill((functions*)this->funcs_, (functions*)this->funcs_+2, - x.current()); - } - - template - hash_table - ::hash_table(hash_table& x, value_allocator const& a, move_tag m) : - buckets(x, a, m), func_(false), cached_begin_bucket_(), size_(), mlf_(x.mlf_), max_load_(0) - { - std::uninitialized_fill((functions*)this->funcs_, (functions*)this->funcs_+2, - x.current()); - - this->calculate_max_load(); // no throw - - if(!this->buckets_) { - buckets new_buckets(this->node_alloc(), x.min_buckets_for_size(x.size_)); - x.copy_buckets_to(new_buckets); - new_buckets.swap(*this); - this->size_ = x.size_; - this->recompute_begin_bucket(); - } - else { - this->cached_begin_bucket_ = x.cached_begin_bucket_; - this->size_ = x.size_; - x.cached_begin_bucket_ = bucket_ptr(); - x.size_ = 0; - } - } - - template - hash_table::~hash_table() - { - BOOST_UNORDERED_DESTRUCT(this->get_functions(false), functions); - BOOST_UNORDERED_DESTRUCT(this->get_functions(true), functions); - } - - // TODO: Reuse current nodes amd buckets? - template - hash_table& hash_table::operator=(hash_table const& x) - { - if(this != &x) { - this->clear(); // no throw - this->set_functions( - this->buffer_functions(x)); // throws, strong - this->mlf_ = x.mlf_; // no throw - buckets new_buckets(this->node_alloc(), x.min_buckets_for_size(x.size_)); - x.copy_buckets_to(new_buckets); - new_buckets.swap(*this); - this->calculate_max_load(); // no throw - this->size_ = x.size_; - this->recompute_begin_bucket(); - } - - 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 - void hash_table - ::swap(hash_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 = this->buffer_functions(x); - functions_ptr new_func_that = x.buffer_functions(*this); - - if(this->node_alloc() == x.node_alloc()) { - this->buckets::swap(x); // No throw - std::swap(this->cached_begin_bucket_, x.cached_begin_bucket_); - std::swap(this->size_, x.size_); - } - else { - // 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 new_this(this->node_alloc(), x.min_buckets_for_size(x.size_)); - x.copy_buckets_to(new_this); - - buckets new_that(x.node_alloc(), this->min_buckets_for_size(this->size_)); - copy_buckets_to(new_that); - - // Modifying the data, so no throw from now on. - - this->buckets::swap(new_this); - x.buckets::swap(new_that); - std::swap(this->size_, x.size_); - this->recompute_begin_bucket(); - x.recompute_begin_bucket(); - } - - // The rest is no throw. - - std::swap(this->mlf_, x.mlf_); - - this->set_functions(new_func_this); - x.set_functions(new_func_that); - - //TODO: Test that this works: - this->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. - - 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. - functions_ptr new_func_this = this->buffer_functions(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_; - x.size_ = 0; - x.cached_begin_bucket_ = bucket_ptr(); - } - 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 new_this(this->node_alloc(), next_prime(x.min_buckets_for_size(x.size_))); - x.copy_buckets_to(new_this); - - // Start updating the data here, no throw from now on. - this->buckets::move(new_this); - this->size_ = x.size_; - this->recompute_begin_bucket(); - } - - // We've made it, the rest is no throw. - this->mlf_ = x.mlf_; - this->set_functions(new_func_this); - - this->calculate_max_load(); - } - - //////////////////////////////////////////////////////////////////////////// - // Reserve & Rehash - - // basic exception safety - template - inline bool hash_table - ::reserve(std::size_t n) - { - bool need_to_reserve = n >= this->max_load_; - // throws - basic: - if (need_to_reserve) rehash_impl(this->min_buckets_for_size(n)); - BOOST_ASSERT(n < this->max_load_ || n > max_size()); - return need_to_reserve; - } - - // basic exception safety - template - inline bool hash_table - ::reserve_for_insert(std::size_t n) - { - bool need_to_reserve = n >= this->max_load_; - // throws - basic: - if (need_to_reserve) { - std::size_t s = this->size_; - s = s + (s >> 1); - s = s > n ? s : n; - rehash_impl(this->min_buckets_for_size(s)); - } - BOOST_ASSERT(n < this->max_load_ || n > max_size()); - return need_to_reserve; - } - - // if hash function throws, basic exception safety - // strong otherwise. - template - void hash_table - ::rehash(std::size_t n) - { - using namespace std; - - // no throw: - std::size_t min_size = this->min_buckets_for_size(this->size_); - // basic/strong: - rehash_impl(min_size > n ? min_size : n); - - BOOST_ASSERT((float) this->bucket_count() > (float) this->size_ / this->mlf_ - && this->bucket_count() >= n); - } - - // if hash function throws, basic exception safety - // strong otherwise - - template - void hash_table - ::rehash_impl(std::size_t n) - { - n = next_prime(n); // no throw - - if (n == this->bucket_count()) // no throw - return; - - // Save the size to restore it if successful - std::size_t size = this->size_; - - // Create another buckets to move the nodes into. - buckets dst(this->node_alloc(), n);// throws, separate - - // Move the nodes to dst. - hasher const& hf = this->hash_function(); - bucket_ptr end = this->buckets_end(); - - for(; this->cached_begin_bucket_ != end; ++this->cached_begin_bucket_) { - bucket_ptr src_bucket = this->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(extractor::extract(node::get_value(src_bucket->next_)))); - - - node_ptr n = src_bucket->next_; - this->size_ -= node::group_count(n); - node::unlink_group(&src_bucket->next_); - node::add_group_to_bucket(n, *dst_bucket); - } - } - - // Swap the new nodes back into the container and setup the local - // variables. - dst.swap(*this); // no throw - this->size_ = size; - this->recompute_begin_bucket(); // no throw - this->calculate_max_load(); // no throw - } - - //////////////////////////////////////////////////////////////////////////// - // 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->buckets_end(); - - hash_node_constructor a(dst); - - // 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(extractor::extract(node::get_value(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 = next_node(it); it != group_end; it = next_node(it)) { - 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 - std::pair< - BOOST_DEDUCED_TYPENAME hash_table::iterator_base, - BOOST_DEDUCED_TYPENAME hash_table::iterator_base - > - hash_table - ::equal_range(key_type const& k) const - { - if(!this->size_) - return std::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(node::next_group(second.node_)); - return std::pair(first, second); - } - else { - return std::pair(this->end(), this->end()); - } - } - - //////////////////////////////////////////////////////////////////////////// - // Erase methods - - template - void hash_table::clear() - { - for(bucket_ptr begin = this->buckets_begin(), end = this->buckets_end(); begin != end; ++begin) { - this->clear_bucket(begin); - } - - this->cached_begin_bucket_ = this->buckets_end(); - this->size_ = 0; - } - - template - std::size_t hash_table - ::erase_key(key_type const& k) - { - // 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.is_end()); - iterator_base next = r; - next.increment(); - --this->size_; - node::unlink_node(*r.bucket_, r.node_); - this->destruct_node(r.node_); - // r has been invalidated but its bucket is still valid - this->recompute_begin_bucket(r.bucket_, next.bucket_); - return next; - } - - template - inline std::size_t hash_table::erase_group(node_ptr* it, bucket_ptr bucket) - { - node_ptr pos = *it; - std::size_t count = node::group_count(*it); - this->size_ -= count; - node::unlink_group(it); - this->delete_group(pos); - this->recompute_begin_bucket(bucket); - return count; - } - - template - BOOST_DEDUCED_TYPENAME hash_table::iterator_base - hash_table::erase_range(iterator_base r1, iterator_base r2) - { - if(r1 != r2) - { - BOOST_ASSERT(!r1.is_end()); - - if (r1.bucket_ == r2.bucket_) { - this->size_ -= node_count(r1.node_, r2.node_); - node::unlink_nodes(*r1.bucket_, r1.node_, r2.node_); - 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 { - BOOST_ASSERT(r1.bucket_ < r2.bucket_); - - this->size_ -= node_count(r1.node_, node_ptr()); - node::unlink_nodes(*r1.bucket_, r1.node_, node_ptr()); - this->delete_to_bucket_end(r1.node_); - - bucket_ptr i = r1.bucket_; - for(++i; i != r2.bucket_; ++i) { - this->size_ -= node_count(i->next_, node_ptr()); - this->clear_bucket(i); - } - - if(!r2.is_end()) { - node_ptr first = r2.bucket_->next_; - this->size_ -= node_count(r2.bucket_->next_, r2.node_); - node::unlink_nodes(*r2.bucket_, r2.node_); - this->delete_nodes(first, r2.node_); - } - - // r1 has been invalidated but its bucket is still - // valid. - this->recompute_begin_bucket(r1.bucket_, r2.bucket_); - } - } - - return r2; - } - - - template - inline void hash_table::recompute_begin_bucket() - { - if (this->size_ != 0) { - this->cached_begin_bucket_ = this->buckets_begin(); + 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->buckets_end(); + this->cached_begin_bucket_ = this->get_bucket(this->bucket_count_); } + this->max_load_ = calculate_max_load(); } - // recompute_begin_bucket - // // After an erase cached_begin_bucket_ might be left pointing to // an empty bucket, so this is called to update it // @@ -701,7 +165,8 @@ namespace boost { namespace unordered_detail { while (!this->cached_begin_bucket_->next_) ++this->cached_begin_bucket_; } else { - this->cached_begin_bucket_ = this->buckets_end(); + this->cached_begin_bucket_ = + this->get_bucket(this->bucket_count_); } } } @@ -711,7 +176,8 @@ namespace boost { namespace unordered_detail { // no throw template - inline void hash_table::recompute_begin_bucket(bucket_ptr b1, bucket_ptr b2) + 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_)); @@ -729,6 +195,550 @@ namespace boost { namespace unordered_detail { / static_cast(this->bucket_count_); } + //////////////////////////////////////////////////////////////////////////// + // Constructors + + template + hash_table::hash_table(std::size_t n, + hasher const& hf, key_equal const& eq, node_allocator const& a) + : buckets(a, next_prime(n)), + 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 n) + { + if(n > this->bucket_count_) + this->bucket_count_ = this->min_buckets_for_size(n); + this->create_buckets(); + this->init_buckets(); + } + + // basic exception safety + template + inline bool hash_table::reserve_for_insert(std::size_t n) + { + if(n >= max_load_) { + std::size_t s = this->size_; + s = s + (s >> 1); + n = this->min_buckets_for_size(s > n ? s : n); + if(n != this->bucket_count_) { + rehash_impl(n); + 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 n) + { + using namespace std; + + if(!this->buckets_) { + this->bucket_count_ = next_prime(n); + this->create_buckets(); + this->init_buckets(); + } + else if(n != this->bucket_count_) { + // no throw: + // TODO: Needlessly calling next_prime twice. + std::size_t min_size = this->min_buckets_for_size(this->size_); + n = next_prime(n); + n = min_size > n ? min_size : n; + + rehash_impl(n); + } + } + + // if hash function throws, basic exception safety + // strong otherwise + + // TODO: Rewrite so that it doesn't need to keep updating size_. + + template + void hash_table + ::rehash_impl(std::size_t n) + { + 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(), n); + 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 n) + { + key_type const& k = get_key(a.value()); + std::size_t hash_value = this->hash_function()(k); + if(this->buckets_) this->reserve_for_insert(n); + else this->create_for_insert(n); + bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); + node_ptr node = a.release(); + node::add_to_bucket(node, *bucket); + ++this->size_; + this->cached_begin_bucket_ = bucket; + return iterator_base(bucket, node); + } }} #endif diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp new file mode 100644 index 00000000..0f5cf88f --- /dev/null +++ b/include/boost/unordered/detail/unique.hpp @@ -0,0 +1,431 @@ + +// 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, n, _) \ + 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, n)) \ + { \ + 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, n)); \ + \ + 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, n)) \ + { \ + node_constructor a(*this); \ + a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \ + 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, n)) \ + { \ + node_constructor a(*this); \ + a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \ + 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)...); + } + + // 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 + template + BOOST_DEDUCED_TYPENAME hash_unique_table::iterator_base + hash_unique_table::emplace_hint(iterator_base const&, + Args&&... args) + { + return this->size_ ? + emplace_impl( + extractor::extract(std::forward(args)...), + std::forward(args)...).first : + emplace_empty_impl(std::forward(args)...).first; + } + +#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); + } + + template + template + BOOST_DEDUCED_TYPENAME hash_unique_table::iterator_base + hash_unique_table::emplace_hint(iterator_base const&, + Arg0 const& arg0) + { + return this->size_ ? + emplace_impl(extractor::extract(arg0), arg0).first : + emplace_empty_impl(arg0).first; + } + +#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ + template \ + template \ + BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return \ + hash_unique_table::emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + return this->size_ ? \ + emplace_impl(extractor::extract(arg0, arg1), \ + BOOST_UNORDERED_CALL_PARAMS(z, n)) : \ + emplace_empty_impl( \ + BOOST_UNORDERED_CALL_PARAMS(z, n)); \ + } \ + \ + template \ + template \ + BOOST_DEDUCED_TYPENAME hash_unique_table::iterator_base \ + hash_unique_table:: \ + emplace_hint(iterator_base const& it, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + return this->size_ ? \ + emplace_impl(extractor::extract(arg0, arg1), \ + BOOST_UNORDERED_CALL_PARAMS(z, n)) : \ + emplace_empty_impl( \ + BOOST_UNORDERED_CALL_PARAMS(z, n)); \ + } \ + + 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 index b6827b27..9a70185e 100644 --- a/include/boost/unordered/detail/util.hpp +++ b/include/boost/unordered/detail/util.hpp @@ -14,22 +14,7 @@ #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, class 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 +#include namespace boost { namespace unordered_detail { @@ -38,7 +23,8 @@ namespace boost { namespace unordered_detail { inline std::size_t double_to_size_t(double f) { - return f >= static_cast((std::numeric_limits::max)()) ? + return f >= static_cast( + (std::numeric_limits::max)()) ? (std::numeric_limits::max)() : static_cast(f); } @@ -143,7 +129,7 @@ namespace boost { namespace unordered_detail { template inline std::size_t initial_size(I i, I j, - std::size_t n = boost::unordered_detail::default_initial_bucket_count) + std::size_t n = boost::unordered_detail::default_bucket_count) { return (std::max)(static_cast(insert_size(i, j)) + 1, n); } @@ -172,29 +158,29 @@ namespace boost { namespace unordered_detail { #else -#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, n, _) \ - template < \ - class T, \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - inline void construct_impl( \ - T*, void* address, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - new(address) T( \ - BOOST_UNORDERED_CALL_PARAMS(z, n)); \ - } \ - \ - template \ - inline void construct_impl( \ - std::pair*, void* address, \ - Key const& k, BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ - { \ - new(address) std::pair(k, \ - Second(BOOST_UNORDERED_CALL_PARAMS(z, n))); \ +#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, n, _) \ + template < \ + class T, \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + inline void construct_impl( \ + T*, void* address, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + new(address) T( \ + BOOST_UNORDERED_CALL_PARAMS(z, n)); \ + } \ + \ + template \ + inline void construct_impl( \ + std::pair*, void* address, \ + Key const& k, BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + new(address) std::pair(k, \ + Second(BOOST_UNORDERED_CALL_PARAMS(z, n))); \ } BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, @@ -244,20 +230,20 @@ namespace boost { namespace unordered_detail { } #else -#define BOOST_UNORDERED_CONSTRUCT(z, n, _) \ - template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - void construct( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - construct_preamble(); \ - construct_impl( \ - (value_type*) 0, node_->address(), \ - BOOST_UNORDERED_CALL_PARAMS(z, n) \ - ); \ - value_constructed_ = true; \ +#define BOOST_UNORDERED_CONSTRUCT(z, n, _) \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + void construct( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + ) \ + { \ + construct_preamble(); \ + construct_impl( \ + (value_type*) 0, node_->address(), \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + ); \ + value_constructed_ = true; \ } BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, @@ -274,10 +260,10 @@ namespace boost { namespace unordered_detail { value_constructed_ = true; } - real_node_ptr get() const + value_type& value() const { BOOST_ASSERT(node_); - return node_; + return node_->value(); } // no throw @@ -297,11 +283,11 @@ namespace boost { namespace unordered_detail { // hash_node_constructor template - hash_node_constructor::~hash_node_constructor() + inline hash_node_constructor::~hash_node_constructor() { if (node_) { if (value_constructed_) { - BOOST_UNORDERED_DESTRUCT(&node_->value(), value_type); + boost::unordered_detail::destroy(&node_->value()); } if (node_constructed_) @@ -312,7 +298,7 @@ namespace boost { namespace unordered_detail { } template - void hash_node_constructor::construct_preamble() + inline void hash_node_constructor::construct_preamble() { if(!node_) { node_constructed_ = false; @@ -324,7 +310,7 @@ namespace boost { namespace unordered_detail { } else { BOOST_ASSERT(node_constructed_ && value_constructed_); - BOOST_UNORDERED_DESTRUCT(&node_->value(), value_type); + boost::unordered_detail::destroy(&node_->value()); value_constructed_ = false; } } diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 8880a029..0e89d43a 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -16,7 +16,8 @@ #include #include #include -#include +#include +#include #if !defined(BOOST_HAS_RVALUE_REFS) #include @@ -53,32 +54,41 @@ namespace boost #endif typedef BOOST_DEDUCED_TYPENAME - boost::unordered_detail::rebind_wrap::type + boost::unordered_detail::rebind_wrap< + allocator_type, value_type>::type value_allocator; - typedef boost::unordered_detail::hash_unique_table table; + 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 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; + value_allocator, boost::unordered_detail::ungrouped> + const_local_iterator; typedef boost::unordered_detail::hash_local_iterator< - value_allocator, boost::unordered_detail::ungrouped> 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; + value_allocator, boost::unordered_detail::ungrouped> + const_iterator; typedef boost::unordered_detail::hash_iterator< - value_allocator, boost::unordered_detail::ungrouped> iterator; + value_allocator, boost::unordered_detail::ungrouped> + iterator; #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) private: @@ -97,49 +107,51 @@ namespace boost // construct/destroy/copy explicit unordered_map( - size_type n = boost::unordered_detail::default_initial_bucket_count, + 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) + : table_(n, hf, eql, a) { } explicit unordered_map(allocator_type const& a) - : table_(boost::unordered_detail::default_initial_bucket_count, + : 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) + : table_(other.table_, a) { } - template - unordered_map(InputIterator f, InputIterator l) - : table_(boost::unordered_detail::initial_size(f, l), hasher(), key_equal(), allocator_type()) + 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(InputIterator f, InputIterator 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_(boost::unordered_detail::initial_size(f, l, n), + hf, eql, allocator_type()) { table_.insert_range(f, l); } - template - unordered_map(InputIterator f, InputIterator 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_(boost::unordered_detail::initial_size(f, l, n), hf, eql, a) { table_.insert_range(f, l); } @@ -148,12 +160,12 @@ namespace boost #if defined(BOOST_HAS_RVALUE_REFS) unordered_map(unordered_map&& other) - : table_(other.table_, boost::unordered_detail::move_tag()) + : 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()) + : table_(other.table_, a, boost::unordered_detail::move_tag()) { } @@ -163,8 +175,10 @@ namespace boost return *this; } #else - unordered_map(boost::unordered_detail::move_from > other) - : table_(other.source.table_, boost::unordered_detail::move_tag()) + unordered_map(boost::unordered_detail::move_from< + unordered_map + > other) + : table_(other.source.table_, boost::unordered_detail::move_tag()) { } @@ -179,11 +193,13 @@ namespace boost #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) unordered_map(std::initializer_list list, - size_type n = boost::unordered_detail::default_initial_bucket_count, + 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_(boost::unordered_detail::initial_size( + list.begin(), list.end(), n), + hf, eql, allocator_type()) { table_.insert_range(list.begin(), list.end()); } @@ -263,7 +279,8 @@ namespace boost template iterator emplace_hint(const_iterator hint, Args&&... args) { - return iterator(table_.emplace_hint(get(hint), std::forward(args)...)); + return iterator( + table_.emplace_hint(get(hint), std::forward(args)...)); } #else @@ -273,35 +290,36 @@ namespace boost 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(table_.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( \ - 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) \ - )); \ +#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_hint(get(hint), \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + )); \ } BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, @@ -322,8 +340,8 @@ namespace boost return iterator(table_.emplace_hint(get(hint), obj)); } - template - void insert(InputIterator first, InputIterator last) + template + void insert(InputIt first, InputIt last) { table_.insert_range(first, last); } @@ -400,14 +418,16 @@ namespace boost std::pair equal_range(const key_type& k) { - return boost::unordered_detail::pair_cast( + 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( + return boost::unordered_detail::pair_cast< + const_iterator, const_iterator>( table_.equal_range(k)); } @@ -415,7 +435,7 @@ namespace boost size_type bucket_count() const { - return table_.bucket_count(); + return table_.bucket_count_; } size_type max_bucket_count() const @@ -443,14 +463,14 @@ namespace boost return const_local_iterator(table_.bucket_begin(n)); } - local_iterator end(size_type n) + local_iterator end(size_type) { - return local_iterator(table_.bucket_end(n)); + return local_iterator(); } - const_local_iterator end(size_type n) const + const_local_iterator end(size_type) const { - return const_local_iterator(table_.bucket_end(n)); + return const_local_iterator(); } const_local_iterator cbegin(size_type n) const @@ -458,9 +478,9 @@ namespace boost 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(table_.bucket_end(n)); + return const_local_iterator(); } // hash policy @@ -486,8 +506,10 @@ namespace boost } #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) - friend bool operator==(unordered_map const&, unordered_map const&); - friend bool operator!=(unordered_map const&, unordered_map const&); + friend bool operator==( + unordered_map const&, unordered_map const&); + friend bool operator!=( + unordered_map const&, unordered_map const&); #endif }; // class template unordered_map @@ -528,31 +550,40 @@ namespace boost private: #endif typedef BOOST_DEDUCED_TYPENAME - boost::unordered_detail::rebind_wrap::type + boost::unordered_detail::rebind_wrap< + allocator_type, value_type>::type value_allocator; - typedef boost::unordered_detail::hash_equivalent_table table; + 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 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; + value_allocator, boost::unordered_detail::grouped> + const_local_iterator; typedef boost::unordered_detail::hash_local_iterator< - value_allocator, boost::unordered_detail::grouped> 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; + value_allocator, boost::unordered_detail::grouped> + const_iterator; typedef boost::unordered_detail::hash_iterator< - value_allocator, boost::unordered_detail::grouped> iterator; + value_allocator, boost::unordered_detail::grouped> + iterator; #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) private: @@ -571,7 +602,7 @@ namespace boost // construct/destroy/copy explicit unordered_multimap( - size_type n = boost::unordered_detail::default_initial_bucket_count, + 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()) @@ -580,35 +611,38 @@ namespace boost } explicit unordered_multimap(allocator_type const& a) - : table_(boost::unordered_detail::default_initial_bucket_count, + : 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) + unordered_multimap(unordered_multimap const& other, + allocator_type const& a) + : table_(other.table_, a) { } - template - unordered_multimap(InputIterator f, InputIterator l) - : table_(boost::unordered_detail::initial_size(f, l), hasher(), key_equal(), allocator_type()) + 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(InputIterator f, InputIterator 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_(boost::unordered_detail::initial_size(f, l, n), + hf, eql, allocator_type()) { table_.insert_range(f, l); } - template - unordered_multimap(InputIterator f, InputIterator l, + template + unordered_multimap(InputIt f, InputIt l, size_type n, const hasher &hf, const key_equal &eql, @@ -622,12 +656,12 @@ namespace boost #if defined(BOOST_HAS_RVALUE_REFS) unordered_multimap(unordered_multimap&& other) - : table_(other.table_, boost::unordered_detail::move_tag()) + : 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()) + : table_(other.table_, a, boost::unordered_detail::move_tag()) { } @@ -637,8 +671,10 @@ namespace boost return *this; } #else - unordered_multimap(boost::unordered_detail::move_from > other) - : table_(other.source.table_, boost::unordered_detail::move_tag()) + unordered_multimap(boost::unordered_detail::move_from< + unordered_multimap + > other) + : table_(other.source.table_, boost::unordered_detail::move_tag()) { } @@ -653,11 +689,13 @@ namespace boost #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) unordered_multimap(std::initializer_list list, - size_type n = boost::unordered_detail::default_initial_bucket_count, + 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_(boost::unordered_detail::initial_size( + list.begin(), list.end(), n), + hf, eql, allocator_type()) { table_.insert_range(list.begin(), list.end()); } @@ -736,7 +774,8 @@ namespace boost template iterator emplace_hint(const_iterator hint, Args&&... args) { - return iterator(table_.emplace_hint(get(hint), std::forward(args)...)); + return iterator(table_.emplace_hint(get(hint), + std::forward(args)...)); } #else @@ -745,36 +784,37 @@ namespace boost 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(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( \ - 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) \ - )); \ +#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, @@ -794,8 +834,8 @@ namespace boost return iterator(table_.emplace_hint(get(hint), obj)); } - template - void insert(InputIterator first, InputIterator last) + template + void insert(InputIt first, InputIt last) { table_.insert_range(first, last); } @@ -857,14 +897,16 @@ namespace boost std::pair equal_range(const key_type& k) { - return boost::unordered_detail::pair_cast( + 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( + return boost::unordered_detail::pair_cast< + const_iterator, const_iterator>( table_.equal_range(k)); } @@ -872,7 +914,7 @@ namespace boost size_type bucket_count() const { - return table_.bucket_count(); + return table_.bucket_count_; } size_type max_bucket_count() const @@ -900,14 +942,14 @@ namespace boost return const_local_iterator(table_.bucket_begin(n)); } - local_iterator end(size_type n) + local_iterator end(size_type) { - return local_iterator(table_.bucket_end(n)); + return local_iterator(); } - const_local_iterator end(size_type n) const + const_local_iterator end(size_type) const { - return const_local_iterator(table_.bucket_end(n)); + return const_local_iterator(); } const_local_iterator cbegin(size_type n) const @@ -915,9 +957,9 @@ namespace boost 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(table_.bucket_end(n)); + return const_local_iterator(); } // hash policy @@ -943,8 +985,10 @@ namespace boost } #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) - friend bool operator==(unordered_multimap const&, unordered_multimap const&); - friend bool operator!=(unordered_multimap const&, unordered_multimap const&); + friend bool operator==( + unordered_multimap const&, unordered_multimap const&); + friend bool operator!=( + unordered_multimap const&, unordered_multimap const&); #endif }; // class template unordered_multimap diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index c6ef5fc7..e7d53d23 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -16,7 +16,8 @@ #include #include #include -#include +#include +#include #if !defined(BOOST_HAS_RVALUE_REFS) #include @@ -53,27 +54,34 @@ namespace boost #endif typedef BOOST_DEDUCED_TYPENAME - boost::unordered_detail::rebind_wrap::type + boost::unordered_detail::rebind_wrap< + allocator_type, value_type>::type value_allocator; - typedef boost::unordered_detail::hash_unique_table table; + 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 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; + value_allocator, boost::unordered_detail::ungrouped> + const_local_iterator; typedef boost::unordered_detail::hash_const_iterator< - value_allocator, boost::unordered_detail::ungrouped> const_iterator; + value_allocator, boost::unordered_detail::ungrouped> + const_iterator; typedef const_local_iterator local_iterator; typedef const_iterator iterator; @@ -94,47 +102,49 @@ namespace boost // construct/destroy/copy explicit unordered_set( - size_type n = boost::unordered_detail::default_initial_bucket_count, + 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) + : table_(n, hf, eql, a) { } explicit unordered_set(allocator_type const& a) - : table_(boost::unordered_detail::default_initial_bucket_count, + : 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) + : table_(other.table_, a) { } - template - unordered_set(InputIterator f, InputIterator l) - : table_(boost::unordered_detail::initial_size(f, l), hasher(), key_equal(), allocator_type()) + 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(InputIterator f, InputIterator l, size_type n, + 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_(boost::unordered_detail::initial_size(f, l, n), + hf, eql, allocator_type()) { table_.insert_range(f, l); } - template - unordered_set(InputIterator f, InputIterator l, size_type n, + 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_(boost::unordered_detail::initial_size(f, l, n), hf, eql, a) { table_.insert_range(f, l); } @@ -143,12 +153,12 @@ namespace boost #if defined(BOOST_HAS_RVALUE_REFS) unordered_set(unordered_set&& other) - : table_(other.table_, boost::unordered_detail::move_tag()) + : 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()) + : table_(other.table_, a, boost::unordered_detail::move_tag()) { } @@ -158,8 +168,10 @@ namespace boost return *this; } #else - unordered_set(boost::unordered_detail::move_from > other) - : table_(other.source.table_, boost::unordered_detail::move_tag()) + unordered_set(boost::unordered_detail::move_from< + unordered_set + > other) + : table_(other.source.table_, boost::unordered_detail::move_tag()) { } @@ -174,11 +186,13 @@ namespace boost #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) unordered_set(std::initializer_list list, - size_type n = boost::unordered_detail::default_initial_bucket_count, + 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_(boost::unordered_detail::initial_size( + list.begin(), list.end(), n), + hf, eql, allocator_type()) { table_.insert_range(list.begin(), list.end()); } @@ -269,35 +283,36 @@ namespace boost 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(table_.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( \ - 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) \ - )); \ +#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_hint(get(hint), \ + BOOST_UNORDERED_CALL_PARAMS(z, n) \ + )); \ } BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, @@ -318,8 +333,8 @@ namespace boost return iterator(table_.emplace_hint(get(hint), obj)); } - template - void insert(InputIterator first, InputIterator last) + template + void insert(InputIt first, InputIt last) { table_.insert_range(first, last); } @@ -376,7 +391,8 @@ namespace boost std::pair equal_range(const key_type& k) const { - return boost::unordered_detail::pair_cast( + return boost::unordered_detail::pair_cast< + const_iterator, const_iterator>( table_.equal_range(k)); } @@ -384,7 +400,7 @@ namespace boost size_type bucket_count() const { - return table_.bucket_count(); + return table_.bucket_count_; } size_type max_bucket_count() const @@ -412,14 +428,14 @@ namespace boost return const_local_iterator(table_.bucket_begin(n)); } - local_iterator end(size_type n) + local_iterator end(size_type) { - return local_iterator(table_.bucket_end(n)); + return local_iterator(); } - const_local_iterator end(size_type n) const + const_local_iterator end(size_type) const { - return const_local_iterator(table_.bucket_end(n)); + return const_local_iterator(); } const_local_iterator cbegin(size_type n) const @@ -427,9 +443,9 @@ namespace boost 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(table_.bucket_end(n)); + return const_local_iterator(); } // hash policy @@ -455,8 +471,10 @@ namespace boost } #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) - friend bool operator==(unordered_set const&, unordered_set const&); - friend bool operator!=(unordered_set const&, unordered_set const&); + friend bool operator==( + unordered_set const&, unordered_set const&); + friend bool operator!=( + unordered_set const&, unordered_set const&); #endif }; // class template unordered_set @@ -496,27 +514,34 @@ namespace boost private: #endif typedef BOOST_DEDUCED_TYPENAME - boost::unordered_detail::rebind_wrap::type + boost::unordered_detail::rebind_wrap< + allocator_type, value_type>::type value_allocator; - typedef boost::unordered_detail::hash_equivalent_table table; + 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 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; + value_allocator, boost::unordered_detail::grouped> + const_local_iterator; typedef boost::unordered_detail::hash_const_iterator< - value_allocator, boost::unordered_detail::grouped> const_iterator; + value_allocator, boost::unordered_detail::grouped> + const_iterator; typedef const_local_iterator local_iterator; typedef const_iterator iterator; @@ -537,7 +562,7 @@ namespace boost // construct/destroy/copy explicit unordered_multiset( - size_type n = boost::unordered_detail::default_initial_bucket_count, + 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()) @@ -546,34 +571,37 @@ namespace boost } explicit unordered_multiset(allocator_type const& a) - : table_(boost::unordered_detail::default_initial_bucket_count, + : 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) + unordered_multiset(unordered_multiset const& other, + allocator_type const& a) + : table_(other.table_, a) { } - template - unordered_multiset(InputIterator f, InputIterator l) - : table_(boost::unordered_detail::initial_size(f, l), hasher(), key_equal(), allocator_type()) + 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(InputIterator f, InputIterator l, size_type n, + 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_(boost::unordered_detail::initial_size(f, l, n), + hf, eql, allocator_type()) { table_.insert_range(f, l); } - template - unordered_multiset(InputIterator f, InputIterator l, size_type n, + template + unordered_multiset(InputIt f, InputIt l, size_type n, const hasher &hf, const key_equal &eql, const allocator_type &a) @@ -586,12 +614,12 @@ namespace boost #if defined(BOOST_HAS_RVALUE_REFS) unordered_multiset(unordered_multiset&& other) - : table_(other.table_, boost::unordered_detail::move_tag()) + : 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()) + : table_(other.table_, a, boost::unordered_detail::move_tag()) { } @@ -601,8 +629,10 @@ namespace boost return *this; } #else - unordered_multiset(boost::unordered_detail::move_from > other) - : table_(other.source.table_, boost::unordered_detail::move_tag()) + unordered_multiset(boost::unordered_detail::move_from< + unordered_multiset + > other) + : table_(other.source.table_, boost::unordered_detail::move_tag()) { } @@ -617,11 +647,13 @@ namespace boost #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) unordered_multiset(std::initializer_list list, - size_type n = boost::unordered_detail::default_initial_bucket_count, + 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_(boost::unordered_detail::initial_size( + list.begin(), list.end(), n), + hf, eql, allocator_type()) { table_.insert_range(list.begin(), list.end()); } @@ -700,7 +732,8 @@ namespace boost template iterator emplace_hint(const_iterator hint, Args&&... args) { - return iterator(table_.emplace_hint(get(hint), std::forward(args)...)); + return iterator(table_.emplace_hint(get(hint), + std::forward(args)...)); } #else @@ -709,33 +742,34 @@ namespace boost 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(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( \ - 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) \ - )); \ +#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, @@ -755,8 +789,8 @@ namespace boost return iterator(table_.emplace_hint(get(hint), obj)); } - template - void insert(InputIterator first, InputIterator last) + template + void insert(InputIt first, InputIt last) { table_.insert_range(first, last); } @@ -813,7 +847,8 @@ namespace boost std::pair equal_range(const key_type& k) const { - return boost::unordered_detail::pair_cast( + return boost::unordered_detail::pair_cast< + const_iterator, const_iterator>( table_.equal_range(k)); } @@ -821,7 +856,7 @@ namespace boost size_type bucket_count() const { - return table_.bucket_count(); + return table_.bucket_count_; } size_type max_bucket_count() const @@ -849,14 +884,14 @@ namespace boost return const_local_iterator(table_.bucket_begin(n)); } - local_iterator end(size_type n) + local_iterator end(size_type) { - return local_iterator(table_.bucket_end(n)); + return local_iterator(); } - const_local_iterator end(size_type n) const + const_local_iterator end(size_type) const { - return const_local_iterator(table_.bucket_end(n)); + return const_local_iterator(); } const_local_iterator cbegin(size_type n) const @@ -864,9 +899,9 @@ namespace boost 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(table_.bucket_end(n)); + return const_local_iterator(); } // hash policy @@ -892,8 +927,10 @@ namespace boost } #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) - friend bool operator==(unordered_multiset const&, unordered_multiset const&); - friend bool operator!=(unordered_multiset const&, unordered_multiset const&); + friend bool operator==( + unordered_multiset const&, unordered_multiset const&); + friend bool operator!=( + unordered_multiset const&, unordered_multiset const&); #endif }; // class template unordered_multiset 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/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/out_of_line.cpp b/test/unordered/out_of_line.cpp index b8d24e1f..98262529 100644 --- a/test/unordered/out_of_line.cpp +++ b/test/unordered/out_of_line.cpp @@ -10,7 +10,7 @@ struct foo { template template -bool foo::bar(U x) { return x; } +bool foo::bar(U x) { return x ? true : false; } int main() { foo x; From 965c2ae89c5e5e04ee01fda2573ed926d9d17d00 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 21 Sep 2009 21:17:19 +0000 Subject: [PATCH 104/471] Slightly more consistent variable names. In detail 'n' is now always a node pointer. [SVN r56346] --- include/boost/unordered/detail/buckets.hpp | 12 +- include/boost/unordered/detail/equivalent.hpp | 14 +- include/boost/unordered/detail/fwd.hpp | 24 +-- include/boost/unordered/detail/node.hpp | 28 ++-- include/boost/unordered/detail/table.hpp | 56 ++++--- include/boost/unordered/detail/unique.hpp | 156 +++++++++--------- include/boost/unordered/detail/util.hpp | 35 ++-- 7 files changed, 165 insertions(+), 160 deletions(-) diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index fed14388..8a2163c6 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -19,9 +19,9 @@ namespace boost { namespace unordered_detail { template inline BOOST_DEDUCED_TYPENAME hash_buckets::bucket_ptr - hash_buckets::get_bucket(std::size_t n) const + hash_buckets::get_bucket(std::size_t num) const { - return buckets_ + static_cast(n); + return buckets_ + static_cast(num); } template @@ -46,9 +46,9 @@ namespace boost { namespace unordered_detail { template inline BOOST_DEDUCED_TYPENAME hash_buckets::node_ptr - hash_buckets::bucket_begin(std::size_t n) const + hash_buckets::bucket_begin(std::size_t num) const { - return buckets_ ? get_bucket(n)->next_ : node_ptr(); + return buckets_ ? get_bucket(num)->next_ : node_ptr(); } //////////////////////////////////////////////////////////////////////////// @@ -103,9 +103,9 @@ namespace boost { namespace unordered_detail { { std::size_t count = 0; while(begin != end) { - node_ptr node = begin; + node_ptr n = begin; begin = begin->next_; - delete_node(node); + delete_node(n); ++count; } return count; diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index efb3a688..fa05019d 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -177,27 +177,27 @@ namespace boost { namespace unordered_detail { #else -#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ +#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \ template \ - template \ + template \ BOOST_DEDUCED_TYPENAME hash_equivalent_table::iterator_base \ hash_equivalent_table \ - ::emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + ::emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ { \ node_constructor a(*this); \ - a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \ + a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ return emplace_impl(a); \ } \ \ template \ - template \ + template \ BOOST_DEDUCED_TYPENAME hash_equivalent_table::iterator_base \ hash_equivalent_table \ ::emplace_hint(iterator_base const& it, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ { \ node_constructor a(*this); \ - a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \ + a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ return emplace_hint_impl(it, a); \ } diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index 15924676..c8a4abc7 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -50,12 +50,12 @@ #include #include -#define BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - BOOST_PP_ENUM_PARAMS_Z(z, n, class 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) +#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 @@ -126,7 +126,7 @@ namespace boost { namespace unordered_detail { 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 node); + 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); }; @@ -146,7 +146,7 @@ namespace boost { namespace unordered_detail { 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 node); + 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); @@ -237,12 +237,12 @@ namespace boost { namespace unordered_detail { return node::get_value(node_); } - void increment_bucket(node_ptr node) { - while(!node) { + void increment_bucket(node_ptr n) { + while(!n) { ++bucket_; - node = bucket_->next_; + n = bucket_->next_; } - node_ = bucket_ == node ? node_ptr() : node; + node_ = bucket_ == n ? node_ptr() : n; } void increment() { diff --git a/include/boost/unordered/detail/node.hpp b/include/boost/unordered/detail/node.hpp index 21645105..85a31410 100644 --- a/include/boost/unordered/detail/node.hpp +++ b/include/boost/unordered/detail/node.hpp @@ -71,9 +71,9 @@ namespace boost { namespace unordered_detail { } template - inline void ungrouped_node_base::unlink_node(bucket& b, node_ptr node) + inline void ungrouped_node_base::unlink_node(bucket& b, node_ptr n) { - unlink_nodes(b, node, node->next_); + unlink_nodes(b, n, n->next_); } //////////////////////////////////////////////////////////////////////////// @@ -144,41 +144,41 @@ namespace boost { namespace unordered_detail { } template - void grouped_node_base::unlink_node(bucket& b, node_ptr node) + void grouped_node_base::unlink_node(bucket& b, node_ptr n) { - node_ptr next = node->next_; - node_ptr* pos = &next_group(node); + node_ptr next = n->next_; + node_ptr* pos = &next_group(n); - if(*pos != node) { + if(*pos != n) { // The node is at the beginning of a group. // Find the previous node pointer: pos = &b.next_; - while(*pos != node) pos = &next_group(*pos); + while(*pos != n) pos = &next_group(*pos); // Remove from group if(BOOST_UNORDERED_BORLAND_BOOL(next) && - get(next).group_prev_ == node) + get(next).group_prev_ == n) { - get(next).group_prev_ = get(node).group_prev_; + get(next).group_prev_ = get(n).group_prev_; } } else if(BOOST_UNORDERED_BORLAND_BOOL(next) && - get(next).group_prev_ == node) + 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(node).group_prev_; + 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(node).group_prev_; - while(get(x).group_prev_ != node) { + node_ptr x = get(n).group_prev_; + while(get(x).group_prev_ != n) { x = get(x).group_prev_; } - get(x).group_prev_ = get(node).group_prev_; + get(x).group_prev_ = get(n).group_prev_; } *pos = next; } diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index eb18926f..edbc3773 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -116,7 +116,7 @@ namespace boost { namespace unordered_detail { // no throw template inline std::size_t hash_table::min_buckets_for_size( - std::size_t n) const + std::size_t size) const { BOOST_ASSERT(this->mlf_ != 0); @@ -128,7 +128,7 @@ namespace boost { namespace unordered_detail { // // Or from rehash post-condition: // count > size / mlf_ - return next_prime(double_to_size_t(floor(n / (double) mlf_)) + 1); + return next_prime(double_to_size_t(floor(size / (double) mlf_)) + 1); } //////////////////////////////////////////////////////////////////////////// @@ -199,9 +199,9 @@ namespace boost { namespace unordered_detail { // Constructors template - hash_table::hash_table(std::size_t n, + hash_table::hash_table(std::size_t num_buckets, hasher const& hf, key_equal const& eq, node_allocator const& a) - : buckets(a, next_prime(n)), + : buckets(a, next_prime(num_buckets)), base(hf, eq), size_(), mlf_(1.0f), @@ -404,24 +404,26 @@ namespace boost { namespace unordered_detail { // basic exception safety template - inline void hash_table::create_for_insert(std::size_t n) + inline void hash_table::create_for_insert(std::size_t size) { - if(n > this->bucket_count_) - this->bucket_count_ = this->min_buckets_for_size(n); + // TODO: Write a test to detect this bug: + if(size > this->bucket_count_) + 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 n) + inline bool hash_table::reserve_for_insert(std::size_t size) { - if(n >= max_load_) { + if(size >= max_load_) { std::size_t s = this->size_; s = s + (s >> 1); - n = this->min_buckets_for_size(s > n ? s : n); - if(n != this->bucket_count_) { - rehash_impl(n); + std::size_t num_buckets + = this->min_buckets_for_size(s > size ? s : size); + if(num_buckets != this->bucket_count_) { + rehash_impl(num_buckets); return true; } } @@ -433,24 +435,24 @@ namespace boost { namespace unordered_detail { // strong otherwise. // TODO: Should this always create buckets? template - inline void hash_table - ::rehash(std::size_t n) + inline void hash_table::rehash(std::size_t min_buckets) { using namespace std; if(!this->buckets_) { - this->bucket_count_ = next_prime(n); + this->bucket_count_ = next_prime(min_buckets); this->create_buckets(); this->init_buckets(); } - else if(n != this->bucket_count_) { + // TODO: Another bug: + else if(min_buckets != this->bucket_count_) { // no throw: // TODO: Needlessly calling next_prime twice. std::size_t min_size = this->min_buckets_for_size(this->size_); - n = next_prime(n); - n = min_size > n ? min_size : n; + min_buckets = next_prime(min_buckets); + min_buckets = min_size > min_buckets ? min_size : min_buckets; - rehash_impl(n); + rehash_impl(min_buckets); } } @@ -461,13 +463,13 @@ namespace boost { namespace unordered_detail { template void hash_table - ::rehash_impl(std::size_t n) + ::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(), n); + buckets dst(this->node_alloc(), num_buckets); dst.create_buckets(); buckets src(this->node_alloc(), this->bucket_count_); @@ -726,18 +728,18 @@ namespace boost { namespace unordered_detail { template BOOST_DEDUCED_TYPENAME hash_table::iterator_base hash_table::emplace_empty_impl_with_node( - node_constructor& a, std::size_t n) + 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(n); - else this->create_for_insert(n); + 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 node = a.release(); - node::add_to_bucket(node, *bucket); + node_ptr n = a.release(); + node::add_to_bucket(n, *bucket); ++this->size_; this->cached_begin_bucket_ = bucket; - return iterator_base(bucket, node); + return iterator_base(bucket, n); } }} diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index 0f5cf88f..14565bca 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -191,56 +191,58 @@ namespace boost { namespace unordered_detail { #else -#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ - 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, n)) \ - { \ - 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, n)); \ - \ - 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, n)) \ - { \ - node_constructor a(*this); \ - a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \ - 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, n)) \ - { \ - node_constructor a(*this); \ - a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \ - return emplace_return(this->emplace_empty_impl_with_node(a, 1), true); \ +#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, @@ -312,33 +314,33 @@ namespace boost { namespace unordered_detail { emplace_empty_impl(arg0).first; } -#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ - template \ - template \ - BOOST_DEDUCED_TYPENAME hash_unique_table::emplace_return \ - hash_unique_table::emplace( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ - { \ - return this->size_ ? \ - emplace_impl(extractor::extract(arg0, arg1), \ - BOOST_UNORDERED_CALL_PARAMS(z, n)) : \ - emplace_empty_impl( \ - BOOST_UNORDERED_CALL_PARAMS(z, n)); \ - } \ - \ - template \ - template \ - BOOST_DEDUCED_TYPENAME hash_unique_table::iterator_base \ - hash_unique_table:: \ - emplace_hint(iterator_base const& it, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ - { \ - return this->size_ ? \ - emplace_impl(extractor::extract(arg0, arg1), \ - BOOST_UNORDERED_CALL_PARAMS(z, n)) : \ - emplace_empty_impl( \ - BOOST_UNORDERED_CALL_PARAMS(z, n)); \ - } \ +#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)); \ + } \ + \ + template \ + template \ + BOOST_DEDUCED_TYPENAME hash_unique_table::iterator_base \ + hash_unique_table:: \ + emplace_hint(iterator_base const& it, \ + 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, _) diff --git a/include/boost/unordered/detail/util.hpp b/include/boost/unordered/detail/util.hpp index 9a70185e..1f592dd3 100644 --- a/include/boost/unordered/detail/util.hpp +++ b/include/boost/unordered/detail/util.hpp @@ -61,24 +61,24 @@ namespace boost { namespace unordered_detail { typedef prime_list_template prime_list; // no throw - inline std::size_t next_prime(std::size_t n) { + 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, n); + 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 n) { + 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, n); + std::upper_bound(prime_list_begin,prime_list_end, num); if(bound != prime_list_begin) bound--; return *bound; @@ -129,9 +129,10 @@ namespace boost { namespace unordered_detail { template inline std::size_t initial_size(I i, I j, - std::size_t n = boost::unordered_detail::default_bucket_count) + std::size_t num_buckets = boost::unordered_detail::default_bucket_count) { - return (std::max)(static_cast(insert_size(i, j)) + 1, n); + return (std::max)(static_cast(insert_size(i, j)) + 1, + num_buckets); } //////////////////////////////////////////////////////////////////////////// @@ -158,29 +159,29 @@ namespace boost { namespace unordered_detail { #else -#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, n, _) \ +#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \ template < \ class T, \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \ > \ inline void construct_impl( \ T*, void* address, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \ ) \ { \ new(address) T( \ - BOOST_UNORDERED_CALL_PARAMS(z, n)); \ + BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ } \ \ template \ inline void construct_impl( \ std::pair*, void* address, \ - Key const& k, BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + Key const& k, BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ { \ new(address) std::pair(k, \ - Second(BOOST_UNORDERED_CALL_PARAMS(z, n))); \ + Second(BOOST_UNORDERED_CALL_PARAMS(z, num_params))); \ } BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, @@ -230,18 +231,18 @@ namespace boost { namespace unordered_detail { } #else -#define BOOST_UNORDERED_CONSTRUCT(z, n, _) \ +#define BOOST_UNORDERED_CONSTRUCT(z, num_params, _) \ template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \ > \ void construct( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \ ) \ { \ construct_preamble(); \ construct_impl( \ (value_type*) 0, node_->address(), \ - BOOST_UNORDERED_CALL_PARAMS(z, n) \ + BOOST_UNORDERED_CALL_PARAMS(z, num_params) \ ); \ value_constructed_ = true; \ } From ff6e4576512c6595e072531600fae6c190c62ceb Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 21 Sep 2009 21:17:40 +0000 Subject: [PATCH 105/471] Fix bug where container was reducing the number of buckets. [SVN r56347] --- include/boost/unordered/detail/table.hpp | 5 ++--- test/unordered/constructor_tests.cpp | 13 +++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index edbc3773..4d47ee67 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -406,9 +406,8 @@ namespace boost { namespace unordered_detail { template inline void hash_table::create_for_insert(std::size_t size) { - // TODO: Write a test to detect this bug: - if(size > this->bucket_count_) - this->bucket_count_ = this->min_buckets_for_size(size); + std::size_t min_buckets = this->min_buckets_for_size(size); + if(min_buckets > this->bucket_count_) this->bucket_count_ = min_buckets; this->create_buckets(); this->init_buckets(); } 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 From 08d533cb88e73e402e09b14d2229f6446fdc5401 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 21 Sep 2009 21:18:01 +0000 Subject: [PATCH 106/471] Fix a bug that was causing unnecessary rehahes. [SVN r56348] --- include/boost/unordered/detail/table.hpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 4d47ee67..8d94bcd7 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -443,23 +443,19 @@ namespace boost { namespace unordered_detail { this->create_buckets(); this->init_buckets(); } - // TODO: Another bug: - else if(min_buckets != this->bucket_count_) { + else { // no throw: // TODO: Needlessly calling next_prime twice. std::size_t min_size = this->min_buckets_for_size(this->size_); min_buckets = next_prime(min_buckets); min_buckets = min_size > min_buckets ? min_size : min_buckets; - - rehash_impl(min_buckets); + if(min_buckets != this->bucket_count_) rehash_impl(min_buckets); } } // if hash function throws, basic exception safety // strong otherwise - // TODO: Rewrite so that it doesn't need to keep updating size_. - template void hash_table ::rehash_impl(std::size_t num_buckets) From efbf13685eddf83f39e9403e690f0732f85e2dc5 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 21 Sep 2009 21:18:21 +0000 Subject: [PATCH 107/471] Use std::max. [SVN r56349] --- include/boost/unordered/detail/table.hpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 8d94bcd7..9e80078b 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -417,10 +417,9 @@ namespace boost { namespace unordered_detail { inline bool hash_table::reserve_for_insert(std::size_t size) { if(size >= max_load_) { - std::size_t s = this->size_; - s = s + (s >> 1); std::size_t num_buckets - = this->min_buckets_for_size(s > size ? s : size); + = 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; @@ -446,9 +445,9 @@ namespace boost { namespace unordered_detail { else { // no throw: // TODO: Needlessly calling next_prime twice. - std::size_t min_size = this->min_buckets_for_size(this->size_); - min_buckets = next_prime(min_buckets); - min_buckets = min_size > min_buckets ? min_size : min_buckets; + 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); } } From f76af2d0c88b5426f1d1d599897537810441a7c4 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 22 Sep 2009 22:39:00 +0000 Subject: [PATCH 108/471] Another std::max. [SVN r56362] --- include/boost/unordered/detail/table.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 9e80078b..4e7a5811 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -406,8 +406,8 @@ namespace boost { namespace unordered_detail { template inline void hash_table::create_for_insert(std::size_t size) { - std::size_t min_buckets = this->min_buckets_for_size(size); - if(min_buckets > this->bucket_count_) this->bucket_count_ = min_buckets; + this->bucket_count_ = (std::max)(this->bucket_count_, + this->min_buckets_for_size(size)); this->create_buckets(); this->init_buckets(); } From 437a35feaa6f8a719229f29822d7a9f00ebb26ff Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 22 Sep 2009 22:39:17 +0000 Subject: [PATCH 109/471] Remove the emplace_hint implementation for unique containers as it isn't really used and seems to be causing sun 5.7 problems. [SVN r56363] --- include/boost/unordered/detail/fwd.hpp | 17 +-------- include/boost/unordered/detail/unique.hpp | 46 +---------------------- include/boost/unordered/unordered_map.hpp | 17 ++++----- include/boost/unordered/unordered_set.hpp | 18 ++++----- 4 files changed, 17 insertions(+), 81 deletions(-) diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index c8a4abc7..39f85427 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -629,30 +629,18 @@ namespace boost { namespace unordered_detail { template emplace_return emplace(Args&&... args); template - iterator_base emplace_hint(iterator_base const&, 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 - template - emplace_return emplace(Arg0 const& arg0); - template - iterator_base emplace_hint(iterator_base const&, Arg0 const& arg0); #define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ template \ emplace_return emplace( \ BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \ template \ - iterator_base emplace_hint(iterator_base const& it, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \ - BOOST_UNORDERED_INSERT_IMPL2(z, n, _) - -#define BOOST_UNORDERED_INSERT_IMPL2(z, n, _) \ - template \ emplace_return emplace_impl(key_type const& k, \ BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \ template \ @@ -662,13 +650,10 @@ namespace boost { namespace unordered_detail { emplace_return emplace_empty_impl( \ BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); - BOOST_UNORDERED_INSERT_IMPL2(1, 1, _) - - BOOST_PP_REPEAT_FROM_TO(2, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_INSERT_IMPL, _) #undef BOOST_UNORDERED_INSERT_IMPL -#undef BOOST_UNORDERED_INSERT_IMPL2 #endif diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index 14565bca..b4a5157c 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -272,25 +272,6 @@ namespace boost { namespace unordered_detail { emplace_empty_impl(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 - template - BOOST_DEDUCED_TYPENAME hash_unique_table::iterator_base - hash_unique_table::emplace_hint(iterator_base const&, - Args&&... args) - { - return this->size_ ? - emplace_impl( - extractor::extract(std::forward(args)...), - std::forward(args)...).first : - emplace_empty_impl(std::forward(args)...).first; - } - #else template @@ -303,17 +284,6 @@ namespace boost { namespace unordered_detail { emplace_empty_impl(arg0); } - template - template - BOOST_DEDUCED_TYPENAME hash_unique_table::iterator_base - hash_unique_table::emplace_hint(iterator_base const&, - Arg0 const& arg0) - { - return this->size_ ? - emplace_impl(extractor::extract(arg0), arg0).first : - emplace_empty_impl(arg0).first; - } - #define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \ template \ template \ @@ -326,21 +296,7 @@ namespace boost { namespace unordered_detail { BOOST_UNORDERED_CALL_PARAMS(z, num_params)) : \ emplace_empty_impl( \ BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ - } \ - \ - template \ - template \ - BOOST_DEDUCED_TYPENAME hash_unique_table::iterator_base \ - hash_unique_table:: \ - emplace_hint(iterator_base const& it, \ - 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, _) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 0e89d43a..f4c052f5 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -277,10 +277,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)...).first); } #else @@ -290,10 +289,9 @@ namespace boost 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(table_.emplace_hint(get(hint), v)); + return iterator(table_.emplace(v).first); } #define BOOST_UNORDERED_EMPLACE(z, n, _) \ @@ -317,9 +315,8 @@ namespace boost BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ ) \ { \ - return iterator(table_.emplace_hint(get(hint), \ - BOOST_UNORDERED_CALL_PARAMS(z, n) \ - )); \ + return iterator(table_.emplace( \ + BOOST_UNORDERED_CALL_PARAMS(z, n)).first); \ } BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, @@ -337,7 +334,7 @@ namespace boost iterator insert(const_iterator hint, const value_type& obj) { - return iterator(table_.emplace_hint(get(hint), obj)); + return iterator(table_.emplace(obj).first); } template diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index e7d53d23..2b147b28 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -270,10 +270,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)...).first); } #else @@ -283,10 +282,10 @@ namespace boost 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).first); } #define BOOST_UNORDERED_EMPLACE(z, n, _) \ @@ -306,13 +305,12 @@ 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), \ - BOOST_UNORDERED_CALL_PARAMS(z, n) \ - )); \ + return iterator(table_.emplace( \ + BOOST_UNORDERED_CALL_PARAMS(z, n)).first); \ } BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, @@ -330,7 +328,7 @@ namespace boost iterator insert(const_iterator hint, const value_type& obj) { - return iterator(table_.emplace_hint(get(hint), obj)); + return iterator(table_.emplace(obj).first); } template From b75b7dd5acb3c2b9a7946bb4faa861fb04df19cf Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 24 Sep 2009 20:42:19 +0000 Subject: [PATCH 110/471] Remove temporary test. [SVN r56374] --- test/unordered/Jamfile.v2 | 1 - test/unordered/out_of_line.cpp | 21 --------------------- 2 files changed, 22 deletions(-) delete mode 100644 test/unordered/out_of_line.cpp diff --git a/test/unordered/Jamfile.v2 b/test/unordered/Jamfile.v2 index 5a4696f6..ee1505f7 100644 --- a/test/unordered/Jamfile.v2 +++ b/test/unordered/Jamfile.v2 @@ -38,5 +38,4 @@ test-suite unordered [ run rehash_tests.cpp ] [ run equality_tests.cpp ] [ run swap_tests.cpp : : : BOOST_UNORDERED_SWAP_METHOD=2 ] - [ run out_of_line.cpp ] ; diff --git a/test/unordered/out_of_line.cpp b/test/unordered/out_of_line.cpp deleted file mode 100644 index 98262529..00000000 --- a/test/unordered/out_of_line.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// Just a little test to see if out of line template methods are supported: - -#include - -template -struct foo { - template - bool bar(U x); -}; - -template -template -bool foo::bar(U x) { return x ? true : false; } - -int main() { - foo x; - BOOST_TEST(x.bar(1)); - BOOST_TEST(!x.bar(0)); - - return boost::report_errors(); -} \ No newline at end of file From 31cd8f4e1645a8ed644b50a6ab45fb55b847fab4 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 27 Sep 2009 19:12:04 +0000 Subject: [PATCH 111/471] Try supporting reference parameters in pairs. Probably not required. [SVN r56441] --- .../boost/unordered/detail/extract_key.hpp | 3 +- test/objects/test.hpp | 4 ++ test/unordered/Jamfile.v2 | 1 + test/unordered/insert_range_tests.cpp | 40 +++++++++++++++++++ 4 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 test/unordered/insert_range_tests.cpp diff --git a/include/boost/unordered/detail/extract_key.hpp b/include/boost/unordered/detail/extract_key.hpp index cba889eb..59fab7c2 100644 --- a/include/boost/unordered/detail/extract_key.hpp +++ b/include/boost/unordered/detail/extract_key.hpp @@ -106,7 +106,7 @@ namespace unordered_detail { { return v.first; } -/* + template static key_type const& extract( std::pair const& v) @@ -120,7 +120,6 @@ namespace unordered_detail { { return v.first; } -*/ #if defined(BOOST_UNORDERED_STD_FORWARD) template 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/Jamfile.v2 b/test/unordered/Jamfile.v2 index ee1505f7..ce89396a 100644 --- a/test/unordered/Jamfile.v2 +++ b/test/unordered/Jamfile.v2 @@ -27,6 +27,7 @@ test-suite unordered [ run move_tests.cpp : : : always_show_run_output ] [ run assign_tests.cpp ] [ run insert_tests.cpp ] + [ run insert_range_tests.cpp ] [ run insert_stable_tests.cpp ] [ run unnecessary_copy_tests.cpp ] [ run erase_tests.cpp ] diff --git a/test/unordered/insert_range_tests.cpp b/test/unordered/insert_range_tests.cpp new file mode 100644 index 00000000..ef55cf6b --- /dev/null +++ b/test/unordered/insert_range_tests.cpp @@ -0,0 +1,40 @@ + +// Copyright 2006-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 +#include +#include +#include "../helpers/test.hpp" +#include "../objects/test.hpp" + +UNORDERED_AUTO_TEST(needless_copies_1) { + std::vector > src; + src.push_back(std::pair(test::object(1, 2), 0)); + + boost::unordered_map dst; + dst[test::object(1, 2)] = 0; + + test::object_count count = test::global_object_count; + dst.insert(src.begin(), src.end()); + BOOST_TEST(count == test::global_object_count); +} + +UNORDERED_AUTO_TEST(needless_copies_2) { + test::object x(1, 2); + std::pair src(x, 0); + + boost::unordered_map dst; + + test::object_count count = test::global_object_count; + dst.emplace(src); + BOOST_TEST(test::global_object_count.instances == count.instances + 1); + BOOST_TEST_EQ(test::global_object_count.constructions, count.constructions + 1); + + count = test::global_object_count; + dst.emplace(src); + BOOST_TEST_EQ(test::global_object_count, count); +} + +RUN_TESTS() From 2b8680d2c459fc648d9c5ce5526dae9655983bc4 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 28 Sep 2009 23:06:03 +0000 Subject: [PATCH 112/471] 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. [SVN r56461] --- include/boost/unordered/detail/extract_key.hpp | 14 -------------- test/unordered/insert_range_tests.cpp | 5 +++-- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/include/boost/unordered/detail/extract_key.hpp b/include/boost/unordered/detail/extract_key.hpp index 59fab7c2..d415d935 100644 --- a/include/boost/unordered/detail/extract_key.hpp +++ b/include/boost/unordered/detail/extract_key.hpp @@ -107,20 +107,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 static key_type const& extract(key_type const& k, diff --git a/test/unordered/insert_range_tests.cpp b/test/unordered/insert_range_tests.cpp index ef55cf6b..b9234796 100644 --- a/test/unordered/insert_range_tests.cpp +++ b/test/unordered/insert_range_tests.cpp @@ -29,12 +29,13 @@ UNORDERED_AUTO_TEST(needless_copies_2) { test::object_count count = test::global_object_count; dst.emplace(src); - BOOST_TEST(test::global_object_count.instances == count.instances + 1); + BOOST_TEST_EQ(test::global_object_count.instances, count.instances + 1); BOOST_TEST_EQ(test::global_object_count.constructions, count.constructions + 1); count = test::global_object_count; dst.emplace(src); - BOOST_TEST_EQ(test::global_object_count, count); + BOOST_TEST_EQ(test::global_object_count.instances, count.instances); + BOOST_TEST(test::global_object_count.constructions <= count.constructions + 1); } RUN_TESTS() From d0a3efab6a3a4096c07da28e506cc353f2e7a092 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 29 Sep 2009 07:46:44 +0000 Subject: [PATCH 113/471] Just remove the test since the test itself doesn't work on most compilers. [SVN r56468] --- test/unordered/Jamfile.v2 | 1 - test/unordered/insert_range_tests.cpp | 41 --------------------------- 2 files changed, 42 deletions(-) delete mode 100644 test/unordered/insert_range_tests.cpp diff --git a/test/unordered/Jamfile.v2 b/test/unordered/Jamfile.v2 index ce89396a..ee1505f7 100644 --- a/test/unordered/Jamfile.v2 +++ b/test/unordered/Jamfile.v2 @@ -27,7 +27,6 @@ test-suite unordered [ run move_tests.cpp : : : always_show_run_output ] [ run assign_tests.cpp ] [ run insert_tests.cpp ] - [ run insert_range_tests.cpp ] [ run insert_stable_tests.cpp ] [ run unnecessary_copy_tests.cpp ] [ run erase_tests.cpp ] diff --git a/test/unordered/insert_range_tests.cpp b/test/unordered/insert_range_tests.cpp deleted file mode 100644 index b9234796..00000000 --- a/test/unordered/insert_range_tests.cpp +++ /dev/null @@ -1,41 +0,0 @@ - -// Copyright 2006-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 -#include -#include -#include "../helpers/test.hpp" -#include "../objects/test.hpp" - -UNORDERED_AUTO_TEST(needless_copies_1) { - std::vector > src; - src.push_back(std::pair(test::object(1, 2), 0)); - - boost::unordered_map dst; - dst[test::object(1, 2)] = 0; - - test::object_count count = test::global_object_count; - dst.insert(src.begin(), src.end()); - BOOST_TEST(count == test::global_object_count); -} - -UNORDERED_AUTO_TEST(needless_copies_2) { - test::object x(1, 2); - std::pair src(x, 0); - - boost::unordered_map dst; - - test::object_count count = test::global_object_count; - dst.emplace(src); - BOOST_TEST_EQ(test::global_object_count.instances, count.instances + 1); - BOOST_TEST_EQ(test::global_object_count.constructions, count.constructions + 1); - - count = test::global_object_count; - dst.emplace(src); - BOOST_TEST_EQ(test::global_object_count.instances, count.instances); - BOOST_TEST(test::global_object_count.constructions <= count.constructions + 1); -} - -RUN_TESTS() From 63e04cfb604101e595a50fb7c1fdeab82f81bd57 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 3 Oct 2009 16:40:26 +0000 Subject: [PATCH 114/471] Fix the iterator category. [SVN r56557] --- doc/ref.xml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/ref.xml b/doc/ref.xml index 67a2179b..59f2df51 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -93,7 +93,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 +101,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. @@ -831,7 +831,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 +839,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. @@ -1579,7 +1579,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 +1587,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. @@ -2366,7 +2366,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 +2374,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. From 55eafdf0eef5dca21519d7052b13a40ce806dac1 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 3 Oct 2009 16:40:53 +0000 Subject: [PATCH 115/471] Update reference docs to latest version of draft standard and fill in some missing details. [SVN r56558] --- doc/ref.xml | 244 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 236 insertions(+), 8 deletions(-) diff --git a/doc/ref.xml b/doc/ref.xml index 59f2df51..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 @@ -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 @@ -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 @@ -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 @@ -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 From 4601f5c51f6fb4d797c02ab8e948811ffe1f6b0d Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 3 Oct 2009 16:41:11 +0000 Subject: [PATCH 116/471] Stricter insert exception tests. [SVN r56559] --- test/exception/insert_exception_tests.cpp | 14 +++++++------- test/helpers/strong.hpp | 8 ++++++-- 2 files changed, 13 insertions(+), 9 deletions(-) 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."); } }; } From 1e24f85fbc7375fb2a586b17f46b5de3c7d1881d Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 3 Oct 2009 16:41:32 +0000 Subject: [PATCH 117/471] Insert using initializer lists. [SVN r56560] --- include/boost/unordered/unordered_map.hpp | 14 +++++++ include/boost/unordered/unordered_set.hpp | 14 +++++++ test/unordered/insert_tests.cpp | 48 +++++++++++++++++++++++ 3 files changed, 76 insertions(+) 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/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 6a4f4d86..30f6d28d 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -372,6 +372,54 @@ UNORDERED_TEST(associative_insert_range_test, ((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 788a3661a25dbbe0ae05a9df6e01d786d5d4d920 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 3 Oct 2009 16:42:00 +0000 Subject: [PATCH 118/471] Update the unordered rationale. [SVN r56561] --- doc/intro.qbk | 2 +- doc/rationale.qbk | 122 ++++++++++++---------------------------------- 2 files changed, 31 insertions(+), 93 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] From ae0c97a77af4d323195a6546dfef3fccecd2a373 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 3 Oct 2009 16:42:20 +0000 Subject: [PATCH 119/471] Make sure inserting from a range of types other than the value type is better tested. [SVN r56562] --- include/boost/unordered/detail/unique.hpp | 7 +++--- test/unordered/insert_tests.cpp | 27 ++++++++++++++++++++--- 2 files changed, 27 insertions(+), 7 deletions(-) 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/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 30f6d28d..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,7 +383,12 @@ 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)) ) From fe3d612fe0fe4d3e2c2ba3876d19ec2ec537b2bc Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 4 Oct 2009 10:37:36 +0000 Subject: [PATCH 120/471] Clean up some unordered TODOs. [SVN r56570] --- include/boost/unordered/detail/buckets.hpp | 3 +- include/boost/unordered/detail/equivalent.hpp | 1 - include/boost/unordered/detail/table.hpp | 17 +++----- test/unordered/rehash_tests.cpp | 43 +++++++++++++++++++ 4 files changed, 50 insertions(+), 14 deletions(-) diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index 8a2163c6..332acf2d 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_; 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..90c333f8 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -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/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 373791d0b22d388973104733ccd7005816b7bbc7 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 4 Oct 2009 10:37:56 +0000 Subject: [PATCH 121/471] Detab. [SVN r56571] --- include/boost/unordered/detail/buckets.hpp | 2 +- include/boost/unordered/detail/table.hpp | 2 +- test/helpers/list.hpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index 332acf2d..759c2e48 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -156,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_; diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 90c333f8..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 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_; From 854dc0b353cdbb8304d8e7f649cbc68263fc79ea Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 5 Oct 2009 21:29:39 +0000 Subject: [PATCH 122/471] Various inspect fixes. [SVN r56603] --- include/boost/unordered/detail/buckets.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index 759c2e48..0f513e44 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -167,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_); } From 4e07c94502b81ac99a6dab88ad2328a61740a8ea Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 10 Oct 2009 15:09:02 +0000 Subject: [PATCH 123/471] Copy the unordered and hash CMake files from release. [SVN r56704] --- CMakeLists.txt | 2 +- test/CMakeLists.txt | 61 ++--------------------------------- test/exception/CMakeLists.txt | 25 ++++++++++++++ test/unordered/CMakeLists.txt | 43 ++++++++++++++++++++++++ 4 files changed, 71 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 c1213cbd..b7dd577c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,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 a2df088e..a941b96f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -18,64 +18,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..aacdf3d9 --- /dev/null +++ b/test/exception/CMakeLists.txt @@ -0,0 +1,25 @@ +# +# 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 new file mode 100644 index 00000000..68d92be8 --- /dev/null +++ b/test/unordered/CMakeLists.txt @@ -0,0 +1,43 @@ +# +# 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 3dff89c240ab232d19a4ff095272555deb932b7a Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 14 Oct 2009 20:30:48 +0000 Subject: [PATCH 124/471] Correct macro checks for initializer lists. [SVN r56844] --- 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 0702e4e6..e1b96087 100644 --- a/test/unordered/constructor_tests.cpp +++ b/test/unordered/constructor_tests.cpp @@ -312,7 +312,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 a277cbb7..866e4fea 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 51fdfa7ac75ab196cf1e2300f93d24b25cce336f Mon Sep 17 00:00:00 2001 From: "Troy D. Straszheim" Date: Sat, 17 Oct 2009 02:07:38 +0000 Subject: [PATCH 125/471] rm cmake from trunk. I'm not entirely sure this is necessary to satisfy the inspect script, but I'm not taking any chances, and it is easy to put back [SVN r56942] --- 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 6c24cccf96d6b59930078675783f179498401fa9 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 18 Oct 2009 20:18:28 +0000 Subject: [PATCH 126/471] Add release notes for unordered. [SVN r56988] --- 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 8d4b503e56bada1418f7f80bcbd9f59bfb31ca36 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 19 Oct 2009 19:24:33 +0000 Subject: [PATCH 127/471] 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. [SVN r57005] --- include/boost/unordered/detail/equivalent.hpp | 61 ------------------- include/boost/unordered/detail/fwd.hpp | 10 +-- include/boost/unordered/unordered_map.hpp | 21 +++---- include/boost/unordered/unordered_set.hpp | 19 +++--- 4 files changed, 20 insertions(+), 91 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..92125fc9 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -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); } @@ -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..1d661deb 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -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); } @@ -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 From 2fdd33381c4c73121e14b844a987d2ffcc3b0ff6 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 19 Oct 2009 19:32:09 +0000 Subject: [PATCH 128/471] Fix allocator for construct from initializer list. [SVN r57006] --- include/boost/unordered/unordered_map.hpp | 4 +- include/boost/unordered/unordered_set.hpp | 4 +- test/unordered/constructor_tests.cpp | 53 +++++++++++++++++++++++ 3 files changed, 57 insertions(+), 4 deletions(-) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 92125fc9..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()); } @@ -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()); } diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 1d661deb..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()); } @@ -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()); } diff --git a/test/unordered/constructor_tests.cpp b/test/unordered/constructor_tests.cpp index e1b96087..5a719e2a 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 5bedbde746aa1b164cbefd175c36093797d4d1a0 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 24 Oct 2009 11:56:30 +0000 Subject: [PATCH 129/471] Update the intel compile flags. [SVN r57126] --- test/exception/Jamfile.v2 | 6 +----- test/unordered/Jamfile.v2 | 6 +++--- 2 files changed, 4 insertions(+), 8 deletions(-) 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..d41d0229 100644 --- a/test/unordered/Jamfile.v2 +++ b/test/unordered/Jamfile.v2 @@ -7,10 +7,10 @@ import testing ; project unordered-test/unordered : requirements - intel-linux:"-strict_ansi -cxxlib-icc" - gcc:"-Wsign-promo -Wunused-parameter" - #msvc:/W4 all + intel:on + msvc:/W4 + gcc:"-Wsign-promo -Wunused-parameter" ; test-suite unordered From 6bac25221ab8649d4ae3ec063bfec0d7aae0afff Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 24 Oct 2009 17:53:03 +0000 Subject: [PATCH 130/471] Fix unordered for intel strict. [SVN r57139] --- include/boost/unordered/detail/equivalent.hpp | 10 +++++----- include/boost/unordered/detail/unique.hpp | 17 ++++++++--------- test/unordered/Jamfile.v2 | 2 +- 3 files changed, 14 insertions(+), 15 deletions(-) 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/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/unordered/Jamfile.v2 b/test/unordered/Jamfile.v2 index d41d0229..55451718 100644 --- a/test/unordered/Jamfile.v2 +++ b/test/unordered/Jamfile.v2 @@ -8,7 +8,7 @@ import testing ; project unordered-test/unordered : requirements all - intel:on + intel:on -strict_ansi msvc:/W4 gcc:"-Wsign-promo -Wunused-parameter" ; From 8cde8d12527d3636d35346d2b768dc3e41743050 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 25 Oct 2009 10:54:28 +0000 Subject: [PATCH 131/471] Fix the intel strict flag. [SVN r57150] --- test/unordered/Jamfile.v2 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/unordered/Jamfile.v2 b/test/unordered/Jamfile.v2 index 55451718..d21e3da1 100644 --- a/test/unordered/Jamfile.v2 +++ b/test/unordered/Jamfile.v2 @@ -8,7 +8,8 @@ import testing ; project unordered-test/unordered : requirements all - intel:on -strict_ansi + intel:on + intel:-strict-ansi msvc:/W4 gcc:"-Wsign-promo -Wunused-parameter" ; From 8727de1a1b690bdb6907e45bf92a82b4965cca02 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 25 Oct 2009 10:54:53 +0000 Subject: [PATCH 132/471] Remove insert empty initializer lists, as there's a bug in gcc. [SVN r57151] --- test/unordered/insert_tests.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 866e4fea..69d1c67c 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -408,7 +408,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); @@ -424,7 +424,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); @@ -433,7 +433,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 060acb3f250f84eca898c49e3a5d4fd680a406e5 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 25 Oct 2009 10:55:08 +0000 Subject: [PATCH 133/471] Slightly rearrange the unordered container headers so that prev_prime is defined before it's used. [SVN r57152] --- include/boost/unordered/detail/buckets.hpp | 7 +++++++ include/boost/unordered/detail/fwd.hpp | 5 +---- include/boost/unordered/detail/table.hpp | 1 - test/unordered/Jamfile.v2 | 2 +- 4 files changed, 9 insertions(+), 6 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/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index 3a5e3f73..a7298780 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 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/test/unordered/Jamfile.v2 b/test/unordered/Jamfile.v2 index d21e3da1..882ec132 100644 --- a/test/unordered/Jamfile.v2 +++ b/test/unordered/Jamfile.v2 @@ -11,7 +11,7 @@ project unordered-test/unordered intel:on intel:-strict-ansi msvc:/W4 - gcc:"-Wsign-promo -Wunused-parameter" + gcc:"-Wsign-promo -Wunused-parameter -pedantic" ; test-suite unordered From b4f08db39114c7ec99d9dac6e372396458e813b4 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 25 Oct 2009 10:55:27 +0000 Subject: [PATCH 134/471] Remove 'grouped' from hash_table as it isn't used and is a bit confusing. [SVN r57153] --- include/boost/unordered/detail/fwd.hpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index a7298780..5696cbca 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -440,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; @@ -572,7 +571,7 @@ namespace boost { namespace unordered_detail { template class hash_unique_table : - public hash_table + public hash_table { public: @@ -666,7 +665,7 @@ namespace boost { namespace unordered_detail { template class hash_equivalent_table : - public hash_table + public hash_table { public: @@ -675,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; From ba5c383877cfc274814c0a252fdc4d188d989912 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 10 Nov 2009 08:15:55 +0000 Subject: [PATCH 135/471] Stricter warnings for unordered and hash. There are still warnings in hash_complex_test. [SVN r57537] --- test/exception/Jamfile.v2 | 13 +++++- test/exception/assign_exception_tests.cpp | 4 ++ test/exception/swap_exception_tests.cpp | 4 ++ test/helpers/exception_test.hpp | 3 ++ test/helpers/input_iterator.hpp | 2 + test/helpers/list.hpp | 19 ++++++++- test/helpers/strong.hpp | 2 +- test/helpers/tracker.hpp | 4 +- test/unordered/Jamfile.v2 | 10 +++-- test/unordered/equality_tests.cpp | 52 +++++++++++------------ test/unordered/erase_tests.cpp | 2 +- 11 files changed, 80 insertions(+), 35 deletions(-) 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..f059e0f7 100644 --- a/test/exception/assign_exception_tests.cpp +++ b/test/exception/assign_exception_tests.cpp @@ -7,6 +7,10 @@ #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 diff --git a/test/exception/swap_exception_tests.cpp b/test/exception/swap_exception_tests.cpp index 2025b8bd..e884cb11 100644 --- a/test/exception/swap_exception_tests.cpp +++ b/test/exception/swap_exception_tests.cpp @@ -7,6 +7,10 @@ #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 diff --git a/test/helpers/exception_test.hpp b/test/helpers/exception_test.hpp index a235526c..e64d168c 100644 --- a/test/helpers/exception_test.hpp +++ b/test/helpers/exception_test.hpp @@ -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/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/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..5cae0605 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 diff --git a/test/unordered/equality_tests.cpp b/test/unordered/equality_tests.cpp index bfc78f1b..73633a06 100644 --- a/test/unordered/equality_tests.cpp +++ b/test/unordered/equality_tests.cpp @@ -29,36 +29,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 +89,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/erase_tests.cpp b/test/unordered/erase_tests.cpp index 74fc6d1f..36ce40a2 100644 --- a/test/unordered/erase_tests.cpp +++ b/test/unordered/erase_tests.cpp @@ -65,7 +65,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(); From 574783675446c21db0b1579b1915acc42d32ea80 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 10 Nov 2009 18:17:53 +0000 Subject: [PATCH 136/471] Change unordered move tests to be more lenient on compilers without NRVO. Will probably need to reintroduce some of the failure markup later. [SVN r57550] --- test/unordered/move_tests.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/unordered/move_tests.cpp b/test/unordered/move_tests.cpp index 3d06686b..20f35c35 100644 --- a/test/unordered/move_tests.cpp +++ b/test/unordered/move_tests.cpp @@ -64,7 +64,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 +80,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 +102,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)); From 4438b8e01727e1d488dd67e937bf92ba36a9fd79 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 10 Nov 2009 20:07:50 +0000 Subject: [PATCH 137/471] Fix a warning that only shows up in release builds. [SVN r57556] --- include/boost/unordered/detail/fwd.hpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index 5696cbca..5b904344 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 @@ -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 From ab843eb5877bc52e74a845a2c34343b95b6b1297 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 12 Nov 2009 21:36:27 +0000 Subject: [PATCH 138/471] Fix a warning on Visual C++ 7.1. Although, I don't think I'm going to be warning free on the compiler. [SVN r57617] --- include/boost/unordered/detail/fwd.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index 5b904344..53ef556d 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -179,6 +179,8 @@ namespace boost { namespace unordered_detail { value_type& value() { return *(ValueType*) this; } + private: + value_base& operator=(value_base const&); }; // Node @@ -195,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 From 55957bbab57e973b8cb0edf61e59998ce997f8a8 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 16 Nov 2009 23:56:37 +0000 Subject: [PATCH 139/471] Some more warning fixes for Visual C++ 7.1 [SVN r57719] --- include/boost/unordered/detail/fwd.hpp | 2 -- test/helpers/invariants.hpp | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index 53ef556d..69098b8f 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -74,9 +74,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 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 From 26c72f9860e188649828e8a91d6e69ab99c1b310 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 20 Nov 2009 08:02:48 +0000 Subject: [PATCH 140/471] Use 'E' for key extractor, freeing 'K' for key. [SVN r57797] --- include/boost/unordered/detail/equivalent.hpp | 46 ++--- include/boost/unordered/detail/fwd.hpp | 22 +-- include/boost/unordered/detail/table.hpp | 168 +++++++++--------- include/boost/unordered/detail/unique.hpp | 90 +++++----- 4 files changed, 163 insertions(+), 163 deletions(-) diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 970c18bc..097dd60f 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/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index 69098b8f..f925dbc6 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -29,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) @@ -424,7 +424,7 @@ namespace boost { namespace unordered_detail { } }; - template + template class hash_table : public hash_buckets, public hash_buffered_functions @@ -434,7 +434,7 @@ namespace boost { namespace unordered_detail { typedef H hasher; typedef P key_equal; typedef A value_allocator; - typedef K key_extractor; + typedef E key_extractor; typedef hash_buffered_functions base; typedef hash_buckets buckets; @@ -563,18 +563,18 @@ namespace boost { namespace unordered_detail { node_constructor&, std::size_t); }; - template + template class hash_unique_table : - public hash_table + public hash_table { public: typedef H hasher; typedef P key_equal; typedef A value_allocator; - typedef K key_extractor; + typedef E key_extractor; - typedef hash_table table; + typedef hash_table table; typedef hash_node_constructor node_constructor; typedef BOOST_DEDUCED_TYPENAME table::key_type key_type; @@ -657,18 +657,18 @@ namespace boost { namespace unordered_detail { void insert_range_impl(no_key, InputIt i, InputIt j); }; - template + template class hash_equivalent_table : - public hash_table + public hash_table { public: typedef H hasher; typedef P key_equal; typedef A value_allocator; - typedef K key_extractor; + typedef E key_extractor; - typedef hash_table table; + typedef hash_table table; typedef hash_node_constructor node_constructor; typedef hash_iterator_base iterator_base; diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 66c9d744..4fe86b88 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 hash_table::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 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( + 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_; @@ -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,8 +290,8 @@ 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. @@ -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; @@ -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,8 +364,8 @@ 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. @@ -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_); @@ -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 hash_table::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 + template BOOST_DEDUCED_TYPENAME A::value_type& - hash_table::at(key_type const& k) const + 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 hash_table::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 hash_table::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 hash_table::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..3d89d7db 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,11 +231,11 @@ 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)) \ { \ @@ -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); From df72c4886f7d267a0308e2996e97c45c0b2926cb Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 20 Nov 2009 08:03:26 +0000 Subject: [PATCH 141/471] Support incomplete template parameters to unordered containers. [SVN r57798] --- include/boost/unordered/detail/equivalent.hpp | 46 ++-- .../boost/unordered/detail/extract_key.hpp | 214 +++++++++--------- include/boost/unordered/detail/fwd.hpp | 193 ++++++++++------ 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/helpers/allocator.hpp | 4 +- test/unordered/Jamfile.v2 | 1 + test/unordered/incomplete_test.cpp | 39 ++++ 10 files changed, 458 insertions(+), 354 deletions(-) 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 097dd60f..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..184600d2 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 Key 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 f925dbc6..ff3d63e9 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -66,7 +66,9 @@ namespace boost { namespace unordered_detail { template class hash_node_constructor; + template struct set_extractor; + template struct map_extractor; struct no_key; @@ -208,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_; @@ -268,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; @@ -424,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 E 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 @@ -563,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 E 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; @@ -657,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 E 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 @@ -963,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 4fe86b88..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 3d89d7db..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/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/unordered/Jamfile.v2 b/test/unordered/Jamfile.v2 index 5cae0605..2fdfd357 100644 --- a/test/unordered/Jamfile.v2 +++ b/test/unordered/Jamfile.v2 @@ -25,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/incomplete_test.cpp b/test/unordered/incomplete_test.cpp new file mode 100644 index 00000000..01f4c530 --- /dev/null +++ b/test/unordered/incomplete_test.cpp @@ -0,0 +1,39 @@ + +// 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 +#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; + + m1[test::value()] = test::value(); + m2.insert(std::make_pair(test::value(), test::value())); + s1.insert(test::value()); + s2.insert(test::value()); +} \ No newline at end of file From 3882a610659a703a1bb40de9f20d50f550f7ead3 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 21 Nov 2009 19:40:28 +0000 Subject: [PATCH 142/471] Inspect fixes. [SVN r57838] --- test/exception/assign_exception_tests.cpp | 6 ++++-- test/exception/erase_exception_tests.cpp | 2 +- test/exception/insert_exception_tests.cpp | 6 +++--- test/exception/rehash_exception_tests.cpp | 4 +++- test/exception/swap_exception_tests.cpp | 4 ++-- test/helpers/exception_test.hpp | 2 +- test/unordered/incomplete_test.cpp | 2 +- 7 files changed, 15 insertions(+), 11 deletions(-) diff --git a/test/exception/assign_exception_tests.cpp b/test/exception/assign_exception_tests.cpp index f059e0f7..a6c92945 100644 --- a/test/exception/assign_exception_tests.cpp +++ b/test/exception/assign_exception_tests.cpp @@ -22,7 +22,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 @@ -52,7 +53,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/erase_exception_tests.cpp b/test/exception/erase_exception_tests.cpp index 6746d628..4c944a1d 100644 --- a/test/exception/erase_exception_tests.cpp +++ b/test/exception/erase_exception_tests.cpp @@ -22,7 +22,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..5dc7611b 100644 --- a/test/exception/insert_exception_tests.cpp +++ b/test/exception/insert_exception_tests.cpp @@ -27,7 +27,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 +92,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 +215,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..8a6c6d22 100644 --- a/test/exception/rehash_exception_tests.cpp +++ b/test/exception/rehash_exception_tests.cpp @@ -28,7 +28,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 e884cb11..ed370e2d 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 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 @@ -77,7 +77,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/exception_test.hpp b/test/helpers/exception_test.hpp index e64d168c..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 diff --git a/test/unordered/incomplete_test.cpp b/test/unordered/incomplete_test.cpp index 01f4c530..7bfaf7bc 100644 --- a/test/unordered/incomplete_test.cpp +++ b/test/unordered/incomplete_test.cpp @@ -36,4 +36,4 @@ int main() { m2.insert(std::make_pair(test::value(), test::value())); s1.insert(test::value()); s2.insert(test::value()); -} \ No newline at end of file +} From 1f17294cd3983402fe05ded92f05f0c548286c81 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 21 Nov 2009 20:37:50 +0000 Subject: [PATCH 143/471] Use remove_const again. [SVN r57840] --- include/boost/unordered/detail/extract_key.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/extract_key.hpp b/include/boost/unordered/detail/extract_key.hpp index 184600d2..bedb175f 100644 --- a/include/boost/unordered/detail/extract_key.hpp +++ b/include/boost/unordered/detail/extract_key.hpp @@ -75,7 +75,7 @@ namespace unordered_detail { struct map_extractor { typedef ValueType value_type; - typedef Key key_type; + typedef BOOST_DEDUCED_TYPENAME boost::remove_const::type key_type; static key_type const& extract(value_type const& v) { From d3fe62a6465b82f5b081e976ac27018fd4237e54 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 25 Nov 2009 09:09:25 +0000 Subject: [PATCH 144/471] Try to avoid an odd warning from Visual C++ [SVN r57919] --- test/unordered/incomplete_test.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/unordered/incomplete_test.cpp b/test/unordered/incomplete_test.cpp index 7bfaf7bc..32cca272 100644 --- a/test/unordered/incomplete_test.cpp +++ b/test/unordered/incomplete_test.cpp @@ -32,8 +32,9 @@ int main() { test::set s1; test::multiset s2; - m1[test::value()] = test::value(); - m2.insert(std::make_pair(test::value(), test::value())); - s1.insert(test::value()); - s2.insert(test::value()); + test::value x; + m1[x] = x; + m2.insert(std::make_pair(x, x)); + s1.insert(x); + s2.insert(x); } From 7b2c5189b3bef06e129f83c56999e0b0f16fdd5a Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 25 Nov 2009 09:14:16 +0000 Subject: [PATCH 145/471] Suppress some warnings on visual c++ 7.1. [SVN r57921] --- test/unordered/bucket_tests.cpp | 5 +++++ test/unordered/compile_tests.hpp | 2 ++ test/unordered/erase_equiv_tests.cpp | 5 +++++ 3 files changed, 12 insertions(+) diff --git a/test/unordered/bucket_tests.cpp b/test/unordered/bucket_tests.cpp index eeaa625a..94ebcf98 100644 --- a/test/unordered/bucket_tests.cpp +++ b/test/unordered/bucket_tests.cpp @@ -11,6 +11,11 @@ #include "../helpers/random_values.hpp" #include "../helpers/helpers.hpp" +#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) +#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_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/erase_equiv_tests.cpp b/test/unordered/erase_equiv_tests.cpp index a1bebf45..c18751d2 100644 --- a/test/unordered/erase_equiv_tests.cpp +++ b/test/unordered/erase_equiv_tests.cpp @@ -15,6 +15,11 @@ #include #include "../objects/test.hpp" +#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) +#pragma warning(disable:4267) // conversion from 'size_t' to 'unsigned int', + // possible loss of data. +#endif + struct write_pair_type { template From 0dcf1b5cd26cf34bd1b8bdcf8352b516f6c46011 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 26 Nov 2009 23:14:53 +0000 Subject: [PATCH 146/471] Fix the version check when suppressing warnings. [SVN r57962] --- test/unordered/bucket_tests.cpp | 2 +- test/unordered/erase_equiv_tests.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unordered/bucket_tests.cpp b/test/unordered/bucket_tests.cpp index 94ebcf98..bb3829b7 100644 --- a/test/unordered/bucket_tests.cpp +++ b/test/unordered/bucket_tests.cpp @@ -11,7 +11,7 @@ #include "../helpers/random_values.hpp" #include "../helpers/helpers.hpp" -#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) +#if BOOST_WORKAROUND(BOOST_MSVC, < 1400) #pragma warning(disable:4267) // conversion from 'size_t' to 'unsigned int', // possible loss of data. #endif diff --git a/test/unordered/erase_equiv_tests.cpp b/test/unordered/erase_equiv_tests.cpp index c18751d2..e1120d2f 100644 --- a/test/unordered/erase_equiv_tests.cpp +++ b/test/unordered/erase_equiv_tests.cpp @@ -15,7 +15,7 @@ #include #include "../objects/test.hpp" -#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) +#if BOOST_WORKAROUND(BOOST_MSVC, < 1400) #pragma warning(disable:4267) // conversion from 'size_t' to 'unsigned int', // possible loss of data. #endif From 7023460394462fa9c445aea139a742bfad43aa83 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 26 Nov 2009 23:15:30 +0000 Subject: [PATCH 147/471] Suppress a warning that's in the windows mobile system headers. [SVN r57963] --- test/exception/assign_exception_tests.cpp | 2 ++ test/exception/constructor_exception_tests.cpp | 2 ++ test/exception/copy_exception_tests.cpp | 2 ++ test/exception/erase_exception_tests.cpp | 2 ++ test/exception/insert_exception_tests.cpp | 2 ++ test/exception/rehash_exception_tests.cpp | 2 ++ test/exception/swap_exception_tests.cpp | 2 ++ test/helpers/prefix.hpp | 10 ++++++++++ test/unordered/assign_tests.cpp | 2 ++ test/unordered/at_tests.cpp | 2 ++ test/unordered/bucket_tests.cpp | 2 ++ test/unordered/compile_map.cpp | 2 ++ test/unordered/compile_set.cpp | 2 ++ test/unordered/constructor_tests.cpp | 2 ++ test/unordered/copy_tests.cpp | 2 ++ test/unordered/equality_tests.cpp | 2 ++ test/unordered/equivalent_keys_tests.cpp | 2 ++ test/unordered/erase_equiv_tests.cpp | 2 ++ test/unordered/erase_tests.cpp | 2 ++ 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 | 2 ++ 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 | 2 ++ 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 ++ 33 files changed, 74 insertions(+) create mode 100644 test/helpers/prefix.hpp diff --git a/test/exception/assign_exception_tests.cpp b/test/exception/assign_exception_tests.cpp index a6c92945..bdb99c15 100644 --- a/test/exception/assign_exception_tests.cpp +++ b/test/exception/assign_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" 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 4c944a1d..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" diff --git a/test/exception/insert_exception_tests.cpp b/test/exception/insert_exception_tests.cpp index 5dc7611b..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" diff --git a/test/exception/rehash_exception_tests.cpp b/test/exception/rehash_exception_tests.cpp index 8a6c6d22..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" diff --git a/test/exception/swap_exception_tests.cpp b/test/exception/swap_exception_tests.cpp index ed370e2d..a3cfe823 100644 --- a/test/exception/swap_exception_tests.cpp +++ b/test/exception/swap_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" 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/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 bb3829b7..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" 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/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 73633a06..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 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 e1120d2f..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" diff --git a/test/unordered/erase_tests.cpp b/test/unordered/erase_tests.cpp index 36ce40a2..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" 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 index 32cca272..b1666c9e 100644 --- a/test/unordered/incomplete_test.cpp +++ b/test/unordered/incomplete_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 #include 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 20f35c35..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" 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 7f59e8e0581d7424d3e856cdc28c670345fa5c18 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 27 Nov 2009 19:43:06 +0000 Subject: [PATCH 148/471] Better testing of incomplete types. [SVN r57975] --- test/unordered/incomplete_test.cpp | 112 ++++++++++++++++++++++++++--- 1 file changed, 103 insertions(+), 9 deletions(-) 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(); } From 3e638049eca5a36e6f7122758aa6537892cef26e Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 28 Nov 2009 11:46:05 +0000 Subject: [PATCH 149/471] Try to support incomplete types for Sun - at the expense of zero argument emplace. [SVN r58002] --- include/boost/unordered/unordered_map.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index b0034116..00c27ef8 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -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 < \ @@ -786,6 +788,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 +799,7 @@ namespace boost { return iterator(table_.emplace(v)); } - + #endif #define BOOST_UNORDERED_EMPLACE(z, n, _) \ template < \ From ef67d9ae124464f2526d954002f6249d0703d67c Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 28 Nov 2009 11:46:24 +0000 Subject: [PATCH 150/471] Document the unordered changes. [SVN r58004] --- doc/changes.qbk | 5 +++++ 1 file changed, 5 insertions(+) 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] From a1252fcc0e86617fb5ae8183cf31e1edb47e3ee1 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 30 Nov 2009 18:25:26 +0000 Subject: [PATCH 151/471] Use consistent names for template parameters. I'm trying to fix the codegear ICEs, but it's hard to tell the cause. Since the error happens operator== I suspect it's either to do with defining friend functions with different template names or something to do with friend functions in general. This is the first stab in the dark at fixing this. [SVN r58062] --- include/boost/unordered/unordered_map.hpp | 40 +++++++++---------- include/boost/unordered/unordered_map_fwd.hpp | 16 ++++---- include/boost/unordered/unordered_set.hpp | 40 +++++++++---------- include/boost/unordered/unordered_set_fwd.hpp | 16 ++++---- 4 files changed, 56 insertions(+), 56 deletions(-) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 00c27ef8..10d72829 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()) { @@ -513,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 @@ -541,17 +541,17 @@ namespace boost 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: @@ -562,7 +562,7 @@ namespace boost allocator_type, value_type>::type value_allocator; - typedef boost::unordered_detail::multimap types; typedef BOOST_DEDUCED_TYPENAME types::impl table; @@ -682,7 +682,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()) { @@ -1002,9 +1002,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 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..f2af28af 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 @@ -506,16 +506,16 @@ namespace boost 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 +526,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 +640,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 +943,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 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&, From c8b893cb77205de761297e48fdcc691fcc6e6e03 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 4 Dec 2009 00:51:50 +0000 Subject: [PATCH 152/471] Workaround codegear ICE. It seems that the problem is calling sizeof on a dependent type when the containers have only been used by reference. So by putting in these dummy structures with the containers as members, it helps the compiler instantiate the class to the level where sizeof works. I hope. [SVN r58130] --- include/boost/unordered/detail/util.hpp | 3 +++ include/boost/unordered/unordered_map.hpp | 18 ++++++++++++++++++ include/boost/unordered/unordered_set.hpp | 18 ++++++++++++++++++ test/unordered/link_test_2.cpp | 9 +++++++++ 4 files changed, 48 insertions(+) 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 10d72829..ef649897 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -524,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_); } @@ -531,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_); } @@ -538,6 +544,9 @@ 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); } @@ -1013,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_); } @@ -1020,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_); } @@ -1027,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_set.hpp b/include/boost/unordered/unordered_set.hpp index f2af28af..59843fd6 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -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,6 +509,9 @@ 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); } @@ -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/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 18a5010436f695a29ea5905d8ed0b966f1dd9395 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 4 Dec 2009 19:44:34 +0000 Subject: [PATCH 153/471] Remove use of iterator_adaptor in unordered tests. [SVN r58144] --- .../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/insert_tests.cpp | 4 +- 5 files changed, 49 insertions(+), 20 deletions(-) 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/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); From 618a51df1310585ca528c72e25f8bd1f9d666d83 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 15 Dec 2009 13:16:32 +0000 Subject: [PATCH 154/471] Turn off warnings as errors on gcc/darwin because the integer library currently causes some warnings. [SVN r58394] --- test/exception/Jamfile.v2 | 4 ++-- test/unordered/Jamfile.v2 | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) 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 From 2f0a94bcfd9afaa6c0ff850c8e80e3bcce34ac45 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 15 Dec 2009 22:42:04 +0000 Subject: [PATCH 155/471] Add missing std:: qualifier to ptrdiff_t. Refs #3773. [SVN r58402] --- doc/changes.qbk | 2 ++ include/boost/unordered/detail/buckets.hpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index d1b26254..790e3863 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -107,5 +107,7 @@ First official release. * Support instantiating the containers with incomplete value types. * Reduced the number of warnings (mostly in tests). +* [@http://svn.boost.org/trac/boost/ticket/3773 Ticket 3773]: + Add missing `std` qualifier to `ptrdiff_t`. [endsect] 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 From 4e6292b439f7109f0f308411fd6728840eef3e60 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 15 Dec 2009 22:52:52 +0000 Subject: [PATCH 156/471] Implement an alternative erase function that doesn't return an iterator. Ref #3693 [SVN r58403] --- doc/changes.qbk | 4 + doc/ref.xml | 120 ++++++++++++++++++++++ include/boost/unordered/detail/fwd.hpp | 3 +- include/boost/unordered/detail/table.hpp | 12 ++- include/boost/unordered/unordered_map.hpp | 14 ++- include/boost/unordered/unordered_set.hpp | 14 ++- test/unordered/erase_tests.cpp | 49 +++++++++ 7 files changed, 210 insertions(+), 6 deletions(-) diff --git a/doc/changes.qbk b/doc/changes.qbk index 790e3863..adddc366 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -107,6 +107,10 @@ First official release. * Support instantiating the containers with incomplete value types. * Reduced the number of warnings (mostly in tests). +* [@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. * [@http://svn.boost.org/trac/boost/ticket/3773 Ticket 3773]: Add missing `std` qualifier to `ptrdiff_t`. diff --git a/doc/ref.xml b/doc/ref.xml index 4ca51abf..b55b5492 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 @@ -1252,6 +1282,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 +1326,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 @@ -2059,6 +2119,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 +2163,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 @@ -2901,6 +2991,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 +3035,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 diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index ff3d63e9..7128dbe9 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -532,7 +532,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..ab95f595 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -652,10 +652,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..712f769c 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(); @@ -868,7 +873,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 +886,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(); diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 59843fd6..6982cf93 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(); @@ -822,7 +827,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 +840,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(); 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); From 493f905598f6822f71175590c2cc46243418269c Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 15 Dec 2009 22:53:08 +0000 Subject: [PATCH 157/471] Fix the return type of find in the unordered reference documentation. [SVN r58404] --- doc/ref.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/ref.xml b/doc/ref.xml index b55b5492..a245397d 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -574,7 +574,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) key_type const& - iterator + const_iterator An iterator pointing to an element with key equivalent to k, or b.end() if no such element exists. @@ -1397,7 +1397,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) key_type const& - iterator + const_iterator An iterator pointing to an element with key equivalent to k, or b.end() if no such element exists. @@ -2234,7 +2234,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) key_type const& - iterator + const_iterator An iterator pointing to an element with key equivalent to k, or b.end() if no such element exists. @@ -3106,7 +3106,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) key_type const& - iterator + const_iterator An iterator pointing to an element with key equivalent to k, or b.end() if no such element exists. From b99382b551bec410466decf1f849524565ff2acc Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 15 Dec 2009 22:53:33 +0000 Subject: [PATCH 158/471] Add templated find overload for compatible keys. [SVN r58405] --- doc/changes.qbk | 1 + doc/ref.xml | 136 ++++++++++++++++++++++ include/boost/unordered/detail/fwd.hpp | 5 + include/boost/unordered/detail/table.hpp | 33 ++++++ include/boost/unordered/unordered_map.hpp | 40 +++++++ include/boost/unordered/unordered_set.hpp | 19 +++ test/unordered/find_tests.cpp | 53 +++++++++ 7 files changed, 287 insertions(+) diff --git a/doc/changes.qbk b/doc/changes.qbk index adddc366..4bdcdaa3 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -111,6 +111,7 @@ First official release. 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`. diff --git a/doc/ref.xml b/doc/ref.xml index a245397d..76d15a1a 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -576,6 +576,40 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 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. @@ -1399,6 +1433,40 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 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. @@ -2236,6 +2304,40 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 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. @@ -3108,6 +3210,40 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 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/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index 7128dbe9..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; diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index ab95f595..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 diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 712f769c..58ca3014 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -422,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); @@ -925,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 6982cf93..87c1011b 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -395,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); @@ -874,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/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 0f0161a5a2c1b46d66aab70fea5283ce8511aa3a Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 15 Dec 2009 22:53:54 +0000 Subject: [PATCH 159/471] Add codegear compatibility to the changes. [SVN r58406] --- doc/changes.qbk | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changes.qbk b/doc/changes.qbk index 4bdcdaa3..fa454d4b 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -107,6 +107,7 @@ 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 From 71096f4d2681773d8890113a0af23416f99bc0d4 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 4 Jan 2010 22:49:39 +0000 Subject: [PATCH 160/471] Formatting changes, mostly to fit within 80 characters. Also, some C casts converted to static_cast. [SVN r58692] --- 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 6649b4df3c7abafa3b6fb50621f46f9c7034ccee Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 8 Jan 2010 06:43:57 +0000 Subject: [PATCH 161/471] Update changelogs and slightly improved reference documentation for new release. [SVN r58805] --- 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 7efcf9ccff318bbd8d2b69f308094ccfde094a70 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 21 Jan 2010 18:01:53 +0000 Subject: [PATCH 162/471] Set length of primes inside template on Sun C++. Refs #3854 [SVN r59200] --- include/boost/unordered/detail/util.hpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) 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 From 06f63fdc0d6e12247f379434469f03f39d7491e7 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 15 Feb 2010 23:01:06 +0000 Subject: [PATCH 163/471] Stop using the deprecated BOOST_HAS_ macros in unordered and hash. [SVN r59697] --- include/boost/unordered/detail/fwd.hpp | 2 +- include/boost/unordered/unordered_map.hpp | 6 +++--- include/boost/unordered/unordered_set.hpp | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) 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/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()) { From 1bcb5f8b6fda45ec5374be008207aac2d46a2a86 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 16 Feb 2010 22:32:49 +0000 Subject: [PATCH 164/471] Take advantage of the simplified parameters. [SVN r59707] --- doc/Jamfile.v2 | 3 --- 1 file changed, 3 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 From e594f1eda74838dfd2bbf36370b7a160b11b5316 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 16 Feb 2010 22:33:10 +0000 Subject: [PATCH 165/471] Remove deprecated macros for hash and unordered's tests. [SVN r59708] --- 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 +++++----- 4 files changed, 10 insertions(+), 10 deletions(-) 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 1d02663275cd77b8d12815aeb682333538cb69ce Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 26 Feb 2010 20:50:21 +0000 Subject: [PATCH 166/471] Try to avoid a warning. [SVN r59956] --- 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 ee034e23bbcbfb5083c95d877187b1be08164dad Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 22 Mar 2010 00:42:07 +0000 Subject: [PATCH 167/471] Add quick_erase to the unordered containers. Refs #3966. [SVN r60754] --- 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 00cebc3dfb7607d36fffa9d73405442a6bde4dc1 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 31 Mar 2010 21:42:08 +0000 Subject: [PATCH 168/471] Use boost::throw_exception in unordered. [SVN r60983] --- 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 10e24f93c44eedc9f927cb65c556f91d75e0a653 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 18 Apr 2010 13:20:45 +0000 Subject: [PATCH 169/471] Unordered/hash release notes. [SVN r61356] --- 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 5bab4d4360de46f1f633d57cb4394385bf6a0173 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 23 Apr 2010 07:25:53 +0000 Subject: [PATCH 170/471] Work around `friend` bug in clang. [SVN r61504] --- include/boost/unordered/detail/fwd.hpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index c1c31ffc..ce1d5bd1 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -734,8 +734,18 @@ namespace boost { namespace unordered_detail { 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 - static BOOST_DEDUCED_TYPENAME Iterator::base const& + struct base + { + typedef BOOST_DEDUCED_TYPENAME Iterator::base type; + }; + + template + static BOOST_DEDUCED_TYPENAME base::type const& get(Iterator const& it) { return it.base_; From ea33b5d13400f1ecf2ffe02a749d2c5509dcfc75 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 23 Apr 2010 07:26:43 +0000 Subject: [PATCH 171/471] Fix clang warnings in unordered tests. [SVN r61505] --- test/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 - 5 files changed, 39 insertions(+), 2 deletions(-) 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 ef79fea0b7d9f6f27bc72ba0c931514c153d3d1b Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 24 Apr 2010 12:59:35 +0000 Subject: [PATCH 172/471] The clang workaround broke some compilers, so only use it for clang. [SVN r61529] --- include/boost/unordered/detail/fwd.hpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index ce1d5bd1..a290ded9 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -731,6 +731,18 @@ namespace boost { namespace unordered_detail { // Iterator Access +#if !defined(__clang__) + class iterator_access + { + public: + template + static BOOST_DEDUCED_TYPENAME Iterator::base const& + get(Iterator const& it) + { + return it.base_; + } + }; +#else class iterator_access { public: @@ -751,6 +763,7 @@ namespace boost { namespace unordered_detail { return it.base_; } }; +#endif // Iterators From 71a8e56ae3ac8c4c549f46bface3616ff7cc4596 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 6 May 2010 20:12:40 +0000 Subject: [PATCH 173/471] Move equivalent and unique hash tables into their own headers. [SVN r61830] --- 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 076e195caceb2477db004bf5b198807e9aabb315 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 6 May 2010 20:13:25 +0000 Subject: [PATCH 174/471] Define several methods inline. Sun 5.9 was having some issues. [SVN r61831] --- include/boost/unordered/detail/equivalent.hpp | 304 ++++---- include/boost/unordered/detail/unique.hpp | 663 ++++++++---------- 2 files changed, 418 insertions(+), 549 deletions(-) diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 1c497c32..df7401f2 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -47,41 +47,150 @@ namespace boost { namespace unordered_detail { : 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); + //////////////////////////////////////////////////////////////////////// + // A convenience method for adding nodes. + + inline node_ptr 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 + + inline iterator_base emplace_impl(node_constructor& a) + { + key_type const& k = this->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 = this->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)); + } + } + + inline void emplace_impl_no_rehash(node_constructor& a) + { + key_type const& k = this->get_key(a.value()); + bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); + add_node(a, bucket, this->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 - iterator_base emplace(Args&&... args); - + 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(*this); + a.construct(std::forward(args)...); + + return emplace_impl(a); + } + #else - -#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ - template \ - iterator_base emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); - + +#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \ + template \ + iterator_base 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); \ + } + 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 - void insert_for_range(I i, I j, forward_traversal_tag); + inline void 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 - void insert_for_range(I i, I j, boost::incrementable_traversal_tag); + inline void 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 template - void insert_range(I i, I j); + 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); + } }; template @@ -142,163 +251,6 @@ namespace boost { namespace unordered_detail { 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 = this->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 = this->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 void hash_equivalent_table - ::emplace_impl_no_rehash(node_constructor& a) - { - key_type const& k = this->get_key(a.value()); - bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); - add_node(a, bucket, this->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); - } - -#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); \ - } - - 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 - 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/unique.hpp b/include/boost/unordered/detail/unique.hpp index 7ad367fe..c57714f0 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -48,43 +48,190 @@ namespace boost { namespace unordered_detail { : 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); + //////////////////////////////////////////////////////////////////////// + // A convenience method for adding nodes. + + inline node_ptr 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 + value_type& 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 = this->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)); + } + } + + inline emplace_return emplace_impl_with_node(node_constructor& a) + { + // No side effects in this initial code + 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 = this->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 - emplace_return emplace(Args&&... args); + inline emplace_return 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 = this->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 - emplace_return emplace_impl(key_type const& k, Args&&... args); + inline emplace_return 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 - emplace_return emplace_impl(no_key, Args&&... args); - template - emplace_return emplace_empty_impl(Args&&... args); + inline emplace_return 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, 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)); - +#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \ + template \ + inline emplace_return 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 = this->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 \ + inline emplace_return 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 \ + inline emplace_return 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, _) @@ -92,14 +239,127 @@ namespace boost { namespace unordered_detail { #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 + 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 + emplace_return 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 \ + emplace_return 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 + inline void 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 - 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); + } + } while(++i != j); + } + + template + inline void 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 - 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); + void insert_range(InputIt i, InputIt j) + { + if(i != j) + return insert_range_impl(extractor::extract(*i), i, j); + } }; template @@ -152,349 +412,6 @@ namespace boost { namespace unordered_detail { 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 = this->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 = 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 = this->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 = this->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 = this->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 - 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); - } - } 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 From dfaa61b6666f0860c54aeefbc7bcf3a82c1d27f3 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 9 May 2010 07:24:47 +0000 Subject: [PATCH 175/471] Another inline. [SVN r61872] --- include/boost/unordered/detail/fwd.hpp | 24 ++++++++++++++++++++--- include/boost/unordered/detail/node.hpp | 6 ------ include/boost/unordered/detail/table.hpp | 17 ---------------- include/boost/unordered/detail/unique.hpp | 2 +- 4 files changed, 22 insertions(+), 27 deletions(-) diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index be4d5e1a..4adeb592 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -58,6 +58,12 @@ #endif +#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 { static const float minimum_max_load_factor = 1e-3f; @@ -469,13 +475,25 @@ 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; + inline node_ptr 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; + } + 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; diff --git a/include/boost/unordered/detail/node.hpp b/include/boost/unordered/detail/node.hpp index 85a31410..c2553bef 100644 --- a/include/boost/unordered/detail/node.hpp +++ b/include/boost/unordered/detail/node.hpp @@ -16,12 +16,6 @@ #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 { //////////////////////////////////////////////////////////////////////////// diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index d37c0155..fca6113d 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -29,23 +29,6 @@ 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 diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index c57714f0..19fe7de8 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -248,7 +248,7 @@ namespace boost { namespace unordered_detail { // strong otherwise template - emplace_return hash_unique_table::emplace(Args&&... args) + emplace_return emplace(Args&&... args) { return this->size_ ? emplace_impl( From 5edc45349f07e4252cd3f5d92a7962ff050a73bb Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 21 May 2010 07:06:33 +0000 Subject: [PATCH 176/471] Revert changes for sun 5.9. Nobody seems to be running the tests now. [SVN r62117] --- include/boost/unordered/detail/equivalent.hpp | 304 ++++---- include/boost/unordered/detail/fwd.hpp | 24 +- include/boost/unordered/detail/node.hpp | 6 + include/boost/unordered/detail/table.hpp | 17 + include/boost/unordered/detail/unique.hpp | 663 ++++++++++-------- 5 files changed, 575 insertions(+), 439 deletions(-) diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index df7401f2..1c497c32 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -47,150 +47,41 @@ namespace boost { namespace unordered_detail { : 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; - //////////////////////////////////////////////////////////////////////// - // A convenience method for adding nodes. - - inline node_ptr 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 - - inline iterator_base emplace_impl(node_constructor& a) - { - key_type const& k = this->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 = this->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)); - } - } - - inline void emplace_impl_no_rehash(node_constructor& a) - { - key_type const& k = this->get_key(a.value()); - bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); - add_node(a, bucket, this->find_iterator(bucket, k)); - } + inline node_ptr add_node(node_constructor& a, + bucket_ptr bucket, node_ptr pos); #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(*this); - a.construct(std::forward(args)...); - - return emplace_impl(a); - } - + iterator_base emplace(Args&&... args); + #else - -#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \ - template \ - iterator_base 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); \ - } - + +#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 - - //////////////////////////////////////////////////////////////////////////// - // Insert range methods - // if hash function throws, or inserting > 1 element, basic exception safety - // strong otherwise template - inline void 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 + void insert_for_range(I i, I j, forward_traversal_tag); template - inline void 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 + void insert_for_range(I i, I j, boost::incrementable_traversal_tag); 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); - } + void insert_range(I i, I j); }; template @@ -251,6 +142,163 @@ namespace boost { namespace unordered_detail { 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 = this->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 = this->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 void hash_equivalent_table + ::emplace_impl_no_rehash(node_constructor& a) + { + key_type const& k = this->get_key(a.value()); + bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); + add_node(a, bucket, this->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); + } + +#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); \ + } + + 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 + 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/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index 4adeb592..be4d5e1a 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -58,12 +58,6 @@ #endif -#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 { static const float minimum_max_load_factor = 1e-3f; @@ -475,25 +469,13 @@ namespace boost { namespace unordered_detail { return extractor::extract(node::get_value(n)); } bool equal(key_type const& k, value_type const& v) const; - template - inline node_ptr 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; - } - + 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; - + // Load methods std::size_t max_size() const; diff --git a/include/boost/unordered/detail/node.hpp b/include/boost/unordered/detail/node.hpp index c2553bef..85a31410 100644 --- a/include/boost/unordered/detail/node.hpp +++ b/include/boost/unordered/detail/node.hpp @@ -16,6 +16,12 @@ #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 { //////////////////////////////////////////////////////////////////////////// diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index fca6113d..d37c0155 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -29,6 +29,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 diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index 19fe7de8..7ad367fe 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -48,190 +48,43 @@ namespace boost { namespace unordered_detail { : 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; - //////////////////////////////////////////////////////////////////////// - // A convenience method for adding nodes. - - inline node_ptr 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; - } + node_ptr add_node(node_constructor& a, bucket_ptr bucket); - //////////////////////////////////////////////////////////////////////// - // Insert methods - - // if hash function throws, basic exception safety - // strong otherwise - value_type& 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 = this->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)); - } - } - - inline emplace_return emplace_impl_with_node(node_constructor& a) - { - // No side effects in this initial code - 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 = this->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 - inline emplace_return 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 = this->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); - } - } - + emplace_return emplace(Args&&... args); template - inline emplace_return 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); - } - + emplace_return emplace_impl(key_type const& k, Args&&... args); template - inline emplace_return 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); - } - + emplace_return emplace_impl(no_key, Args&&... args); + template + emplace_return emplace_empty_impl(Args&&... args); #else -#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \ - template \ - inline emplace_return 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 = this->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 \ - inline emplace_return 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 \ - inline emplace_return 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); \ - } - +#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, _) @@ -239,127 +92,14 @@ namespace boost { namespace unordered_detail { #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 - emplace_return emplace(Args&&... args) - { - return this->size_ ? - emplace_impl( - extractor::extract(std::forward(args)...), - std::forward(args)...) : - emplace_empty_impl(std::forward(args)...); - } - -#else - - template - emplace_return 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 \ - emplace_return 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 - inline void 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 - 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); - } - } while(++i != j); - } - - template - inline void 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 - void insert_range(InputIt i, InputIt j) - { - if(i != j) - return insert_range_impl(extractor::extract(*i), i, j); - } + 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 @@ -412,6 +152,349 @@ namespace boost { namespace unordered_detail { 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 = this->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 = 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 = this->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 = this->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 = this->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 - 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); + } + } 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 From 7b272c85d55cf4e3572dac3465bb095eef8cad65 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 27 Jun 2010 16:58:48 +0000 Subject: [PATCH 177/471] Missing bracket. [SVN r63392] --- doc/unordered.qbk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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]) ] ] From 3a13ddb4a32cfbd02698eac0b3dcaf968db1cac1 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 30 Jun 2010 12:04:41 +0000 Subject: [PATCH 178/471] Don't use _GLIBCXX_DEBUG on darwin. It isn't supported by Apple's gcc 4.2. [SVN r63449] --- test/exception/Jamfile.v2 | 2 +- test/unordered/Jamfile.v2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 0cbd02d3ccb1b48fc2482b16768b3ca379d3e8b2 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 30 Jun 2010 12:05:36 +0000 Subject: [PATCH 179/471] Fix images in standalone unordered documentation. [SVN r63451] --- doc/Jamfile.v2 | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 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 From daad24388cae383c8965204a2652d598ca008644 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 21 Oct 2010 20:23:37 +0000 Subject: [PATCH 180/471] Fix iterator insert bug in unordered_set/unordered_map. [SVN r66136] --- doc/changes.qbk | 5 ++ include/boost/unordered/detail/unique.hpp | 63 +++++++++++-------- .../exception/constructor_exception_tests.cpp | 16 ++++- test/helpers/input_iterator.hpp | 61 +++++++++++++++++- test/unordered/constructor_tests.cpp | 15 ++++- test/unordered/insert_tests.cpp | 14 ++++- 6 files changed, 145 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..7bd2fdc7 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,65 @@ 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_; + } + copy_iterator_adaptor& operator++() { + ++base_; return *this; + } + copy_iterator_adaptor operator++(int) { + copy_iterator_adaptor tmp(*this); ++base_; return tmp; + } + bool operator==(copy_iterator_adaptor const& x) const { + return base_ == x.base_; + } + bool operator!=(copy_iterator_adaptor const& x) const { + return base_ != x.base_; + } + copy_iterator_adaptor operator+=(difference_type x) { + base_ += x; + return *this; + } + copy_iterator_adaptor operator-=(difference_type x) { + base_ -= x; + return *this; + } + difference_type operator-(copy_iterator_adaptor const& other) { + return base_-other.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 1b85f812afd02e3ce14ef458088e7d9c68cfe2f0 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 21 Oct 2010 20:34:39 +0000 Subject: [PATCH 181/471] Missing copy_iterator methods. [SVN r66137] --- test/helpers/input_iterator.hpp | 39 +++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/test/helpers/input_iterator.hpp b/test/helpers/input_iterator.hpp index 7bd2fdc7..1671e0c0 100644 --- a/test/helpers/input_iterator.hpp +++ b/test/helpers/input_iterator.hpp @@ -95,17 +95,20 @@ namespace test 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; } - bool operator==(copy_iterator_adaptor const& x) const { - return base_ == x.base_; + copy_iterator_adaptor& operator--() { + --base_; return *this; } - bool operator!=(copy_iterator_adaptor const& x) const { - return base_ != x.base_; + copy_iterator_adaptor operator--(int) { + copy_iterator_adaptor tmp(*this); --base_; return tmp; } copy_iterator_adaptor operator+=(difference_type x) { base_ += x; @@ -115,9 +118,37 @@ namespace test 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_; }; From 77bd36d03876948968f5236b20995108d9cdde08 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 25 Oct 2010 21:59:52 +0000 Subject: [PATCH 182/471] Declare inline functions as inline. [SVN r66193] --- include/boost/unordered/unordered_map_fwd.hpp | 12 ++++++------ include/boost/unordered/unordered_set_fwd.hpp | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) 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); } From eb04f683510568f32a52fb06b07791f5cd42b746 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 7 Nov 2010 14:43:50 +0000 Subject: [PATCH 183/471] Call forward declared functions from templates in unordered tests. Borland is having some issues with the existing tests, since they call inline functions before they're defined. It might be right to, although all the other compilers are fine with it. But the test isn't really what the forward headers are intended for. Try to make the tests better represent the intent, and possibly work on Borland. [SVN r66428] --- test/unordered/fwd_map_test.cpp | 37 ++++++++++++++++++++++++--------- test/unordered/fwd_set_test.cpp | 37 ++++++++++++++++++++++++--------- 2 files changed, 54 insertions(+), 20 deletions(-) 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)); From a49c76c69c6e5adf53a089110965854d3e1c0a2d Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 13 Nov 2010 12:30:06 +0000 Subject: [PATCH 184/471] More comments describing the unordered internals. And fix a couple of small mistakes in the existing comments. [SVN r66555] --- include/boost/unordered/detail/fwd.hpp | 106 +++++++++++++++++++++++-- 1 file changed, 100 insertions(+), 6 deletions(-) diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index be4d5e1a..4f347355 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 { @@ -203,7 +253,13 @@ namespace boost { namespace unordered_detail { 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 +304,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 +395,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 +508,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,7 +654,12 @@ 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 @@ -605,7 +695,6 @@ namespace boost { namespace unordered_detail { }; #endif - // Iterators template class hash_iterator; template class hash_const_iterator; @@ -716,7 +805,7 @@ namespace boost { namespace unordered_detail { } }; - // iterators + // Iterators // // all no throw @@ -823,7 +912,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 From 2c1a8894cb8f09c6977380fa2d241bbece5cf243 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 13 Nov 2010 12:30:45 +0000 Subject: [PATCH 185/471] Remove clang workaround. Clang from llvm 2.8 doesn't need it. Clang form llvm 2.7 isn't supported. [SVN r66556] --- include/boost/unordered/detail/fwd.hpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index 4f347355..274af519 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -661,18 +661,6 @@ namespace boost { namespace unordered_detail { // iterator_access is used to access the internal iterator without // making it publicly available. -#if !defined(__clang__) - class iterator_access - { - public: - template - static BOOST_DEDUCED_TYPENAME Iterator::base const& - get(Iterator const& it) - { - return it.base_; - } - }; -#else class iterator_access { public: @@ -693,8 +681,6 @@ namespace boost { namespace unordered_detail { return it.base_; } }; -#endif - template class hash_iterator; template class hash_const_iterator; From 14e0e1afc27dc24261e1974dfb8934b7f9fd142a Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 13 Nov 2010 12:31:54 +0000 Subject: [PATCH 186/471] Less use of the ampersand operator in unordered. [SVN r66557] --- include/boost/unordered/detail/buckets.hpp | 2 +- include/boost/unordered/detail/fwd.hpp | 10 ++++++++-- include/boost/unordered/detail/util.hpp | 4 ++-- test/objects/minimal.hpp | 20 ++++++++++++++++++++ 4 files changed, 31 insertions(+), 5 deletions(-) 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 274af519..34e72a49 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -231,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&); }; @@ -249,6 +252,9 @@ 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&); }; @@ -719,7 +725,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; @@ -769,7 +775,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; 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/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 From df726c038fc721710b8f8de7be41d3d921dca441 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 14 Nov 2010 11:42:58 +0000 Subject: [PATCH 187/471] Remove some 'always_show_run_output' flags. [SVN r66566] --- test/unordered/Jamfile.v2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unordered/Jamfile.v2 b/test/unordered/Jamfile.v2 index 07be6c28..f7106aeb 100644 --- a/test/unordered/Jamfile.v2 +++ b/test/unordered/Jamfile.v2 @@ -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 ] From b9188caf7dc40882ed724e3e76855e0181e99d2f Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 14 Nov 2010 11:43:49 +0000 Subject: [PATCH 188/471] Fix [66556] - Remove clang workaround. I accidentaly removed the good code and left the workaround in. Also, a correction to the comment: I think bug was only in a unreleased version of clang. [SVN r66567] --- include/boost/unordered/detail/fwd.hpp | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index 34e72a49..471d1d2e 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -670,18 +670,8 @@ namespace boost { namespace unordered_detail { 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& + static BOOST_DEDUCED_TYPENAME Iterator::base const& get(Iterator const& it) { return it.base_; From 5a81ca6ffea75ff07b8c56a9747baafc4ebd6427 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 7 Dec 2010 20:45:08 +0000 Subject: [PATCH 189/471] Import boostbook/quickbook in unordered and hash docs. [SVN r67091] --- doc/Jamfile.v2 | 3 +++ 1 file changed, 3 insertions(+) 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 ; From 3d7abd9cbe6d156a1bbbebe82ce6074bab5bda9f Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 11 Dec 2010 14:43:00 +0000 Subject: [PATCH 190/471] Avoid `-Wconversion` warnings in unordered & hash. [SVN r67170] --- test/unordered/Jamfile.v2 | 4 ++-- test/unordered/insert_tests.cpp | 18 +++++++++--------- test/unordered/load_factor_tests.cpp | 2 +- test/unordered/rehash_tests.cpp | 3 ++- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/test/unordered/Jamfile.v2 b/test/unordered/Jamfile.v2 index f7106aeb..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 diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 4fee0771..df6b75d5 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..ea920c16 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 4d57147c3d56e5fba777212d8bc5c29c3e6a6bd4 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 3 Jan 2011 12:43:34 +0000 Subject: [PATCH 191/471] Fix tabs and files without copyright. [SVN r67612] --- test/unordered/insert_tests.cpp | 4 ++-- test/unordered/rehash_tests.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index df6b75d5..d832c7d2 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -172,7 +172,7 @@ void insert_tests2(X*, BOOST_TEST(*pos == *r2); tracker.compare_key(x, *it); - if(static_cast(x.size()) < b * static_cast(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(static_cast(x.size()) < b * static_cast(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/rehash_tests.cpp b/test/unordered/rehash_tests.cpp index ea920c16..434389b0 100644 --- a/test/unordered/rehash_tests.cpp +++ b/test/unordered/rehash_tests.cpp @@ -20,7 +20,7 @@ template bool postcondition(X const& x, BOOST_DEDUCED_TYPENAME X::size_type n) { return static_cast(x.bucket_count()) > - static_cast(x.size()) / x.max_load_factor() && + static_cast(x.size()) / x.max_load_factor() && x.bucket_count() >= n; } From a33949a0a599af97a8d5114e5c6b0cfe405ce4f4 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 25 Jan 2011 20:13:43 +0000 Subject: [PATCH 192/471] Add copy constructors and assignment operators when using rvalue references. Refs #5119. [SVN r68445] --- 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 a4750fbdba398475ff8fb48e46732fc2dfe2cf05 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Tue, 25 Jan 2011 20:15:27 +0000 Subject: [PATCH 193/471] Make unnecessary_copy_tests a bit more lenient. I'm not sure if those extra moves are avoidable, but I'll allow them for now. They shouldn't hurt much. [SVN r68446] --- test/unordered/unnecessary_copy_tests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 8ade57b9e32762c57fbc46004e48dba56b4a88c1 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 16 Mar 2011 21:33:41 +0000 Subject: [PATCH 194/471] Remove workaround for ancient gcc verisons. [SVN r70027] --- test/objects/test.hpp | 38 -------------------------------------- 1 file changed, 38 deletions(-) diff --git a/test/objects/test.hpp b/test/objects/test.hpp index bfada4d2..df08c81f 100644 --- a/test/objects/test.hpp +++ b/test/objects/test.hpp @@ -279,44 +279,6 @@ namespace test { return x == y; } - -#if BOOST_WORKAROUND(__GNUC__, < 3) - void swap(test::object& x, test::object& y) { - test::object tmp; - tmp = x; - x = y; - y = tmp; - } - - void swap(test::hash& x, test::hash& y) { - test::hash tmp; - tmp = x; - x = y; - y = tmp; - } - - void swap(test::less& x, test::less& y) { - test::less tmp; - tmp = x; - x = y; - y = tmp; - } - - void swap(test::equal_to& x, test::equal_to& y) { - test::equal_to tmp; - tmp = x; - x = y; - y = tmp; - } - - template - void swap(test::allocator& x, test::allocator& y) { - test::allocator tmp; - tmp = x; - x = y; - y = tmp; - } -#endif } #endif From d9c49a6cde84f41599f2114dc6fbed79670b7559 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 16 Mar 2011 21:34:08 +0000 Subject: [PATCH 195/471] Don't require explicit conversion in pairs in unordered's insert tests. In the draft standard the std::pair constructor from another pair is only considered when overloading if both members are implicitly constructible to their corresponding members. This breaks one of the unordered tests which required an explicit conversion, so change it to only require an implicit conversion. [SVN r70028] --- test/objects/test.hpp | 27 +++++++++++++++++++++++++++ test/unordered/insert_tests.cpp | 4 ++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/test/objects/test.hpp b/test/objects/test.hpp index df08c81f..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<<"("< + std::pair > list; test::random_values< - boost::unordered_map + boost::unordered_map > v(1000, generator); list l(v.begin(), v.end()); From 547e1411669c119f5cc5b22f7bf3f92c7b1cb19d Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 16 Apr 2011 18:47:33 +0000 Subject: [PATCH 196/471] Unordered: Overhaul the implementation. Store nodes in a single linked list, with hash values so that their buckets can be found when needed. Iterators now only have to store a pointer to the node and don't have to iterate over empty buckets to reach the next node. This allows the container to meet the iterator requirements - fixing the speed issues with `equal_range` and `erase`. Also, define iterators in their own namespace, so that they don't accidentally pull in detail functions via ADL. I've simplified the code slightly by removing some of the special cases for empty containers. Renamed a few things as well and other minor changes that were made as I went along. [SVN r71327] --- .../unordered/detail/allocator_helpers.hpp | 4 +- include/boost/unordered/detail/buckets.hpp | 786 ++++++-- include/boost/unordered/detail/equivalent.hpp | 401 ++-- .../boost/unordered/detail/extract_key.hpp | 11 +- include/boost/unordered/detail/fwd.hpp | 932 --------- include/boost/unordered/detail/move.hpp | 38 +- include/boost/unordered/detail/node.hpp | 494 +++-- include/boost/unordered/detail/table.hpp | 1411 +++++++------- include/boost/unordered/detail/unique.hpp | 748 ++++---- include/boost/unordered/detail/util.hpp | 286 +-- include/boost/unordered/unordered_map.hpp | 1662 +++++++++++------ include/boost/unordered/unordered_set.hpp | 1491 +++++++++------ test/helpers/invariants.hpp | 49 +- test/helpers/memory.hpp | 2 +- 14 files changed, 4330 insertions(+), 3985 deletions(-) delete mode 100644 include/boost/unordered/detail/fwd.hpp diff --git a/include/boost/unordered/detail/allocator_helpers.hpp b/include/boost/unordered/detail/allocator_helpers.hpp index 2c642231..7393df1e 100644 --- a/include/boost/unordered/detail/allocator_helpers.hpp +++ b/include/boost/unordered/detail/allocator_helpers.hpp @@ -23,7 +23,7 @@ # include #endif -namespace boost { namespace unordered_detail { +namespace boost { namespace unordered { namespace detail { // rebind_wrap // @@ -102,7 +102,7 @@ namespace boost { namespace unordered_detail { 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 index 913dbcd2..ffa59560 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -7,177 +7,665 @@ #ifndef BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED -#include -#include #include -#include -namespace boost { namespace unordered_detail { +namespace boost { namespace unordered { namespace detail { //////////////////////////////////////////////////////////////////////////// - // Buckets + // + // Now the main data structure: + // + // buckets buffered_functions + // | | + // +---------------+--------------+ + // | + // table + // + // T is a class which contains typedefs for all the types we need. - 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); - } + // buckets + // + // This is responsible for allocating and deallocating buckets and nodes. + // + // Notes: + // 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). - template - inline BOOST_DEDUCED_TYPENAME hash_buckets::bucket_ptr - hash_buckets::get_bucket(std::size_t num) const + template + class buckets { - return buckets_ + static_cast(num); - } + buckets(buckets const&); + buckets& operator=(buckets const&); + public: + // Types - 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_); - } + typedef BOOST_DEDUCED_TYPENAME ::boost::detail::if_true:: + BOOST_NESTED_TEMPLATE then< + ::boost::unordered::detail::ungrouped_node, + ::boost::unordered::detail::grouped_node + >::type node; + + typedef A value_allocator; + typedef ::boost::unordered::detail::bucket bucket; + typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; + + 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; + 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 start bucket. + return prev_prime(this->bucket_alloc().max_size() - 1); + } + + //////////////////////////////////////////////////////////////////////// + // Constructors and Destructors + + buckets(node_allocator const& a, std::size_t bucket_count) + : buckets_(), + bucket_count_(bucket_count), + allocators_(a,a) + { + } - template - 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; + inline ~buckets() + { + if(this->buckets_) { this->delete_buckets(); } + } + + void 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 the start node. + constructor.construct(bucket(), this->bucket_count_ + 1); + + // Only release the buckets once everything is successfully + // done. + this->buckets_ = constructor.release(); + } + + // no throw + void swap(buckets& other) + { + BOOST_ASSERT(node_alloc() == other.node_alloc()); + std::swap(buckets_, other.buckets_); + std::swap(bucket_count_, other.bucket_count_); + } + + void move(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; + } + + std::size_t bucket_size(std::size_t index) const + { + if (!this->buckets_) return 0; + node_ptr ptr = this->buckets_[index].next_; + if (!ptr) return 0; 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_ptr()); - 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() + std::size_t count = 0; + while(BOOST_UNORDERED_BORLAND_BOOL(ptr) && + node::get_hash(ptr) % this->bucket_count_ == index) + { + ++count; + ptr = ptr->next_; + } + + return count; + } + + node_ptr bucket_begin(std::size_t bucket_index) const + { + if (!this->buckets_) return node_ptr(); + bucket& b = this->buckets_[bucket_index]; + if (!b.next_) return node_ptr(); + return b.next_->next_; + } + + // For the remaining functions, buckets_ must not be null. + + bucket_ptr get_bucket(std::size_t bucket_index) const + { + return buckets_ + static_cast(bucket_index); + } + + //////////////////////////////////////////////////////////////////////// + // Delete + + void delete_node(node_ptr n) + { + node* raw_ptr = static_cast(&*n); + real_node_ptr real_ptr(node_alloc().address(*raw_ptr)); + + ::boost::unordered::detail::destroy(raw_ptr->value_ptr()); + node_alloc().destroy(real_ptr); + node_alloc().deallocate(real_ptr, 1); + } + + void delete_buckets() + { + bucket_ptr end = this->get_bucket(this->bucket_count_); + + node_ptr n = (end)->next_; + while(BOOST_UNORDERED_BORLAND_BOOL(n)) + { + node_ptr node_to_delete = n; + n = n->next_; + delete_node(node_to_delete); + } + + ++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(); + } + + std::size_t 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; + } + + // This is called after erasing a node or group of nodes to fix up + // the bucket pointers. + void fix_buckets(bucket_ptr bucket, node_ptr prev, node_ptr next) + { + if (!next) + { + if (bucket->next_ == prev) bucket->next_ = node_ptr(); + } + else + { + bucket_ptr next_bucket = this->get_bucket( + node::get_hash(next) % this->bucket_count_); + if (next_bucket != bucket) + { + next_bucket->next_ = prev; + if (bucket->next_ == prev) bucket->next_ = node_ptr(); + } + } + } + + // This is called after erasing a range of nodes to fix any bucket + // pointers into that range. + void fix_buckets_range( + std::size_t bucket_index, node_ptr prev, node_ptr begin, node_ptr end) + { + node_ptr n = begin; + + // If we're not at the start of the current bucket, then + // go to the start of the next bucket. + if (this->get_bucket(bucket_index)->next_ != prev) + { + for(;;) { + n = n->next_; + if (n == end) return; + + std::size_t new_bucket_index = + node::get_hash(n) % this->bucket_count_; + if (bucket_index != new_bucket_index) { + bucket_index = new_bucket_index; + break; + } + } + } + + // Iterate through the remaining nodes, clearing out the bucket + // pointers. + this->buckets_[bucket_index].next_ = bucket_ptr(); + for(;;) { + n = n->next_; + if (n == end) break; + + std::size_t new_bucket_index = + node::get_hash(n) % this->bucket_count_; + if (bucket_index != new_bucket_index) { + bucket_index = new_bucket_index; + this->buckets_[bucket_index].next_ = bucket_ptr(); + } + }; + + // Finally fix the bucket containing the trailing node. + if (BOOST_UNORDERED_BORLAND_BOOL(n)) { + this->buckets_[node::get_hash(n) % this->bucket_count_].next_ + = prev; + } + } + + // Iterate through the nodes placing them in the correct buckets. + // pre: prev->next_ is not null. + node_ptr place_in_bucket(node_ptr prev, node_ptr end) { + bucket_ptr b = this->get_bucket(node::get_hash(prev->next_) % this->bucket_count_); + + if (!b->next_) { + b->next_ = prev; + return end; + } + else { + node_ptr next = end->next_; + end->next_ = b->next_->next_; + b->next_->next_ = prev->next_; + prev->next_ = next; + return prev; + } + } + + void copy_buckets_to(buckets&) const; + }; + + // 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 + class buffered_functions { - // The array constructor will clean up in the event of an - // exception. - allocator_array_constructor - constructor(bucket_alloc()); + friend class set_hash_functions; + buffered_functions& operator=(buffered_functions const&); - // Creates an extra bucket to act as a sentinel. - constructor.construct(bucket(), this->bucket_count_ + 1); + typedef ::boost::compressed_pair function_pair; + typedef BOOST_DEDUCED_TYPENAME ::boost::aligned_storage< + sizeof(function_pair), + ::boost::alignment_of::value>::type aligned_function; - // Set up the sentinel (node_ptr cast) - bucket_ptr sentinel = constructor.get() + - static_cast(this->bucket_count_); - sentinel->next_ = sentinel; + bool current_; // The currently active functions. + aligned_function funcs_[2]; - // Only release the buckets once everything is successfully - // done. - this->buckets_ = constructor.release(); - } + 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: + + buffered_functions(H const& hf, P const& eq) + : current_(false) + { + construct(current_, hf, eq); + } + + buffered_functions(buffered_functions const& bf) + : current_(false) + { + construct(current_, bf.current()); + } + + ~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 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_; + } + }; //////////////////////////////////////////////////////////////////////////// - // Constructors and Destructors + // Node Constructors - // no throw - template - inline void hash_buckets::move(hash_buckets& other) +#if defined(BOOST_UNORDERED_STD_FORWARD) + + template + inline void construct_impl(T*, void* address, Args&&... args) { - 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; + new(address) T(std::forward(args)...); } - template - inline void hash_buckets::swap(hash_buckets& other) +#if defined(BOOST_UNORDERED_CPP0X_PAIR) + template + inline void construct_impl(std::pair*, void* address, + Key&& k, Arg0&& arg0, Args&&... args) + ) { - BOOST_ASSERT(node_alloc() == other.node_alloc()); - std::swap(buckets_, other.buckets_); - std::swap(bucket_count_, other.bucket_count_); + 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 + + /////////////////////////////////////////////////////////////////// + // + // Node construction + + template + class node_constructor + { + typedef ::boost::unordered::detail::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: + + node_constructor(buckets& m) : + buckets_(m), + node_(), + node_constructed_(false), + value_constructed_(false) + { + } + + ~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: + node_constructor(node_constructor const&); + node_constructor& operator=(node_constructor const&); + }; + + // node_constructor + + template + inline node_constructor::~node_constructor() + { + if (node_) { + if (value_constructed_) { +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) + struct dummy { node x; }; +#endif + ::boost::unordered::detail::destroy(node_->value_ptr()); + } + + if (node_constructed_) + buckets_.node_alloc().destroy(node_); + + buckets_.node_alloc().deallocate(node_, 1); + } + } + + template + inline void 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_->init(buckets_.bucket_alloc().address(*node_)); + + node_constructed_ = true; + } + else { + BOOST_ASSERT(node_constructed_ && value_constructed_); + ::boost::unordered::detail::destroy(node_->value_ptr()); + value_constructed_ = false; + } + } + + //////////////////////////////////////////////////////////////////////////// + // copy_buckets_to + // + // basic excpetion safety. If an exception is thrown this will + // leave dst partially filled and the buckets unset. + + template + void buckets::copy_buckets_to(buckets& dst) const + { + BOOST_ASSERT(!dst.buckets_); + + dst.create_buckets(); + bucket_ptr dst_start = dst.get_bucket(dst.bucket_count_); + + { + node_constructor a(dst); + + node_ptr n = this->buckets_[this->bucket_count_].next_; + node_ptr prev = dst_start; + + while(n) { + std::size_t hash = node::get_hash(n); + node_ptr group_end = node::next_group(n); + + a.construct(node::get_value(n)); + node_ptr first_node = a.release(); + node::set_hash(first_node, hash); + node_ptr end = prev->next_ = first_node; + + for(n = n->next_; n != group_end; n = n->next_) { + a.construct(node::get_value(n)); + end = a.release(); + node::set_hash(end, hash); + node::add_after_node(end, first_node); + } + + prev = dst.place_in_bucket(prev, end); + } + } + } + + /////////////////////////////////////////////////////////////////// + // + // Iterators + + // iterator_access is used to access the internal iterator without + // making it publicly available. + + class iterator_access + { + public: + template + static BOOST_DEDUCED_TYPENAME Iterator::node_ptr const& + get(Iterator const& it) + { + return it.node_; + } + }; +}}} #endif diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 1c497c32..9da99ba7 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -7,13 +7,12 @@ #ifndef BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED -#include #include -namespace boost { namespace unordered_detail { +namespace boost { namespace unordered { namespace detail { template - class hash_equivalent_table : public T::table + class equivalent_table : public T::table { public: typedef BOOST_DEDUCED_TYPENAME T::hasher hasher; @@ -27,48 +26,154 @@ namespace boost { namespace unordered_detail { 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, + 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) + equivalent_table(equivalent_table const& x) : table(x, x.node_alloc()) {} - hash_equivalent_table(hash_equivalent_table const& x, + equivalent_table(equivalent_table const& x, value_allocator const& a) : table(x, a) {} - hash_equivalent_table(hash_equivalent_table& x, move_tag m) + equivalent_table(equivalent_table& x, move_tag m) : table(x, m) {} - hash_equivalent_table(hash_equivalent_table& x, + equivalent_table(equivalent_table& x, value_allocator const& a, move_tag m) : table(x, a, m) {} - ~hash_equivalent_table() {} + ~equivalent_table() {} + // Equality + + bool equals(equivalent_table const& other) const + { + if(this->size_ != other.size_) return false; + if(!this->size_) return true; + + for(node_ptr n1 = this->buckets_[this->bucket_count_].next_; n1;) + { + node_ptr n2 = other.find_matching_node(n1); + if(!n2) return false; + + node_ptr end1 = node::next_group(n1); + node_ptr end2 = node::next_group(n2); + + do { + if(!extractor::compare_mapped( + node::get_value(n1), node::get_value(n2))) + return false; + n1 = n1->next_; + n2 = n2->next_; + } while(n1 != end1 && n2 != end2); + if(n1 != end1 || n2 != end2) return false; + } + + return true; + } + + //////////////////////////////////////////////////////////////////////// + // A convenience method for adding nodes. + + inline node_ptr add_node( + node_constructor& a, + std::size_t bucket_index, + std::size_t hash, + node_ptr pos) + { + node_ptr n = a.release(); + node::set_hash(n, hash); + + if(BOOST_UNORDERED_BORLAND_BOOL(pos)) { + node::add_after_node(n, pos); + if (n->next_) { + std::size_t next_bucket = + node::get_hash(n->next_) % this->bucket_count_; + if (next_bucket != bucket_index) { + this->buckets_[next_bucket].next_ = n; + } + } + } + else { + bucket_ptr b = this->get_bucket(bucket_index); + + if (!b->next_) + { + bucket_ptr start_node = + this->get_bucket(this->bucket_count_); + + if (BOOST_UNORDERED_BORLAND_BOOL(start_node->next_)) { + this->buckets_[ + node::get_hash(start_node->next_) % + this->bucket_count_].next_ = n; + } + + b->next_ = start_node; + n->next_ = start_node->next_; + start_node->next_ = n; + } + else + { + n->next_ = b->next_->next_; + b->next_->next_ = n; + } + } + ++this->size_; + return n; + } + + //////////////////////////////////////////////////////////////////////// // Insert methods - iterator_base emplace_impl(node_constructor& a); - void emplace_impl_no_rehash(node_constructor& a); + node_ptr emplace_impl(node_constructor& a) + { + key_type const& k = this->get_key(a.value()); + std::size_t hash = this->hash_function()(k); + std::size_t bucket_index = hash % this->bucket_count_; + node_ptr position = this->find_node(bucket_index, hash, k); + + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + if(this->reserve_for_insert(this->size_ + 1)) { + bucket_index = hash % this->bucket_count_; + } + + return add_node(a, bucket_index, hash, position); + } - // equals - - bool equals(hash_equivalent_table const&) const; - - inline node_ptr add_node(node_constructor& a, - bucket_ptr bucket, node_ptr pos); + void emplace_impl_no_rehash(node_constructor& a) + { + key_type const& k = this->get_key(a.value()); + std::size_t hash = this->hash_function()(k); + std::size_t bucket_index = hash % this->bucket_count_; + add_node(a, bucket_index, hash, + this->find_node(bucket_index, hash, k)); + } #if defined(BOOST_UNORDERED_STD_FORWARD) template - iterator_base emplace(Args&&... args); + node_ptr 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); + } #else -#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ - template \ - iterator_base emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); +#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \ + template \ + node_ptr 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); \ + } BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_INSERT_IMPL, _) @@ -76,12 +181,51 @@ namespace boost { namespace unordered_detail { #undef BOOST_UNORDERED_INSERT_IMPL #endif + //////////////////////////////////////////////////////////////////////// + // Insert range methods + + // 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); + void insert_for_range(I i, I j, forward_traversal_tag) + { + if(i == j) return; + std::size_t distance = ::boost::unordered::detail::distance(i, j); + if(distance == 1) { + emplace(*i); + } + else { + // Only require basic exception safety here + this->reserve_for_insert(this->size_ + distance); + + node_constructor a(*this); + for (; i != j; ++i) { + a.construct(*i); + emplace_impl_no_rehash(a); + } + } + } + template - void insert_for_range(I i, I j, boost::incrementable_traversal_tag); + void 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 template - void insert_range(I i, I j); + 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); + } + }; template @@ -90,10 +234,10 @@ namespace boost { namespace unordered_detail { BOOST_DEDUCED_TYPENAME A::value_type, H, P, A, set_extractor, - grouped> + false> { - typedef hash_equivalent_table > impl; - typedef hash_table > table; + typedef equivalent_table > impl; + typedef table > table; }; template @@ -101,204 +245,11 @@ namespace boost { namespace unordered_detail { K, BOOST_DEDUCED_TYPENAME A::value_type, H, P, A, map_extractor, - grouped> + false> { - typedef hash_equivalent_table > impl; - typedef hash_table > table; + typedef equivalent_table > impl; + typedef table > table; }; - - //////////////////////////////////////////////////////////////////////////// - // 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(this->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 = this->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 = this->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 void hash_equivalent_table - ::emplace_impl_no_rehash(node_constructor& a) - { - key_type const& k = this->get_key(a.value()); - bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); - add_node(a, bucket, this->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); - } - -#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); \ - } - - 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 - 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 index bedb175f..ad90f940 100644 --- a/include/boost/unordered/detail/extract_key.hpp +++ b/include/boost/unordered/detail/extract_key.hpp @@ -6,12 +6,11 @@ #ifndef BOOST_UNORDERED_DETAIL_EXTRACT_KEY_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_EXTRACT_KEY_HPP_INCLUDED -#include -#include -#include +#include namespace boost { -namespace unordered_detail { +namespace unordered { +namespace detail { // key extractors // @@ -75,7 +74,7 @@ namespace unordered_detail { struct map_extractor { typedef ValueType value_type; - typedef BOOST_DEDUCED_TYPENAME boost::remove_const::type key_type; + typedef BOOST_DEDUCED_TYPENAME ::boost::remove_const::type key_type; static key_type const& extract(value_type const& v) { @@ -143,6 +142,6 @@ namespace unordered_detail { return x.second == y.second; } }; -}} +}}} #endif diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp deleted file mode 100644 index 471d1d2e..00000000 --- a/include/boost/unordered/detail/fwd.hpp +++ /dev/null @@ -1,932 +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) - -// 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 - -// 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 unique.hpp and equivalent.hpp. - -// Template parameters: -// -// H = Hash Function -// P = Predicate -// A = Value Allocator -// G = Bucket group policy, 'grouped' or 'ungrouped' -// E = Key Extractor - -#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 -# 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_unique_table; - template class hash_equivalent_table; - template - class hash_node_constructor; - template - struct set_extractor; - template - struct map_extractor; - struct no_key; - - // Explicitly call a destructor - -#if defined(BOOST_MSVC) -#pragma warning(push) -#pragma warning(disable:4100) // unreferenced formal parameter -#endif - - template - inline void destroy(T* x) { - x->~T(); - } - -#if defined(BOOST_MSVC) -#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 - { - 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_() {} - }; - - // 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; - 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); - }; - - // 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 - { - 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); - } - }; - - // 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 - struct base { - typedef ungrouped_node_base type; - }; - }; - - struct grouped - { - template - struct base { - typedef grouped_node_base type; - }; - }; - - // The space used to store values in a node. - - 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; - } - value_type* value_ptr() { - return (ValueType*) this; - } - private: - value_base& operator=(value_base const&); - }; - - // 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(); - } - 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 - { - public: - typedef A value_allocator; - typedef hash_bucket bucket; - typedef hash_node node; - 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_; - - 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_); - } - }; - - //////////////////////////////////////////////////////////////////////////// - // - // 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 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). - - 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 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; - 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; - - // 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); - }; - - // 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 - 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_; - } - }; - - // 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 - { - hash_table(hash_table const&); - 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::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 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 - - 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; - 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; - - // 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; - 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; - - // Erase - // - // no throw - - void clear(); - std::size_t erase_key(key_type const& k); - 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); - - // 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); - }; - - /////////////////////////////////////////////////////////////////// - // - // Iterators - - // iterator_access is used to access the internal iterator without - // making it publicly available. - - class iterator_access - { - public: - template - static BOOST_DEDUCED_TYPENAME Iterator::base const& - get(Iterator const& it) - { - return it.base_; - } - }; - - 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(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(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_; - } - }; - - //////////////////////////////////////////////////////////////////////////// - // - // types - // - // This is used to convieniently pass around a container's typedefs - // without having 7 template parameters. - - 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; - }; -}} - -#endif diff --git a/include/boost/unordered/detail/move.hpp b/include/boost/unordered/detail/move.hpp index 16fd9212..49fb2a92 100644 --- a/include/boost/unordered/detail/move.hpp +++ b/include/boost/unordered/detail/move.hpp @@ -38,7 +38,8 @@ /*************************************************************************************************/ namespace boost { -namespace unordered_detail { +namespace unordered { +namespace detail { /*************************************************************************************************/ @@ -69,7 +70,7 @@ struct class_has_move_assign { /*************************************************************************************************/ template -struct has_move_assign : boost::mpl::and_, class_has_move_assign > {}; +struct has_move_assign : ::boost::mpl::and_, class_has_move_assign > {}; /*************************************************************************************************/ @@ -83,13 +84,13 @@ class test_can_convert_anything { }; /* REVISIT (sparent@adobe.com): This is a work around for Boost 1.34.1 and VC++ 2008 where - boost::is_convertible fails to compile. + ::boost::is_convertible fails to compile. */ template -struct is_convertible : boost::mpl::or_< - boost::is_same, - boost::is_convertible +struct is_convertible : ::boost::mpl::or_< + ::boost::is_same, + ::boost::is_convertible > { }; /*************************************************************************************************/ @@ -124,10 +125,10 @@ private: \brief The is_movable trait can be used to identify movable types. */ template -struct is_movable : boost::mpl::and_< - boost::is_convertible, T>, +struct is_movable : ::boost::mpl::and_< + ::boost::is_convertible, T>, move_detail::has_move_assign, - boost::mpl::not_ > + ::boost::mpl::not_ > > { }; /*************************************************************************************************/ @@ -138,7 +139,7 @@ struct is_movable : boost::mpl::and_< // unless the trait is specialized. template -struct is_movable : boost::mpl::false_ { }; +struct is_movable : ::boost::mpl::false_ { }; #endif @@ -158,10 +159,10 @@ struct is_movable : boost::mpl::false_ { }; template -struct copy_sink : boost::enable_if< - boost::mpl::and_< - boost::unordered_detail::move_detail::is_convertible, - boost::mpl::not_ > +struct copy_sink : ::boost::enable_if< + ::boost::mpl::and_< + ::boost::unordered::detail::move_detail::is_convertible, + ::boost::mpl::not_ > >, R > @@ -179,9 +180,9 @@ struct copy_sink : boost::enable_if< template -struct move_sink : boost::enable_if< - boost::mpl::and_< - boost::unordered_detail::move_detail::is_convertible, +struct move_sink : ::boost::enable_if< + ::boost::mpl::and_< + ::boost::unordered::detail::move_detail::is_convertible, is_movable >, R @@ -233,7 +234,8 @@ T& move(T& x) { #endif // BOOST_NO_SFINAE -} // namespace unordered_detail +} // namespace detail +} // namespace unordered } // namespace boost /*************************************************************************************************/ diff --git a/include/boost/unordered/detail/node.hpp b/include/boost/unordered/detail/node.hpp index 85a31410..1a500029 100644 --- a/include/boost/unordered/detail/node.hpp +++ b/include/boost/unordered/detail/node.hpp @@ -11,10 +11,7 @@ #ifndef BOOST_UNORDERED_DETAIL_NODE_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_NODE_HPP_INCLUDED -#include -#include -#include -#include +#include #if BOOST_WORKAROUND(__BORLANDC__, <= 0X0582) #define BOOST_UNORDERED_BORLAND_BOOL(x) (bool)(x) @@ -22,205 +19,342 @@ #define BOOST_UNORDERED_BORLAND_BOOL(x) x #endif -namespace boost { namespace unordered_detail { +namespace boost { namespace unordered { namespace detail { //////////////////////////////////////////////////////////////////////////// - // ungrouped node implementation + // + // This section implements buckets and nodes. Here's a rough + // inheritance diagram, to show how they pull together. + // + // For unordered_set/unordered_map: + // + // bucket value_base + // | | + // +--------------+-------------+ + // | + // ungrouped_node + // + // For unordered_multiset/unordered_multimap: + // + // bucket value_base + // | | + // +--------------+-------------+ + // | + // grouped_node + + // bucket + // + // 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 - inline BOOST_DEDUCED_TYPENAME ungrouped_node_base::node_ptr& - ungrouped_node_base::next_group(node_ptr ptr) + class bucket { - 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; - } + bucket& operator=(bucket const&); + public: + 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; - template - inline void ungrouped_node_base::unlink_nodes(bucket& b, - node_ptr begin, node_ptr end) + node_ptr next_; + + bucket() : next_() {} + }; + + // The space used to store values in a node. + + template + struct value_base { - node_ptr* pos = &b.next_; - while(*pos != begin) pos = &(*pos)->next_; - *pos = end; - } + typedef ValueType value_type; + BOOST_DEDUCED_TYPENAME ::boost::aligned_storage< + sizeof(value_type), + ::boost::alignment_of::value>::type data_; - 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_; - } + void* address() { + return this; } - else if(BOOST_UNORDERED_BORLAND_BOOL(next) && - get(next).group_prev_ == n) + value_type& value() { + return *(ValueType*) this; + } + value_type* value_ptr() { + return (ValueType*) this; + } + private: + value_base& operator=(value_base const&); + }; + + // 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 + : ::boost::unordered::detail::bucket, + value_base + { + typedef ::boost::unordered::detail::bucket bucket; + typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr; + typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr; + typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; + + std::size_t hash_; + + ungrouped_node() : bucket() {} + + void init(node_ptr) {} + + static node_ptr next_group(node_ptr ptr) { - // 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_; + return ptr->next_; } - 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_; + + static node_ptr next_group2(node_ptr ptr) + { + return ptr->next_; } - *pos = next; - } + + static std::size_t group_count(node_ptr n) + { + return !n ? 0 : 1; + } + + static void add_after_node(node_ptr n, node_ptr position) + { + n->next_ = position->next_; + position->next_ = position; + } + + static node_ptr unlink_node(bucket& b, node_ptr n) + { + return unlink_nodes(b, n, n->next_); + } + + static node_ptr unlink_nodes(bucket& b, node_ptr begin, node_ptr end) + { + node_ptr prev = b.next_; + while(prev->next_ != begin) prev = prev->next_; + prev->next_ = end; + return prev; + } + + static std::size_t get_hash(node_ptr p) + { + return static_cast(*p).hash_; + } + + static void set_hash(node_ptr p, std::size_t hash) + { + static_cast(*p).hash_ = hash; + } + + 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(); + } + }; + + // 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 - void grouped_node_base::unlink_nodes(bucket& b, - node_ptr begin, node_ptr end) + struct grouped_node + : ::boost::unordered::detail::bucket, + value_base { - node_ptr* pos = &next_group(begin); + typedef ::boost::unordered::detail::bucket bucket; + typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr; + typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr; + typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; - if(*pos != begin) { - // The node is at the beginning of a group. + std::size_t hash_; + node_ptr group_prev_; - // 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); + grouped_node() : bucket(), group_prev_() {} + void init(node_ptr n) + { + group_prev_ = n; } - 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; + static node_ptr next_group(node_ptr ptr) + { + return get(ptr).group_prev_->next_; + } + + static node_ptr next_group2(node_ptr ptr) + { + return get(ptr->next_).group_prev_; + } + + static std::size_t group_count(node_ptr ptr) + { + if (!ptr) return 0; + + node_ptr start = ptr; + std::size_t size = 0; + do { + ++size; + ptr = get(ptr).group_prev_; + } while(ptr != start); + return size; + } + + static void add_after_node(node_ptr n, node_ptr pos) + { + n->next_ = get(pos).group_prev_->next_; + get(n).group_prev_ = get(pos).group_prev_; + get(pos).group_prev_->next_ = n; + get(pos).group_prev_ = n; + } + + static node_ptr unlink_node(bucket& b, node_ptr n) + { + node_ptr next = n->next_; + node_ptr prev = get(n).group_prev_; + + if(prev->next_ != n) { + // The node is at the beginning of a group. + + // Find the previous node pointer: + prev = b.next_; + while(prev->next_ != n) { + prev = next_group2(prev); + } + + // 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_; + } + prev->next_ = next; + + return prev; } - *pos = end; - } - template - void grouped_node_base::unlink_nodes(bucket& b, node_ptr end) + static node_ptr unlink_nodes(bucket& b, node_ptr begin, node_ptr end) + { + node_ptr prev = get(begin).group_prev_; + + if(prev->next_ != begin) { + // The node is at the beginning of a group. + + // Find the previous node pointer: + prev = b.next_; + while(prev->next_ != begin) prev = next_group2(prev); + + 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; + } + } + } + + prev->next_ = end; + + return prev; + } + + // 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 node_ptr split_group(node_ptr split) + { + // Find first node in group. + node_ptr first = split; + while(next_group(first) == first) + first = get(first).group_prev_; + + 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; + } + + static std::size_t get_hash(node_ptr p) { + return static_cast(*p).hash_; + } + static void set_hash(node_ptr p, std::size_t hash) { + static_cast(*p).hash_ = hash; + } + 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(); + } + + static grouped_node& get(node_ptr ptr) { + return static_cast(*ptr); + } + }; + + // 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 { - split_group(end); - b.next_ = end; - } -}} + template + struct node { + typedef ungrouped_node type; + }; + }; + + struct grouped + { + template + struct node { + typedef grouped_node type; + }; + }; + +}}} #endif diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index d37c0155..07acb148 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -7,439 +7,502 @@ #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 { +namespace boost { namespace unordered { namespace detail { - //////////////////////////////////////////////////////////////////////////// - // Helper methods + // 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 unique_table and + // equivalent_table. See unique.hpp and equivalent.hpp for + // their declaration and implementation. - // strong exception safety, no side effects template - inline bool hash_table::equal( - key_type const& k, value_type const& v) const + class table : public T::buckets, public T::buffered_functions { - return this->key_eq()(k, get_key(v)); - } + table(table const&); + 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::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; - // 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); + 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::node_allocator node_allocator; + typedef BOOST_DEDUCED_TYPENAME T::iterator_pair iterator_pair; + + // Members + + std::size_t size_; + float mlf_; + std::size_t max_load_; + + // Helper methods + + key_type const& get_key(value_type const& v) const { + return extractor::extract(v); } - return it; - } - - // strong exception safety, no side effects - 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_; - while (BOOST_UNORDERED_BORLAND_BOOL(it) && - !equal(k, node::get_value(it))) + private: + // pre: this->buckets_ != null + template + node_ptr find_node_impl( + std::size_t bucket_index, + std::size_t hash, + Key const& k, + Pred const& eq) const { - it = node::next_group(it); - } - - return it; - } - - // strong exception safety, no side effects - // pre: this->buckets_ - 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 T::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_); + node_ptr n = this->buckets_[bucket_index].next_; + if (!n) return n; + n = n->next_; + + for (;;) + { + if (!n) return n; + std::size_t node_hash = node::get_hash(n); + if (hash == node_hash) + { + if (eq(k, get_key(node::get_value(n)))) + return n; + } + else + { + if (node_hash % this->bucket_count_ != bucket_index) + return node_ptr(); + } + n = node::next_group(n); } } - } - // 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(); + public: + template + node_ptr generic_find_node( + Key const& k, + Hash const& hash_function, + Pred const& eq) const + { + if (!this->size_) return node_ptr(); + std::size_t hash = hash_function(k); + return find_node_impl(hash % this->bucket_count_, hash, k, eq); + } + + node_ptr find_node( + std::size_t bucket_index, + std::size_t hash, + key_type const& k) const + { + if (!this->size_) return node_ptr(); + return find_node_impl(bucket_index, hash, k, this->key_eq()); } - } - // Move Construct + node_ptr find_node(key_type const& k) const + { + if (!this->size_) return node_ptr(); + std::size_t hash = this->hash_function()(k); + return find_node_impl(hash % this->bucket_count_, hash, k, + this->key_eq()); + } - 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); - } + node_ptr find_matching_node(node_ptr n) const + { + // For some stupid reason, I decided to support equality comparison + // when different hash functions are used. So I can't use the hash + // value from the node here. + + return find_node(get_key(node::get_value(n))); + } - 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()) { + //////////////////////////////////////////////////////////////////////// + // Load methods + + std::size_t max_size() const + { + using namespace std; + + // size < mlf_ * count + return double_to_size_t(ceil( + (double) this->mlf_ * this->max_bucket_count())) - 1; + } + + std::size_t calculate_max_load() + { + BOOST_ASSERT(this->buckets_); + + 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_)); + } + + void max_load_factor(float z) + { + BOOST_ASSERT(z > 0); + mlf_ = (std::max)(z, minimum_max_load_factor); + if (BOOST_UNORDERED_BORLAND_BOOL(this->buckets_)) + this->max_load_ = this->calculate_max_load(); + } + + std::size_t 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); + } + + float load_factor() const + { + BOOST_ASSERT(this->bucket_count_ != 0); + return static_cast(this->size_) + / static_cast(this->bucket_count_); + } + + //////////////////////////////////////////////////////////////////////// + // Constructors + + 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), + max_load_(0) + { + } + + table(table const& x, node_allocator const& a) + : buckets(a, x.min_buckets_for_size(x.size_)), + base(x), + size_(x.size_), + mlf_(x.mlf_), + max_load_(0) + { + if(x.size_) { + x.copy_buckets_to(*this); + this->max_load_ = calculate_max_load(); + } + } + + table(table& x, move_tag) + : buckets(x.node_alloc(), x.bucket_count_), + base(x), + size_(0), + mlf_(1.0f), + max_load_(0) + { 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. + table(table& x, node_allocator const& a, move_tag) + : buckets(a, x.bucket_count_), + base(x), + size_(0), + mlf_(x.mlf_), + max_load_(0) { - set_hash_functions op1(*this, x); - set_hash_functions op2(x, *this); - op1.commit(); - op2.commit(); + if(a == x.node_alloc()) { + this->partial_swap(x); + } + else if(x.size_) { + x.copy_buckets_to(*this); + this->size_ = x.size_; + this->max_load_ = calculate_max_load(); + } } - 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; + ~table() + {} + table& operator=(table const& x) + { + table tmp(x, this->node_alloc()); + this->fast_swap(tmp); + return *this; + } + + // Iterators + + node_ptr begin() const { + return !this->buckets_ ? + node_ptr() : this->buckets_[this->bucket_count_].next_; + } + + //////////////////////////////////////////////////////////////////////// + // Swap & Move + + void swap(table& x) + { + if(this->node_alloc() == x.node_alloc()) { + if(this != &x) this->fast_swap(x); + } + else { + this->slow_swap(x); + } + } + + void fast_swap(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); - - // 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(); + { + 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->max_load_, x.max_load_); } - - 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); - } - } + void slow_swap(table& x) + { + if(this == &x) return; - // 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). + { + // 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); - 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(); + // Create new buckets in separate 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_) this->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_); + + this->max_load_ = !this->buckets_ ? 0 : this->calculate_max_load(); + x.max_load_ = !x.buckets_ ? 0 : x.calculate_max_load(); } - // We've made it, the rest is no throw. - this->mlf_ = x.mlf_; - new_func_this.commit(); - } + void partial_swap(table& x) + { + this->buckets::swap(x); // No throw + std::swap(this->size_, x.size_); + std::swap(this->mlf_, x.mlf_); + std::swap(this->max_load_, x.max_load_); + } + + void move(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->max_load_ = x.max_load_; + x.size_ = 0; + } + else { + // Create new buckets in separate buckets + // 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->max_load_ = x.size_ ? calculate_max_load() : 0; + } + + // We've made it, the rest is no throw. + this->mlf_ = x.mlf_; + new_func_this.commit(); + } + + //////////////////////////////////////////////////////////////////////// + // Key methods + + std::size_t count(key_type const& k) const + { + if(!this->size_) return 0; + return node::group_count(find_node(k)); + } + + value_type& at(key_type const& k) const + { + if (this->size_) { + node_ptr it = find_node(k); + if (BOOST_UNORDERED_BORLAND_BOOL(it)) + return node::get_value(it); + } + + ::boost::throw_exception( + std::out_of_range("Unable to find key in unordered_map.")); + } + + iterator_pair equal_range(key_type const& k) const + { + if(!this->size_) + return iterator_pair(node_ptr(), node_ptr()); + + node_ptr ptr = find_node(k); + return iterator_pair(ptr, !ptr ? ptr : node::next_group(ptr)); + } + + // Erase + // + // no throw + + void clear() + { + if(!this->size_) return; + + bucket_ptr end = this->get_bucket(this->bucket_count_); + + node_ptr n = (end)->next_; + while(BOOST_UNORDERED_BORLAND_BOOL(n)) + { + node_ptr node_to_delete = n; + n = n->next_; + delete_node(node_to_delete); + } + + ++end; + for(bucket_ptr begin = this->buckets_; begin != end; ++begin) { + begin->next_ = bucket_ptr(); + } + + this->size_ = 0; + } + + std::size_t erase_key(key_type const& k) + { + if(!this->size_) return 0; + + std::size_t hash = this->hash_function()(k); + std::size_t bucket_index = hash % this->bucket_count_; + bucket_ptr bucket = this->get_bucket(bucket_index); + + node_ptr prev = bucket->next_; + if (!prev) return 0; + + for (;;) + { + if (!prev->next_) return 0; + std::size_t node_hash = node::get_hash(prev->next_); + if (node_hash % this->bucket_count_ != bucket_index) + return 0; + if (node_hash == hash && + this->key_eq()(k, get_key(node::get_value(prev->next_)))) + break; + prev = node::next_group2(prev); + } + + node_ptr pos = prev->next_; + node_ptr end = node::next_group(pos); + prev->next_ = end; + + this->fix_buckets(bucket, prev, end); + + std::size_t count = this->delete_nodes(pos, end); + this->size_ -= count; + + return count; + } + + node_ptr erase(node_ptr r) + { + BOOST_ASSERT(r); + node_ptr next = r->next_; + + bucket_ptr bucket = this->get_bucket( + node::get_hash(r) % this->bucket_count_); + node_ptr prev = node::unlink_node(*bucket, r); + + this->fix_buckets(bucket, prev, next); + + this->delete_node(r); + --this->size_; + + return next; + } + + node_ptr erase_range(node_ptr r1, node_ptr r2) + { + if (r1 == r2) return r2; + + std::size_t bucket_index = node::get_hash(r1) % this->bucket_count_; + node_ptr prev = node::unlink_nodes( + this->buckets_[bucket_index], r1, r2); + this->fix_buckets_range(bucket_index, prev, r1, r2); + this->size_ -= this->delete_nodes(r1, r2); + + return r2; + } + + // Reserve and rehash + + bool reserve_for_insert(std::size_t); + void rehash(std::size_t); + void rehash_impl(std::size_t); + }; //////////////////////////////////////////////////////////////////////////// // 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) + inline bool 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; + if (!this->buckets_) { + std::size_t old_bucket_count = this->bucket_count_; + this->bucket_count_ = (std::max)(this->bucket_count_, + this->min_buckets_for_size(size)); + this->create_buckets(); + this->max_load_ = calculate_max_load(); + return old_bucket_count != this->bucket_count_; + } + else { + 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; + } } } @@ -450,13 +513,14 @@ namespace boost { namespace unordered_detail { // strong otherwise. template - inline void hash_table::rehash(std::size_t min_buckets) + void table::rehash(std::size_t min_buckets) { using namespace std; if(!this->size_) { if(this->buckets_) this->delete_buckets(); this->bucket_count_ = next_prime(min_buckets); + this->max_load_ = 0; } else { // no throw: @@ -466,313 +530,308 @@ namespace boost { namespace unordered_detail { } } - // if hash function throws, basic exception safety - // strong otherwise - + // strong otherwise exception safety template - void hash_table - ::rehash_impl(std::size_t num_buckets) - { - hasher const& hf = this->hash_function(); + void table::rehash_impl(std::size_t num_buckets) + { std::size_t size = this->size_; - bucket_ptr end = this->get_bucket(this->bucket_count_); + BOOST_ASSERT(size); 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_); - - 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); - } - } - } + bucket_ptr src_start = this->get_bucket(this->bucket_count_); + bucket_ptr dst_start = dst.get_bucket(dst.bucket_count_); + + dst_start->next_ = src_start->next_; + src_start->next_ = bucket_ptr(); + // No need to do this, since the following is 'no throw'. + //this->size_ = 0; + + node_ptr prev = dst_start; + while (BOOST_UNORDERED_BORLAND_BOOL(prev->next_)) + prev = dst.place_in_bucket(prev, node::next_group2(prev)); + + // Swap the new nodes back into the container and setup the + // variables. + dst.swap(*this); // no throw + this->size_ = size; + this->max_load_ = calculate_max_load(); } //////////////////////////////////////////////////////////////////////////// - // 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 + // types // - // strong exception safety, no side effects - template - BOOST_DEDUCED_TYPENAME T::iterator_base - hash_table::find(key_type const& k) const + // This is used to convieniently pass around a container's typedefs + // without having 7 template parameters. + + template + struct types { - if(!this->size_) return this->end(); + public: + typedef K key_type; + typedef V value_type; + typedef H hasher; + typedef P key_equal; + typedef A value_allocator; + typedef E extractor; + + typedef ::boost::unordered::detail::node_constructor node_constructor; + typedef ::boost::unordered::detail::buckets buckets; + typedef ::boost::unordered::detail::buffered_functions buffered_functions; - bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); - node_ptr it = find_iterator(bucket, k); + 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::node_allocator node_allocator; - if (BOOST_UNORDERED_BORLAND_BOOL(it)) - return iterator_base(bucket, it); - else - return this->end(); - } + typedef std::pair iterator_pair; + }; +}}} - 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(); +namespace boost { namespace unordered { namespace iterator_detail { - 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 - { - if(!this->size_) - 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 (!it) - boost::throw_exception(std::out_of_range("Unable to find key in unordered_map.")); - - return node::get_value(it); - } - - // equal_range + // Iterators // - // strong exception safety, no side effects - 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()); + // all no throw - 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); + template class iterator; + template class c_iterator; + template class l_iterator; + template class cl_iterator; + + // Local Iterators + // + // all no throw + + template + class l_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 ::boost::unordered::detail::buckets buckets; + typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr; + typedef BOOST_DEDUCED_TYPENAME buckets::node node; + typedef cl_iterator const_local_iterator; + + friend class cl_iterator; + node_ptr ptr_; + std::size_t bucket_; + std::size_t bucket_count_; + + public: + l_iterator() : ptr_() {} + l_iterator(node_ptr x, std::size_t b, std::size_t c) + : ptr_(x), bucket_(b), bucket_count_(c) {} + BOOST_DEDUCED_TYPENAME A::reference operator*() const { + return node::get_value(ptr_); } - else { - return iterator_pair(this->end(), this->end()); + value_type* operator->() const { + return node::get_value_ptr(ptr_); } - } - - //////////////////////////////////////////////////////////////////////////// - // Erase methods - - template - void hash_table::clear() - { - 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); + l_iterator& operator++() { + ptr_ = ptr_->next_; + if (ptr_ && node::get_hash(ptr_) % bucket_count_ != bucket_) + ptr_ = node_ptr(); + return *this; } - - 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 - 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_return_iterator(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 T::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); - } + l_iterator operator++(int) { + l_iterator tmp(*this); + ptr_ = ptr_->next_; + if (ptr_ && node::get_hash(ptr_) % bucket_count_ != bucket_) + ptr_ = node_ptr(); + return tmp; } + bool operator==(l_iterator x) const { + return ptr_ == x.ptr_; + } + bool operator==(const_local_iterator x) const { + return ptr_ == x.ptr_; + } + bool operator!=(l_iterator x) const { + return ptr_ != x.ptr_; + } + bool operator!=(const_local_iterator x) const { + return ptr_ != x.ptr_; + } + }; - return r2; - } - - template - BOOST_DEDUCED_TYPENAME hash_table::iterator_base - hash_table::emplace_empty_impl_with_node( - node_constructor& a, std::size_t size) + template + class cl_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 > { - 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); - } -}} + public: + typedef BOOST_DEDUCED_TYPENAME A::value_type value_type; + + private: + typedef ::boost::unordered::detail::buckets buckets; + typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr; + typedef BOOST_DEDUCED_TYPENAME buckets::node node; + typedef l_iterator local_iterator; + friend class l_iterator; + + node_ptr ptr_; + std::size_t bucket_; + std::size_t bucket_count_; + + public: + cl_iterator() : ptr_() {} + cl_iterator(node_ptr x, std::size_t b, std::size_t c) + : ptr_(x), bucket_(b), bucket_count_(c) {} + cl_iterator(local_iterator x) + : ptr_(x.ptr_), bucket_(x.bucket_), bucket_count_(x.bucket_count_) + {} + BOOST_DEDUCED_TYPENAME A::const_reference + operator*() const { + return node::get_value(ptr_); + } + value_type const* operator->() const { + return node::get_value_ptr(ptr_); + } + cl_iterator& operator++() { + ptr_ = ptr_->next_; + if (ptr_ && node::get_hash(ptr_) % bucket_count_ != bucket_) + ptr_ = node_ptr(); + return *this; + } + cl_iterator operator++(int) { + cl_iterator tmp(*this); + ptr_ = ptr_->next_; + if (ptr_ && node::get_hash(ptr_) % bucket_count_ != bucket_) + ptr_ = node_ptr(); + return tmp; + } + bool operator==(local_iterator x) const { + return ptr_ == x.ptr_; + } + bool operator==(cl_iterator x) const { + return ptr_ == x.ptr_; + } + bool operator!=(local_iterator x) const { + return ptr_ != x.ptr_; + } + bool operator!=(cl_iterator x) const { + return ptr_ != x.ptr_; + } + }; + + template + class 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 ::boost::unordered::detail::buckets buckets; + typedef BOOST_DEDUCED_TYPENAME buckets::node node; + typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr; + typedef c_iterator const_iterator; + friend class c_iterator; + node_ptr node_; + + public: + + iterator() : node_() {} + explicit iterator(node_ptr const& x) : node_(x) {} + BOOST_DEDUCED_TYPENAME A::reference operator*() const { + return node::get_value(node_); + } + value_type* operator->() const { + return &node::get_value(node_); + } + iterator& operator++() { + node_ = node_->next_; return *this; + } + iterator operator++(int) { + iterator tmp(node_); node_ = node_->next_; return tmp; + } + bool operator==(iterator const& x) const { + return node_ == x.node_; + } + bool operator==(const_iterator const& x) const { + return node_ == x.node_; + } + bool operator!=(iterator const& x) const { + return node_ != x.node_; + } + bool operator!=(const_iterator const& x) const { + return node_ != x.node_; + } + }; + + template + class c_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 ::boost::unordered::detail::buckets buckets; + typedef BOOST_DEDUCED_TYPENAME buckets::node node; + typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr; + typedef ::boost::unordered::iterator_detail::iterator + iterator; + friend class ::boost::unordered::iterator_detail::iterator; + friend class ::boost::unordered::detail::iterator_access; + node_ptr node_; + + public: + + c_iterator() : node_() {} + explicit c_iterator(node_ptr const& x) : node_(x) {} + c_iterator(iterator const& x) : node_(x.node_) {} + BOOST_DEDUCED_TYPENAME A::const_reference operator*() const { + return node::get_value(node_); + } + value_type const* operator->() const { + return &node::get_value(node_); + } + c_iterator& operator++() { + node_ = node_->next_; return *this; + } + c_iterator operator++(int) { + c_iterator tmp(node_); node_ = node_->next_; return tmp; + } + bool operator==(iterator const& x) const { + return node_ == x.node_; + } + bool operator==(c_iterator const& x) const { + return node_ == x.node_; + } + bool operator!=(iterator const& x) const { + return node_ != x.node_; + } + bool operator!=(c_iterator const& x) const { + return node_ != x.node_; + } + }; +}}} #endif diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index 96fdfee6..988e3a3a 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -7,13 +7,12 @@ #ifndef BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED -#include #include -namespace boost { namespace unordered_detail { +namespace boost { namespace unordered { namespace detail { template - class hash_unique_table : public T::table + class unique_table : public T::table { public: typedef BOOST_DEDUCED_TYPENAME T::hasher hasher; @@ -27,81 +26,348 @@ namespace boost { namespace unordered_detail { 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; + typedef std::pair emplace_return; // Constructors - hash_unique_table(std::size_t n, hasher const& hf, key_equal const& eq, + 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) + unique_table(unique_table const& x) : table(x, x.node_alloc()) {} - hash_unique_table(hash_unique_table const& x, value_allocator const& a) + unique_table(unique_table const& x, value_allocator const& a) : table(x, a) {} - hash_unique_table(hash_unique_table& x, move_tag m) + unique_table(unique_table& x, move_tag m) : table(x, m) {} - hash_unique_table(hash_unique_table& x, value_allocator const& a, + unique_table(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); + ~unique_table() {} // equals - bool equals(hash_unique_table const&) const; + bool equals(unique_table const& other) const + { + if(this->size_ != other.size_) return false; + if(!this->size_) return true; + + for(node_ptr n1 = this->get_bucket(this->bucket_count_)->next_; + n1; n1 = n1->next_) + { + node_ptr n2 = other.find_matching_node(n1); + if(!BOOST_UNORDERED_BORLAND_BOOL(n2)) return false; + if(!extractor::compare_mapped( + node::get_value(n1), node::get_value(n2))) + return false; + } + + return true; + } + + //////////////////////////////////////////////////////////////////////// + // A convenience method for adding nodes. + + node_ptr add_node( + node_constructor& a, + std::size_t bucket_index, + std::size_t hash) + { + bucket_ptr b = this->get_bucket(bucket_index); + node_ptr n = a.release(); + node::set_hash(n, hash); + + if (!b->next_) + { + bucket_ptr start_node = this->get_bucket(this->bucket_count_); + + if (start_node->next_) { + this->buckets_[ + node::get_hash(start_node->next_) % this->bucket_count_ + ].next_ = n; + } + + b->next_ = start_node; + n->next_ = start_node->next_; + start_node->next_ = n; + } + else + { + n->next_ = b->next_->next_; + b->next_->next_ = n; + } + + ++this->size_; + return n; + } + + //////////////////////////////////////////////////////////////////////////// + // Insert methods + + // if hash function throws, basic exception safety + // strong otherwise + + value_type& operator[](key_type const& k) + { + typedef BOOST_DEDUCED_TYPENAME value_type::second_type mapped_type; + + std::size_t hash = this->hash_function()(k); + std::size_t bucket_index = hash % this->bucket_count_; + node_ptr pos = this->find_node(bucket_index, hash, k); + + if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { + return node::get_value(pos); + } + + // 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_index = hash % this->bucket_count_; + + // Nothing after this point can throw. + + return node::get_value(add_node(a, bucket_index, hash)); + } + + emplace_return emplace_impl_with_node(node_constructor& a) + { + // No side effects in this initial code + key_type const& k = this->get_key(a.value()); + std::size_t hash = this->hash_function()(k); + std::size_t bucket_index = hash % this->bucket_count_; + node_ptr pos = this->find_node(bucket_index, hash, k); + + if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { + // Found an existing key, return it (no throw). + return emplace_return(pos, false); + } + + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + if(this->reserve_for_insert(this->size_ + 1)) + bucket_index = hash % this->bucket_count_; + + // Nothing after this point can throw. + + return emplace_return(add_node(a, bucket_index, hash), true); + } + + emplace_return insert(value_type const& v) + { + key_type const& k = extractor::extract(v); + std::size_t hash = this->hash_function()(k); + std::size_t bucket_index = hash % this->bucket_count_; + node_ptr pos = this->find_node(bucket_index, hash, k); + + if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { + // Found an existing key, return it (no throw). + return emplace_return(pos, false); + } + + // Isn't in table, add to bucket. + + // Create the node before rehashing in case it throws an + // exception (need strong safety in such a case). + node_constructor a(*this); + a.construct(v); + + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + if(this->reserve_for_insert(this->size_ + 1)) + bucket_index = hash % this->bucket_count_; + + // Nothing after this point can throw. + + return emplace_return(add_node(a, bucket_index, hash), true); + } + - node_ptr add_node(node_constructor& a, bucket_ptr bucket); - #if defined(BOOST_UNORDERED_STD_FORWARD) template - emplace_return emplace(Args&&... args); + emplace_return emplace(Args&&... args) + { + return emplace_impl( + extractor::extract(std::forward(args)...), + std::forward(args)...); + } + template - emplace_return emplace_impl(key_type const& k, Args&&... args); + emplace_return emplace_impl(key_type const& k, Args&&... args) + { + // No side effects in this initial code + std::size_t hash = this->hash_function()(k); + std::size_t bucket_index = hash % this->bucket_count_; + node_ptr pos = this->find_node(bucket_index, hash, k); + + if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { + // Found an existing key, return it (no throw). + return emplace_return(pos, false); + } + + // 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_index = hash % this->bucket_count_; + + // Nothing after this point can throw. + + return emplace_return(add_node(a, bucket_index, hash), true); + } + template - emplace_return emplace_impl(no_key, Args&&... args); - template - emplace_return emplace_empty_impl(Args&&... args); + emplace_return 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); + } #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)); + template + emplace_return emplace(Arg0 const& arg0) + { + return emplace_impl(extractor::extract(arg0), arg0); + } +#define BOOST_UNORDERED_INSERT1_IMPL(z, n, _) \ + template \ + emplace_return emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + return emplace_impl(extractor::extract(arg0, arg1), \ + BOOST_UNORDERED_CALL_PARAMS(z, n)); \ + } + +#define BOOST_UNORDERED_INSERT2_IMPL(z, n, _) \ + template \ + emplace_return emplace_impl(key_type const& k, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + std::size_t hash = this->hash_function()(k); \ + std::size_t bucket_index = hash % this->bucket_count_; \ + node_ptr pos = this->find_node(bucket_index, hash, k); \ + \ + if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { \ + return emplace_return(pos, false); \ + } else { \ + node_constructor a(*this); \ + a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \ + \ + if(this->reserve_for_insert(this->size_ + 1)) \ + bucket_index = hash % this->bucket_count_; \ + \ + return emplace_return( \ + add_node(a, bucket_index, hash), \ + true); \ + } \ + } \ + \ + template \ + emplace_return emplace_impl(no_key, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + node_constructor a(*this); \ + a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \ + return emplace_impl_with_node(a); \ + } + + BOOST_PP_REPEAT_FROM_TO(2, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_INSERT1_IMPL, _) BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, - BOOST_UNORDERED_INSERT_IMPL, _) + BOOST_UNORDERED_INSERT2_IMPL, _) -#undef BOOST_UNORDERED_INSERT_IMPL +#undef BOOST_UNORDERED_INSERT1_IMPL +#undef BOOST_UNORDERED_INSERT2_IMPL #endif + //////////////////////////////////////////////////////////////////////// + // Insert range methods + // // if hash function throws, or inserting > 1 element, basic exception // safety strong otherwise + template - void insert_range(InputIt i, InputIt j); + void insert_range(InputIt i, InputIt j) + { + if(i != j) + return insert_range_impl(extractor::extract(*i), i, j); + } + template - void insert_range_impl(key_type const&, InputIt i, InputIt j); + void insert_range_impl(key_type const&, InputIt i, InputIt j) + { + node_constructor a(*this); + + do { + // 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. + // + // 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); + } + template - void insert_range_impl2(node_constructor&, key_type const&, InputIt i, InputIt j); + void 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 = this->hash_function()(k); + std::size_t bucket_index = hash % this->bucket_count_; + node_ptr pos = this->find_node(bucket_index, hash, 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_index = hash % this->bucket_count_; + } + + // Nothing after this point can throw. + add_node(a, bucket_index, hash); + } + } + template - void insert_range_impl(no_key, InputIt i, InputIt j); + void insert_range_impl(no_key, InputIt i, InputIt j) + { + node_constructor a(*this); + + do { + // No side effects in this initial code + a.construct(*i); + emplace_impl_with_node(a); + } while(++i != j); + } }; template @@ -110,10 +376,10 @@ namespace boost { namespace unordered_detail { BOOST_DEDUCED_TYPENAME A::value_type, H, P, A, set_extractor, - ungrouped> + true> { - typedef hash_unique_table > impl; - typedef hash_table > table; + typedef ::boost::unordered::detail::unique_table > impl; + typedef ::boost::unordered::detail::table > table; }; template @@ -121,393 +387,11 @@ namespace boost { namespace unordered_detail { K, BOOST_DEDUCED_TYPENAME A::value_type, H, P, A, map_extractor, - ungrouped> + true> { - typedef hash_unique_table > impl; - typedef hash_table > table; + typedef ::boost::unordered::detail::unique_table > impl; + typedef ::boost::unordered::detail::table > table; }; - - //////////////////////////////////////////////////////////////////////////// - // 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(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))) - 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 = this->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 = 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 = this->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 = this->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 = this->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_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( - 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 { - // 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. - // - // 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); - } - - 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 index 989883e0..801df188 100644 --- a/include/boost/unordered/detail/util.hpp +++ b/include/boost/unordered/detail/util.hpp @@ -7,16 +7,93 @@ #ifndef BOOST_UNORDERED_DETAIL_UTIL_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_UTIL_HPP_INCLUDED -#include -#include #include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include #include #include -#include -namespace boost { namespace unordered_detail { +// Template parameters: +// +// H = Hash Function +// P = Predicate +// A = Value Allocator +// G = Bucket group policy, 'grouped' or 'ungrouped' +// E = Key Extractor + +#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 +# 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 { namespace detail { + + static const float minimum_max_load_factor = 1e-3f; + static const std::size_t default_bucket_count = 11; + struct move_tag {}; + + template class unique_table; + template class equivalent_table; + template class node_constructor; + template + struct set_extractor; + template + struct map_extractor; + struct no_key; + + // Explicitly call a destructor + +#if defined(BOOST_MSVC) +#pragma warning(push) +#pragma warning(disable:4100) // unreferenced formal parameter +#endif + + template + inline void destroy(T* x) { + x->~T(); + } + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif //////////////////////////////////////////////////////////////////////////// // convert double to std::size_t @@ -95,12 +172,19 @@ namespace boost { namespace unordered_detail { //////////////////////////////////////////////////////////////////////////// // pair_cast - because some libraries don't have the full pair constructors. +#if 0 template inline std::pair pair_cast(std::pair const& x) { return std::pair(Dst1(x.first), Dst2(x.second)); } +#define BOOST_UNORDERED_PAIR_CAST(First, Last, Argument) \ + ::boost::unordered::detail::pair_cast(Argument) +#else +#define BOOST_UNORDERED_PAIR_CAST(First, Last, Argument) \ + Argument +#endif //////////////////////////////////////////////////////////////////////////// // insert_size/initial_size @@ -116,13 +200,13 @@ namespace boost { namespace unordered_detail { #endif template - inline std::size_t insert_size(I i, I j, boost::forward_traversal_tag) + 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) + inline std::size_t insert_size(I, I, ::boost::incrementable_traversal_tag) { return 1; } @@ -130,202 +214,18 @@ namespace boost { namespace unordered_detail { template inline std::size_t insert_size(I i, I j) { - BOOST_DEDUCED_TYPENAME boost::iterator_traversal::type + 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) + 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_) { -#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) - struct dummy { hash_node x; }; -#endif - boost::unordered_detail::destroy(node_->value_ptr()); - } - - 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_ptr()); - value_constructed_ = false; - } - } -}} +}}} #endif diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 86a6fc63..8b9e5e6e 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -54,15 +54,15 @@ namespace boost #endif typedef BOOST_DEDUCED_TYPENAME - boost::unordered_detail::rebind_wrap< + ::boost::unordered::detail::rebind_wrap< allocator_type, value_type>::type value_allocator; - typedef boost::unordered_detail::map types; typedef BOOST_DEDUCED_TYPENAME types::impl table; - typedef BOOST_DEDUCED_TYPENAME types::iterator_base iterator_base; + typedef BOOST_DEDUCED_TYPENAME types::node_ptr node_ptr; public: @@ -78,18 +78,14 @@ namespace boost 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; + typedef ::boost::unordered::iterator_detail::cl_iterator< + value_allocator, true> const_local_iterator; + typedef ::boost::unordered::iterator_detail::l_iterator< + value_allocator, true> local_iterator; + typedef ::boost::unordered::iterator_detail::c_iterator< + value_allocator, true> const_iterator; + typedef ::boost::unordered::iterator_detail::iterator< + value_allocator, true> iterator; #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) private: @@ -97,10 +93,10 @@ namespace boost table table_; - BOOST_DEDUCED_TYPENAME types::iterator_base const& + BOOST_DEDUCED_TYPENAME types::node_ptr const& get(const_iterator const& it) { - return boost::unordered_detail::iterator_access::get(it); + return ::boost::unordered::detail::iterator_access::get(it); } public: @@ -108,120 +104,59 @@ namespace boost // 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) - { - } + size_type = ::boost::unordered::detail::default_bucket_count, + const hasher& = hasher(), + const key_equal& = key_equal(), + const allocator_type& = allocator_type()); - explicit unordered_map(allocator_type const& a) - : table_(boost::unordered_detail::default_bucket_count, - hasher(), key_equal(), a) - { - } + explicit unordered_map(allocator_type const&); - unordered_map(unordered_map const& other, allocator_type const& a) - : table_(other.table_, a) - { - } + unordered_map(unordered_map const&, allocator_type const&); 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); - } + unordered_map(InputIt f, InputIt 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); - } + unordered_map( + InputIt, InputIt, + size_type, + const hasher& = hasher(), + const key_equal& = key_equal()); 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() {} + unordered_map( + InputIt, InputIt, + size_type, + const hasher&, + const key_equal&, + const allocator_type&); + + ~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()) - { - } - - unordered_map(unordered_map&& other, allocator_type const& a) - : table_(other.table_, a, boost::unordered_detail::move_tag()) - { - } - - unordered_map& operator=(unordered_map const& x) - { - table_ = x.table_; - return *this; - } - - unordered_map& operator=(unordered_map&& x) - { - table_.move(x.table_); - return *this; - } + unordered_map(unordered_map const&); + unordered_map(unordered_map&&); + unordered_map(unordered_map&&, allocator_type const&); + unordered_map& operator=(unordered_map const&); + unordered_map& operator=(unordered_map&&); #else - unordered_map(boost::unordered_detail::move_from< - unordered_map - > other) - : table_(other.source.table_, boost::unordered_detail::move_tag()) - { - } - + unordered_map(::boost::unordered::detail::move_from< + unordered_map + >); #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) - unordered_map& operator=(unordered_map x) - { - table_.move(x.table_); - return *this; - } + unordered_map& operator=(unordered_map); #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, a) - { - table_.insert_range(list.begin(), list.end()); - } + unordered_map( + std::initializer_list, + size_type = ::boost::unordered::detail::default_bucket_count, + const hasher& = hasher(), + const key_equal&l = key_equal(), + const allocator_type& = allocator_type()); - unordered_map& operator=(std::initializer_list list) - { - table_.clear(); - table_.insert_range(list.begin(), list.end()); - return *this; - } + unordered_map& operator=(std::initializer_list); #endif allocator_type get_allocator() const @@ -241,10 +176,7 @@ namespace boost return table_.size_; } - size_type max_size() const - { - return table_.max_size(); - } + size_type max_size() const; // iterators @@ -260,12 +192,12 @@ namespace boost iterator end() { - return iterator(table_.end()); + return iterator(); } const_iterator end() const { - return const_iterator(table_.end()); + return const_iterator(); } const_iterator cbegin() const @@ -275,38 +207,21 @@ namespace boost const_iterator cend() const { - return const_iterator(table_.end()); + return const_iterator(); } // modifiers #if defined(BOOST_UNORDERED_STD_FORWARD) template - std::pair emplace(Args&&... args) - { - return boost::unordered_detail::pair_cast( - table_.emplace(std::forward(args)...)); - } - + std::pair emplace(Args&&...); template - iterator emplace_hint(const_iterator, Args&&... args) - { - return iterator(table_.emplace(std::forward(args)...).first); - } + iterator emplace_hint(const_iterator, Args&&...); #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( - table_.emplace(v)); - } - - iterator emplace_hint(const_iterator, - value_type const& v = value_type()) - { - return iterator(table_.emplace(v).first); - } + std::pair emplace(value_type const& = value_type()); + iterator emplace_hint(const_iterator, value_type const& = value_type()); #endif #define BOOST_UNORDERED_EMPLACE(z, n, _) \ @@ -315,24 +230,14 @@ namespace boost > \ 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, BOOST_UNORDERED_EMPLACE, _) @@ -341,144 +246,57 @@ namespace boost #endif - std::pair insert(const value_type& obj) - { - return boost::unordered_detail::pair_cast( - table_.emplace(obj)); - } - - iterator insert(const_iterator, const value_type& obj) - { - return iterator(table_.emplace(obj).first); - } - - template - void insert(InputIt first, InputIt last) - { - table_.insert_range(first, last); - } + std::pair insert(const value_type&); + iterator insert(const_iterator, const value_type&); + template void insert(InputIt, InputIt); #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) - void insert(std::initializer_list list) - { - table_.insert_range(list.begin(), list.end()); - } + void insert(std::initializer_list); #endif - iterator erase(const_iterator position) - { - return iterator(table_.erase_return_iterator(get(position))); - } + iterator erase(const_iterator); + size_type erase(const key_type&); + iterator erase(const_iterator, const_iterator); + void quick_erase(const_iterator it) { erase(it); } + void erase_return_void(const_iterator it) { erase(it); } - size_type erase(const key_type& k) - { - return table_.erase_key(k); - } - - iterator erase(const_iterator first, const_iterator last) - { - 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)); - } - - void clear() - { - table_.clear(); - } - - void swap(unordered_map& other) - { - table_.swap(other.table_); - } + void clear(); + void swap(unordered_map&); // observers - hasher hash_function() const - { - return table_.hash_function(); - } + hasher hash_function() const; + key_equal key_eq() const; - key_equal key_eq() const - { - return table_.key_eq(); - } - - mapped_type& operator[](const key_type &k) - { - return table_[k].second; - } - - mapped_type& at(const key_type& k) - { - return table_.at(k).second; - } - - mapped_type const& at(const key_type& k) const - { - return table_.at(k).second; - } + mapped_type& operator[](const key_type&); + mapped_type& at(const key_type&); + mapped_type const& at(const key_type&) const; // lookup - iterator find(const key_type& k) - { - return iterator(table_.find(k)); - } - - const_iterator find(const key_type& k) const - { - return const_iterator(table_.find(k)); - } + iterator find(const key_type&); + const_iterator find(const key_type&) const; template iterator find( - CompatibleKey const& k, - CompatibleHash const& hash, - CompatiblePredicate const& eq) - { - return iterator(table_.find(k, hash, eq)); - } + CompatibleKey const&, + CompatibleHash const&, + CompatiblePredicate const&); template const_iterator find( - CompatibleKey const& k, - CompatibleHash const& hash, - CompatiblePredicate const& eq) const - { - return iterator(table_.find(k, hash, eq)); - } + CompatibleKey const&, + CompatibleHash const&, + CompatiblePredicate const&) const; - size_type count(const key_type& k) const - { - return table_.count(k); - } + size_type count(const key_type&) const; std::pair - equal_range(const key_type& k) - { - return boost::unordered_detail::pair_cast< - iterator, iterator>( - table_.equal_range(k)); - } - + equal_range(const key_type&); std::pair - equal_range(const key_type& k) const - { - return boost::unordered_detail::pair_cast< - const_iterator, const_iterator>( - table_.equal_range(k)); - } + equal_range(const key_type&) const; // bucket interface @@ -492,24 +310,23 @@ namespace boost return table_.max_bucket_count(); } - size_type bucket_size(size_type n) const - { - return table_.bucket_size(n); - } + size_type bucket_size(size_type n) const; size_type bucket(const key_type& k) const { - return table_.bucket_index(k); + return table_.hash_function()(k) % table_.bucket_count_; } local_iterator begin(size_type n) { - return local_iterator(table_.bucket_begin(n)); + return local_iterator( + table_.bucket_begin(n), n, table_.bucket_count_); } const_local_iterator begin(size_type n) const { - return const_local_iterator(table_.bucket_begin(n)); + return const_local_iterator( + table_.bucket_begin(n), n, table_.bucket_count_); } local_iterator end(size_type) @@ -524,7 +341,8 @@ namespace boost const_local_iterator cbegin(size_type n) const { - return const_local_iterator(table_.bucket_begin(n)); + return const_local_iterator( + table_.bucket_begin(n), n, table_.bucket_count_); } const_local_iterator cend(size_type) const @@ -534,64 +352,23 @@ namespace boost // hash policy - float load_factor() const - { - return table_.load_factor(); - } - float max_load_factor() const { return table_.mlf_; } - void max_load_factor(float m) - { - table_.max_load_factor(m); - } + float load_factor() const; + void max_load_factor(float); + void rehash(size_type n); - void rehash(size_type n) - { - table_.rehash(n); - } - #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) - friend bool operator==( - unordered_map const&, unordered_map const&); - friend bool operator!=( - unordered_map const&, unordered_map const&); + friend bool operator==( + unordered_map const&, unordered_map const&); + friend bool operator!=( + unordered_map const&, unordered_map const&); #endif }; // class template unordered_map - template - 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_); - } - - template - 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_); - } - - template - 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 class unordered_multimap { @@ -609,15 +386,15 @@ namespace boost #endif typedef BOOST_DEDUCED_TYPENAME - boost::unordered_detail::rebind_wrap< + ::boost::unordered::detail::rebind_wrap< allocator_type, value_type>::type value_allocator; - typedef boost::unordered_detail::multimap types; typedef BOOST_DEDUCED_TYPENAME types::impl table; - typedef BOOST_DEDUCED_TYPENAME types::iterator_base iterator_base; + typedef BOOST_DEDUCED_TYPENAME types::node_ptr node_ptr; public: @@ -633,18 +410,14 @@ namespace boost 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; + typedef ::boost::unordered::iterator_detail::cl_iterator< + value_allocator, false> const_local_iterator; + typedef ::boost::unordered::iterator_detail::l_iterator< + value_allocator, false> local_iterator; + typedef ::boost::unordered::iterator_detail::c_iterator< + value_allocator, false> const_iterator; + typedef ::boost::unordered::iterator_detail::iterator< + value_allocator, false> iterator; #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) private: @@ -652,10 +425,10 @@ namespace boost table table_; - BOOST_DEDUCED_TYPENAME types::iterator_base const& + BOOST_DEDUCED_TYPENAME types::node_ptr const& get(const_iterator const& it) { - return boost::unordered_detail::iterator_access::get(it); + return ::boost::unordered::detail::iterator_access::get(it); } public: @@ -663,121 +436,60 @@ namespace boost // 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) - { - } + size_type = ::boost::unordered::detail::default_bucket_count, + const hasher& = hasher(), + const key_equal& = key_equal(), + const allocator_type& = allocator_type()); - explicit unordered_multimap(allocator_type const& a) - : table_(boost::unordered_detail::default_bucket_count, - hasher(), key_equal(), a) - { - } + explicit unordered_multimap(allocator_type const&); - unordered_multimap(unordered_multimap const& other, - allocator_type const& a) - : table_(other.table_, a) - { - } + unordered_multimap(unordered_multimap const&, allocator_type const&); 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); - } + unordered_multimap(InputIt, InputIt); 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); - } + unordered_multimap( + InputIt, InputIt, + size_type, + const hasher& = hasher(), + const key_equal& = key_equal()); 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( + InputIt, InputIt, + size_type, + const hasher&, + const key_equal&, + const allocator_type&); - ~unordered_multimap() {} + ~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()) - { - } - - unordered_multimap(unordered_multimap&& other, allocator_type const& a) - : table_(other.table_, a, boost::unordered_detail::move_tag()) - { - } - - unordered_multimap& operator=(unordered_multimap const& x) - { - table_ = x.table_; - return *this; - } - - unordered_multimap& operator=(unordered_multimap&& x) - { - table_.move(x.table_); - return *this; - } + unordered_multimap(unordered_multimap const&); + unordered_multimap(unordered_multimap&&); + unordered_multimap(unordered_multimap&&, allocator_type const&); + unordered_multimap& operator=(unordered_multimap const&); + unordered_multimap& operator=(unordered_multimap&&); #else - unordered_multimap(boost::unordered_detail::move_from< - unordered_multimap - > other) - : table_(other.source.table_, boost::unordered_detail::move_tag()) - { - } + unordered_multimap(::boost::unordered::detail::move_from< + unordered_multimap + >); #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) - unordered_multimap& operator=(unordered_multimap x) - { - table_.move(x.table_); - return *this; - } + unordered_multimap& operator=(unordered_multimap); #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, a) - { - table_.insert_range(list.begin(), list.end()); - } + unordered_multimap( + std::initializer_list, + size_type = ::boost::unordered::detail::default_bucket_count, + const hasher& = hasher(), + const key_equal&l = key_equal(), + const allocator_type& = allocator_type()); - unordered_multimap& operator=(std::initializer_list list) - { - table_.clear(); - table_.insert_range(list.begin(), list.end()); - return *this; - } + unordered_multimap& operator=(std::initializer_list); #endif allocator_type get_allocator() const @@ -797,10 +509,7 @@ namespace boost return table_.size_; } - size_type max_size() const - { - return table_.max_size(); - } + size_type max_size() const; // iterators @@ -816,12 +525,12 @@ namespace boost iterator end() { - return iterator(table_.end()); + return iterator(); } const_iterator end() const { - return const_iterator(table_.end()); + return const_iterator(); } const_iterator cbegin() const @@ -831,36 +540,21 @@ namespace boost const_iterator cend() const { - return const_iterator(table_.end()); + return const_iterator(); } // modifiers #if defined(BOOST_UNORDERED_STD_FORWARD) template - iterator emplace(Args&&... args) - { - return iterator(table_.emplace(std::forward(args)...)); - } - + iterator emplace(Args&&...); template - iterator emplace_hint(const_iterator, Args&&... args) - { - return iterator(table_.emplace(std::forward(args)...)); - } + iterator emplace_hint(const_iterator, Args&&...); #else #if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) - iterator emplace(value_type const& v = value_type()) - { - return iterator(table_.emplace(v)); - } - - iterator emplace_hint(const_iterator, - value_type const& v = value_type()) - { - return iterator(table_.emplace(v)); - } + iterator emplace(value_type const& = value_type()); + iterator emplace_hint(const_iterator, value_type const& = value_type()); #endif #define BOOST_UNORDERED_EMPLACE(z, n, _) \ @@ -869,25 +563,14 @@ namespace boost > \ 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, \ BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - return iterator(table_.emplace( \ - BOOST_UNORDERED_CALL_PARAMS(z, n) \ - )); \ - } + ); BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EMPLACE, _) @@ -896,128 +579,54 @@ namespace boost #endif - iterator insert(const value_type& obj) - { - return iterator(table_.emplace(obj)); - } - - iterator insert(const_iterator, const value_type& obj) - { - return iterator(table_.emplace(obj)); - } - + iterator insert(const value_type&); + iterator insert(const_iterator, const value_type&); template - void insert(InputIt first, InputIt last) - { - table_.insert_range(first, last); - } + void insert(InputIt, InputIt); #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) - void insert(std::initializer_list list) - { - table_.insert_range(list.begin(), list.end()); - } + void insert(std::initializer_list); #endif - iterator erase(const_iterator position) - { - return iterator(table_.erase_return_iterator(get(position))); - } + iterator erase(const_iterator); + size_type erase(const key_type&); + iterator erase(const_iterator, const_iterator); + void quick_erase(const_iterator position) { erase(position); } + void erase_return_void(const_iterator position) { erase(position); } - size_type erase(const key_type& k) - { - return table_.erase_key(k); - } - - iterator erase(const_iterator first, const_iterator last) - { - 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)); - } - - void clear() - { - table_.clear(); - } - - void swap(unordered_multimap& other) - { - table_.swap(other.table_); - } + void clear(); + void swap(unordered_multimap&); // observers - hasher hash_function() const - { - return table_.hash_function(); - } - - key_equal key_eq() const - { - return table_.key_eq(); - } + hasher hash_function() const; + key_equal key_eq() const; // lookup - iterator find(const key_type& k) - { - return iterator(table_.find(k)); - } - - const_iterator find(const key_type& k) const - { - return const_iterator(table_.find(k)); - } + iterator find(const key_type&); + const_iterator find(const key_type&) const; template iterator find( - CompatibleKey const& k, - CompatibleHash const& hash, - CompatiblePredicate const& eq) - { - return iterator(table_.find(k, hash, eq)); - } + CompatibleKey const&, + CompatibleHash const&, + CompatiblePredicate const&); template const_iterator find( - CompatibleKey const& k, - CompatibleHash const& hash, - CompatiblePredicate const& eq) const - { - return iterator(table_.find(k, hash, eq)); - } + CompatibleKey const&, + CompatibleHash const&, + CompatiblePredicate const&) const; - size_type count(const key_type& k) const - { - return table_.count(k); - } + size_type count(const key_type&) const; std::pair - equal_range(const key_type& k) - { - return boost::unordered_detail::pair_cast< - iterator, iterator>( - table_.equal_range(k)); - } - + equal_range(const key_type&); std::pair - equal_range(const key_type& k) const - { - return boost::unordered_detail::pair_cast< - const_iterator, const_iterator>( - table_.equal_range(k)); - } + equal_range(const key_type&) const; // bucket interface @@ -1031,24 +640,23 @@ namespace boost return table_.max_bucket_count(); } - size_type bucket_size(size_type n) const - { - return table_.bucket_size(n); - } + size_type bucket_size(size_type) const; size_type bucket(const key_type& k) const { - return table_.bucket_index(k); + return table_.hash_function()(k) % table_.bucket_count_; } local_iterator begin(size_type n) { - return local_iterator(table_.bucket_begin(n)); + return local_iterator( + table_.bucket_begin(n), n, table_.bucket_count_); } const_local_iterator begin(size_type n) const { - return const_local_iterator(table_.bucket_begin(n)); + return const_local_iterator( + table_.bucket_begin(n), n, table_.bucket_count_); } local_iterator end(size_type) @@ -1063,7 +671,8 @@ namespace boost const_local_iterator cbegin(size_type n) const { - return const_local_iterator(table_.bucket_begin(n)); + return const_local_iterator( + table_.bucket_begin(n), n, table_.bucket_count_); } const_local_iterator cend(size_type) const @@ -1073,37 +682,879 @@ namespace boost // hash policy - float load_factor() const - { - return table_.load_factor(); - } - float max_load_factor() const { return table_.mlf_; } - void max_load_factor(float m) - { - table_.max_load_factor(m); - } - - void rehash(size_type n) - { - table_.rehash(n); - } + float load_factor() const; + void max_load_factor(float); + void rehash(size_type); #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 +//////////////////////////////////////////////////////////////////////////////// + template - inline bool operator==(unordered_multimap const& m1, - unordered_multimap const& m2) + unordered_map::unordered_map( + size_type n, const hasher &hf, const key_equal &eql, + const allocator_type &a) + : table_(n, hf, eql, a) + { + } + + template + unordered_map::unordered_map(allocator_type const& a) + : table_(::boost::unordered::detail::default_bucket_count, + hasher(), key_equal(), a) + { + } + + template + unordered_map::unordered_map( + unordered_map const& other, allocator_type const& a) + : table_(other.table_, a) + { + } + + template + template + unordered_map::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 + template + unordered_map::unordered_map( + InputIt f, InputIt l, + size_type n, + const hasher &hf, + const key_equal &eql) + : table_(::boost::unordered::detail::initial_size(f, l, n), + hf, eql, allocator_type()) + { + table_.insert_range(f, l); + } + + template + template + unordered_map::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); + } + + template + unordered_map::~unordered_map() {} + +#if !defined(BOOST_NO_RVALUE_REFERENCES) + template + unordered_map::unordered_map(unordered_map const& other) + : table_(other.table_) + { + } + + template + unordered_map::unordered_map(unordered_map&& other) + : table_(other.table_, ::boost::unordered::detail::move_tag()) + { + } + + template + unordered_map::unordered_map( + unordered_map&& other, allocator_type const& a) + : table_(other.table_, a, ::boost::unordered::detail::move_tag()) + { + } + + template + unordered_map& unordered_map:: + operator=(unordered_map const& x) + { + table_ = x.table_; + return *this; + } + + template + unordered_map& unordered_map:: + operator=(unordered_map&& x) + { + table_.move(x.table_); + return *this; + } +#else + template + unordered_map::unordered_map( + ::boost::unordered::detail::move_from > + other) + : table_(other.source.table_, ::boost::unordered::detail::move_tag()) + { + } + +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) + template + unordered_map& unordered_map:: + operator=(unordered_map x) + { + table_.move(x.table_); + return *this; + } +#endif +#endif + +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + template + unordered_map::unordered_map( + std::initializer_list list, size_type n, + const hasher &hf, const key_equal &eql, const allocator_type &a) + : table_( + ::boost::unordered::detail::initial_size( + list.begin(), list.end(), n), + hf, eql, a) + { + table_.insert_range(list.begin(), list.end()); + } + + template + unordered_map& unordered_map::operator=( + std::initializer_list list) + { + table_.clear(); + table_.insert_range(list.begin(), list.end()); + return *this; + } +#endif + + // size and capacity + + template + std::size_t unordered_map::max_size() const + { + return table_.max_size(); + } + + // modifiers + +#if defined(BOOST_UNORDERED_STD_FORWARD) + template + template + std::pair::iterator, bool> + unordered_map::emplace(Args&&... args) + { + return BOOST_UNORDERED_PAIR_CAST(iterator, bool, + table_.emplace(std::forward(args)...)); + } + + template + template + BOOST_DEDUCED_TYPENAME unordered_map::iterator + unordered_map::emplace_hint(const_iterator, Args&&... args) + { + return iterator(table_.emplace(std::forward(args)...).first); + } +#else + +#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) + template + std::pair::iterator, bool> + unordered_map::emplace(value_type const& v) + { + return BOOST_UNORDERED_PAIR_CAST(iterator, bool, table_.emplace(v)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_map::iterator + unordered_map::emplace_hint( + const_iterator, value_type const& v) + { + return iterator(table_.emplace(v).first); + } +#endif + +#define BOOST_UNORDERED_EMPLACE(z, n, _) \ + template \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + std::pair< \ + BOOST_DEDUCED_TYPENAME unordered_map::iterator, \ + bool> \ + unordered_map::emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + return \ + BOOST_UNORDERED_PAIR_CAST(iterator, bool, \ + table_.emplace( \ + BOOST_UNORDERED_CALL_PARAMS(z, n))); \ + } \ + \ + template \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + BOOST_DEDUCED_TYPENAME unordered_map::iterator \ + unordered_map::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, + BOOST_UNORDERED_EMPLACE, _) + +#undef BOOST_UNORDERED_EMPLACE + +#endif + + template + std::pair::iterator, bool> + unordered_map::insert(const value_type& obj) + { + return BOOST_UNORDERED_PAIR_CAST(iterator, bool, table_.insert(obj)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_map::iterator + unordered_map::insert(const_iterator, const value_type& obj) + { + return iterator(table_.emplace(obj).first); + } + + template + template + void unordered_map::insert(InputIt first, InputIt last) + { + table_.insert_range(first, last); + } + +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + template + void unordered_map::insert( + std::initializer_list list) + { + table_.insert_range(list.begin(), list.end()); + } +#endif + + template + BOOST_DEDUCED_TYPENAME unordered_map::iterator + unordered_map::erase(const_iterator position) + { + return iterator(table_.erase(get(position))); + } + + template + BOOST_DEDUCED_TYPENAME unordered_map::size_type + unordered_map::erase(const key_type& k) + { + return table_.erase_key(k); + } + + template + BOOST_DEDUCED_TYPENAME unordered_map::iterator + unordered_map::erase( + const_iterator first, const_iterator last) + { + return iterator(table_.erase_range(get(first), get(last))); + } + + template + void unordered_map::clear() + { + table_.clear(); + } + + template + void unordered_map::swap(unordered_map& other) + { + table_.swap(other.table_); + } + + // observers + + template + BOOST_DEDUCED_TYPENAME unordered_map::hasher + unordered_map::hash_function() const + { + return table_.hash_function(); + } + + template + BOOST_DEDUCED_TYPENAME unordered_map::key_equal + unordered_map::key_eq() const + { + return table_.key_eq(); + } + + template + BOOST_DEDUCED_TYPENAME unordered_map::mapped_type& + unordered_map::operator[](const key_type &k) + { + return table_[k].second; + } + + template + BOOST_DEDUCED_TYPENAME unordered_map::mapped_type& + unordered_map::at(const key_type& k) + { + return table_.at(k).second; + } + + template + BOOST_DEDUCED_TYPENAME unordered_map::mapped_type const& + unordered_map::at(const key_type& k) const + { + return table_.at(k).second; + } + + // lookup + + template + BOOST_DEDUCED_TYPENAME unordered_map::iterator + unordered_map::find(const key_type& k) + { + return iterator(table_.find_node(k)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_map::const_iterator + unordered_map::find(const key_type& k) const + { + return const_iterator(table_.find_node(k)); + } + + template + template + BOOST_DEDUCED_TYPENAME unordered_map::iterator + unordered_map::find( + CompatibleKey const& k, + CompatibleHash const& hash, + CompatiblePredicate const& eq) + { + return iterator(table_.generic_find_node(k, hash, eq)); + } + + template + template + BOOST_DEDUCED_TYPENAME unordered_map::const_iterator + unordered_map::find( + CompatibleKey const& k, + CompatibleHash const& hash, + CompatiblePredicate const& eq) const + { + return const_iterator(table_.generic_find_node(k, hash, eq)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_map::size_type + unordered_map::count(const key_type& k) const + { + return table_.count(k); + } + + template + std::pair< + BOOST_DEDUCED_TYPENAME unordered_map::iterator, + BOOST_DEDUCED_TYPENAME unordered_map::iterator> + unordered_map::equal_range(const key_type& k) + { + return BOOST_UNORDERED_PAIR_CAST(iterator, iterator, + table_.equal_range(k)); + } + + template + std::pair< + BOOST_DEDUCED_TYPENAME unordered_map::const_iterator, + BOOST_DEDUCED_TYPENAME unordered_map::const_iterator> + unordered_map::equal_range(const key_type& k) const + { + return BOOST_UNORDERED_PAIR_CAST(const_iterator, const_iterator, + table_.equal_range(k)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_map::size_type + unordered_map::bucket_size(size_type n) const + { + return table_.bucket_size(n); + } + + // hash policy + + template + float unordered_map::load_factor() const + { + return table_.load_factor(); + } + + template + void unordered_map::max_load_factor(float m) + { + table_.max_load_factor(m); + } + + template + void unordered_map::rehash(size_type n) + { + table_.rehash(n); + } + + template + 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_); + } + + template + 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_); + } + + template + 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 + unordered_multimap::unordered_multimap( + size_type n, const hasher &hf, const key_equal &eql, + const allocator_type &a) + : table_(n, hf, eql, a) + { + } + + template + unordered_multimap::unordered_multimap(allocator_type const& a) + : table_(::boost::unordered::detail::default_bucket_count, + hasher(), key_equal(), a) + { + } + + template + unordered_multimap::unordered_multimap( + unordered_multimap const& other, allocator_type const& a) + : table_(other.table_, a) + { + } + + template + template + unordered_multimap::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 + template + unordered_multimap::unordered_multimap( + InputIt f, InputIt l, + size_type n, + const hasher &hf, + const key_equal &eql) + : table_(::boost::unordered::detail::initial_size(f, l, n), + hf, eql, allocator_type()) + { + table_.insert_range(f, l); + } + + template + template + unordered_multimap::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); + } + + template + unordered_multimap::~unordered_multimap() {} + +#if !defined(BOOST_NO_RVALUE_REFERENCES) + template + unordered_multimap::unordered_multimap( + unordered_multimap const& other) + : table_(other.table_) + { + } + + template + unordered_multimap::unordered_multimap( + unordered_multimap&& other) + : table_(other.table_, ::boost::unordered::detail::move_tag()) + { + } + + template + unordered_multimap::unordered_multimap( + unordered_multimap&& other, allocator_type const& a) + : table_(other.table_, a, ::boost::unordered::detail::move_tag()) + { + } + + template + unordered_multimap& unordered_multimap:: + operator=(unordered_multimap const& x) + { + table_ = x.table_; + return *this; + } + + template + unordered_multimap& unordered_multimap:: + operator=(unordered_multimap&& x) + { + table_.move(x.table_); + return *this; + } + +#else + + template + unordered_multimap::unordered_multimap( + ::boost::unordered::detail::move_from< + unordered_multimap > other) + : table_(other.source.table_, ::boost::unordered::detail::move_tag()) + { + } + +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) + template + unordered_multimap& unordered_multimap:: + operator=(unordered_multimap x) + { + table_.move(x.table_); + return *this; + } +#endif +#endif + +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + template + unordered_multimap::unordered_multimap( + std::initializer_list list, size_type n, + const hasher &hf, const key_equal &eql, const allocator_type &a) + : table_( + ::boost::unordered::detail::initial_size( + list.begin(), list.end(), n), + hf, eql, a) + { + table_.insert_range(list.begin(), list.end()); + } + + template + unordered_multimap& unordered_multimap::operator=( + std::initializer_list list) + { + table_.clear(); + table_.insert_range(list.begin(), list.end()); + return *this; + } +#endif + + // size and capacity + + template + std::size_t unordered_multimap::max_size() const + { + return table_.max_size(); + } + + // modifiers + +#if defined(BOOST_UNORDERED_STD_FORWARD) + + template + template + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + unordered_multimap::emplace(Args&&... args) + { + return iterator(table_.emplace(std::forward(args)...)); + } + + template + template + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + unordered_multimap::emplace_hint( + const_iterator, Args&&... args) + { + return iterator(table_.emplace(std::forward(args)...)); + } + +#else + +#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) + template + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + unordered_multimap::emplace(value_type const& v) + { + return iterator(table_.emplace(v)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + unordered_multimap::emplace_hint( + const_iterator, value_type const& v) + { + return iterator(table_.emplace(v)); + } +#endif + +#define BOOST_UNORDERED_EMPLACE(z, n, _) \ + template \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator \ + unordered_multimap::emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + return iterator(table_.emplace( \ + BOOST_UNORDERED_CALL_PARAMS(z, n))); \ + } \ + \ + template \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator \ + unordered_multimap::emplace_hint( \ + const_iterator, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + return iterator(table_.emplace( \ + BOOST_UNORDERED_CALL_PARAMS(z, n))); \ + } + + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_EMPLACE, _) + +#undef BOOST_UNORDERED_EMPLACE + +#endif + + template + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + unordered_multimap::insert(const value_type& obj) + { + return iterator(table_.emplace(obj)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + unordered_multimap::insert( + const_iterator, const value_type& obj) + { + return iterator(table_.emplace(obj)); + } + + template + template + void unordered_multimap::insert(InputIt first, InputIt last) + { + table_.insert_range(first, last); + } + +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + template + void unordered_multimap::insert( + std::initializer_list list) + { + table_.insert_range(list.begin(), list.end()); + } +#endif + + template + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + unordered_multimap::erase(const_iterator position) + { + return iterator(table_.erase(get(position))); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multimap::size_type + unordered_multimap::erase(const key_type& k) + { + return table_.erase_key(k); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + unordered_multimap::erase( + const_iterator first, const_iterator last) + { + return iterator(table_.erase_range(get(first), get(last))); + } + + template + void unordered_multimap::clear() + { + table_.clear(); + } + + template + void unordered_multimap::swap(unordered_multimap& other) + { + table_.swap(other.table_); + } + + // observers + + template + BOOST_DEDUCED_TYPENAME unordered_multimap::hasher + unordered_multimap::hash_function() const + { + return table_.hash_function(); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multimap::key_equal + unordered_multimap::key_eq() const + { + return table_.key_eq(); + } + + // lookup + + template + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + unordered_multimap::find(const key_type& k) + { + return iterator(table_.find_node(k)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multimap::const_iterator + unordered_multimap::find(const key_type& k) const + { + return const_iterator(table_.find_node(k)); + } + + template + template + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + unordered_multimap::find( + CompatibleKey const& k, + CompatibleHash const& hash, + CompatiblePredicate const& eq) + { + return iterator(table_.generic_find_node(k, hash, eq)); + } + + template + template + BOOST_DEDUCED_TYPENAME unordered_multimap::const_iterator + unordered_multimap::find( + CompatibleKey const& k, + CompatibleHash const& hash, + CompatiblePredicate const& eq) const + { + return const_iterator(table_.generic_find_node(k, hash, eq)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multimap::size_type + unordered_multimap::count(const key_type& k) const + { + return table_.count(k); + } + + template + std::pair< + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator, + BOOST_DEDUCED_TYPENAME unordered_multimap::iterator> + unordered_multimap::equal_range(const key_type& k) + { + return BOOST_UNORDERED_PAIR_CAST(iterator, iterator, + table_.equal_range(k)); + } + + template + std::pair< + BOOST_DEDUCED_TYPENAME unordered_multimap::const_iterator, + BOOST_DEDUCED_TYPENAME unordered_multimap::const_iterator> + unordered_multimap::equal_range(const key_type& k) const + { + return BOOST_UNORDERED_PAIR_CAST(const_iterator, const_iterator, + table_.equal_range(k)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multimap::size_type + unordered_multimap::bucket_size(size_type n) const + { + return table_.bucket_size(n); + } + + // hash policy + + template + float unordered_multimap::load_factor() const + { + return table_.load_factor(); + } + + template + void unordered_multimap::max_load_factor(float m) + { + table_.max_load_factor(m); + } + + template + void unordered_multimap::rehash(size_type n) + { + table_.rehash(n); + } + + template + inline bool operator==( + unordered_multimap const& m1, + unordered_multimap const& m2) { #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) struct dummy { unordered_multimap x; }; @@ -1112,8 +1563,9 @@ namespace boost } template - inline bool operator!=(unordered_multimap const& m1, - unordered_multimap const& m2) + inline bool operator!=( + unordered_multimap const& m1, + unordered_multimap const& m2) { #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) struct dummy { unordered_multimap x; }; @@ -1122,8 +1574,9 @@ namespace boost } template - inline void swap(unordered_multimap &m1, - unordered_multimap &m2) + inline void swap( + unordered_multimap &m1, + unordered_multimap &m2) { #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) struct dummy { unordered_multimap x; }; @@ -1131,6 +1584,7 @@ namespace boost m1.swap(m2); } + } // namespace boost #if defined(BOOST_MSVC) diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 89d1c1cf..fae9a000 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -54,15 +54,15 @@ namespace boost #endif typedef BOOST_DEDUCED_TYPENAME - boost::unordered_detail::rebind_wrap< + ::boost::unordered::detail::rebind_wrap< allocator_type, value_type>::type value_allocator; - typedef boost::unordered_detail::set types; typedef BOOST_DEDUCED_TYPENAME types::impl table; - typedef BOOST_DEDUCED_TYPENAME types::iterator_base iterator_base; + typedef BOOST_DEDUCED_TYPENAME types::node_ptr node_ptr; public: @@ -78,12 +78,10 @@ namespace boost 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 ::boost::unordered::iterator_detail::cl_iterator< + value_allocator, true> const_local_iterator; + typedef ::boost::unordered::iterator_detail::c_iterator< + value_allocator, true> const_iterator; typedef const_local_iterator local_iterator; typedef const_iterator iterator; @@ -93,10 +91,10 @@ namespace boost table table_; - BOOST_DEDUCED_TYPENAME types::iterator_base const& + BOOST_DEDUCED_TYPENAME types::node_ptr const& get(const_iterator const& it) { - return boost::unordered_detail::iterator_access::get(it); + return ::boost::unordered::detail::iterator_access::get(it); } public: @@ -104,118 +102,59 @@ namespace boost // 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) - { - } + size_type = ::boost::unordered::detail::default_bucket_count, + const hasher& = hasher(), + const key_equal& = key_equal(), + const allocator_type& = allocator_type()); - explicit unordered_set(allocator_type const& a) - : table_(boost::unordered_detail::default_bucket_count, - hasher(), key_equal(), a) - { - } + explicit unordered_set(allocator_type const&); - unordered_set(unordered_set const& other, allocator_type const& a) - : table_(other.table_, a) - { - } + unordered_set(unordered_set const&, allocator_type const&); 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); - } + unordered_set(InputIt f, InputIt 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); - } + unordered_set( + InputIt, InputIt, + size_type, + const hasher& = hasher(), + const key_equal& = key_equal()); + + template + unordered_set( + InputIt, InputIt, + size_type, + const hasher&, + const key_equal&, + const allocator_type&); - 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() {} + ~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()) - { - } - - unordered_set(unordered_set&& other, allocator_type const& a) - : table_(other.table_, a, boost::unordered_detail::move_tag()) - { - } - - unordered_set& operator=(unordered_set const& x) - { - table_ = x.table_; - return *this; - } - - unordered_set& operator=(unordered_set&& x) - { - table_.move(x.table_); - return *this; - } + unordered_set(unordered_set const&); + unordered_set(unordered_set&&); + unordered_set(unordered_set&&, allocator_type const&); + unordered_set& operator=(unordered_set const&); + unordered_set& operator=(unordered_set&&); #else - unordered_set(boost::unordered_detail::move_from< - unordered_set - > other) - : table_(other.source.table_, boost::unordered_detail::move_tag()) - { - } - + unordered_set(::boost::unordered::detail::move_from< + unordered_set + >); #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) - unordered_set& operator=(unordered_set x) - { - table_.move(x.table_); - return *this; - } + unordered_set& operator=(unordered_set); #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, a) - { - table_.insert_range(list.begin(), list.end()); - } + unordered_set( + std::initializer_list, + size_type = ::boost::unordered::detail::default_bucket_count, + const hasher& = hasher(), + const key_equal&l = key_equal(), + const allocator_type& = allocator_type()); - unordered_set& operator=(std::initializer_list list) - { - table_.clear(); - table_.insert_range(list.begin(), list.end()); - return *this; - } + unordered_set& operator=(std::initializer_list); #endif allocator_type get_allocator() const @@ -235,10 +174,7 @@ namespace boost return table_.size_; } - size_type max_size() const - { - return table_.max_size(); - } + size_type max_size() const; // iterators @@ -254,12 +190,12 @@ namespace boost iterator end() { - return iterator(table_.end()); + return iterator(); } const_iterator end() const { - return const_iterator(table_.end()); + return const_iterator(); } const_iterator cbegin() const @@ -269,37 +205,20 @@ namespace boost const_iterator cend() const { - return const_iterator(table_.end()); + return const_iterator(); } // modifiers #if defined(BOOST_UNORDERED_STD_FORWARD) template - std::pair emplace(Args&&... args) - { - return boost::unordered_detail::pair_cast( - table_.emplace(std::forward(args)...)); - } - + std::pair emplace(Args&&...); template - iterator emplace_hint(const_iterator, Args&&... args) - { - return iterator(table_.emplace(std::forward(args)...).first); - } + iterator emplace_hint(const_iterator, Args&&...); #else - std::pair emplace(value_type const& v = value_type()) - { - return boost::unordered_detail::pair_cast( - table_.emplace(v)); - } - - iterator emplace_hint(const_iterator, - value_type const& v = value_type()) - { - return iterator(table_.emplace(v).first); - } + std::pair emplace(value_type const& = value_type()); + iterator emplace_hint(const_iterator, value_type const& = value_type()); #define BOOST_UNORDERED_EMPLACE(z, n, _) \ template < \ @@ -307,24 +226,14 @@ namespace boost > \ 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, BOOST_UNORDERED_EMPLACE, _) @@ -333,105 +242,42 @@ namespace boost #endif - std::pair insert(const value_type& obj) - { - return boost::unordered_detail::pair_cast( - table_.emplace(obj)); - } - - iterator insert(const_iterator, const value_type& obj) - { - return iterator(table_.emplace(obj).first); - } - - template - void insert(InputIt first, InputIt last) - { - table_.insert_range(first, last); - } + std::pair insert(const value_type&); + iterator insert(const_iterator, const value_type&); + template void insert(InputIt, InputIt); #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) - void insert(std::initializer_list list) - { - table_.insert_range(list.begin(), list.end()); - } + void insert(std::initializer_list); #endif - iterator erase(const_iterator position) - { - return iterator(table_.erase_return_iterator(get(position))); - } + iterator erase(const_iterator); + size_type erase(const key_type&); + iterator erase(const_iterator, const_iterator); + void quick_erase(const_iterator it) { erase(it); } + void erase_return_void(const_iterator it) { erase(it); } - size_type erase(const key_type& k) - { - return table_.erase_key(k); - } - - iterator erase(const_iterator first, const_iterator last) - { - 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)); - } - - void clear() - { - table_.clear(); - } - - void swap(unordered_set& other) - { - table_.swap(other.table_); - } + void clear(); + void swap(unordered_set&); // observers - hasher hash_function() const - { - return table_.hash_function(); - } - - key_equal key_eq() const - { - return table_.key_eq(); - } + hasher hash_function() const; + key_equal key_eq() const; // lookup - const_iterator find(const key_type& k) const - { - return const_iterator(table_.find(k)); - } + const_iterator find(const key_type&) const; 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); - } + CompatibleKey const&, + CompatibleHash const&, + CompatiblePredicate const&) const; + size_type count(const key_type&) const; std::pair - equal_range(const key_type& k) const - { - return boost::unordered_detail::pair_cast< - const_iterator, const_iterator>( - table_.equal_range(k)); - } + equal_range(const key_type&) const; // bucket interface @@ -445,24 +291,23 @@ namespace boost return table_.max_bucket_count(); } - size_type bucket_size(size_type n) const - { - return table_.bucket_size(n); - } + size_type bucket_size(size_type n) const; size_type bucket(const key_type& k) const { - return table_.bucket_index(k); + return table_.hash_function()(k) % table_.bucket_count_; } local_iterator begin(size_type n) { - return local_iterator(table_.bucket_begin(n)); + return local_iterator( + table_.bucket_begin(n), n, table_.bucket_count_); } const_local_iterator begin(size_type n) const { - return const_local_iterator(table_.bucket_begin(n)); + return const_local_iterator( + table_.bucket_begin(n), n, table_.bucket_count_); } local_iterator end(size_type) @@ -477,7 +322,8 @@ namespace boost const_local_iterator cbegin(size_type n) const { - return const_local_iterator(table_.bucket_begin(n)); + return const_local_iterator( + table_.bucket_begin(n), n, table_.bucket_count_); } const_local_iterator cend(size_type) const @@ -487,64 +333,23 @@ namespace boost // hash policy - float load_factor() const - { - return table_.load_factor(); - } - float max_load_factor() const { return table_.mlf_; } - void max_load_factor(float m) - { - table_.max_load_factor(m); - } - - void rehash(size_type n) - { - table_.rehash(n); - } + float load_factor() const; + void max_load_factor(float); + void rehash(size_type n); #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) - friend bool operator==( - unordered_set const&, unordered_set const&); - friend bool operator!=( - unordered_set const&, unordered_set const&); + friend bool operator==( + unordered_set const&, unordered_set const&); + friend bool operator!=( + unordered_set const&, unordered_set const&); #endif }; // class template unordered_set - template - 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_); - } - - template - 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_); - } - - template - 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 class unordered_multiset { @@ -561,15 +366,15 @@ namespace boost #endif typedef BOOST_DEDUCED_TYPENAME - boost::unordered_detail::rebind_wrap< + ::boost::unordered::detail::rebind_wrap< allocator_type, value_type>::type value_allocator; - typedef boost::unordered_detail::multiset types; typedef BOOST_DEDUCED_TYPENAME types::impl table; - typedef BOOST_DEDUCED_TYPENAME types::iterator_base iterator_base; + typedef BOOST_DEDUCED_TYPENAME types::node_ptr node_ptr; public: @@ -585,12 +390,10 @@ namespace boost 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 ::boost::unordered::iterator_detail::cl_iterator< + value_allocator, false> const_local_iterator; + typedef ::boost::unordered::iterator_detail::c_iterator< + value_allocator, false> const_iterator; typedef const_local_iterator local_iterator; typedef const_iterator iterator; @@ -600,10 +403,10 @@ namespace boost table table_; - BOOST_DEDUCED_TYPENAME types::iterator_base const& + BOOST_DEDUCED_TYPENAME types::node_ptr const& get(const_iterator const& it) { - return boost::unordered_detail::iterator_access::get(it); + return ::boost::unordered::detail::iterator_access::get(it); } public: @@ -611,119 +414,60 @@ namespace boost // 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) - { - } + size_type = ::boost::unordered::detail::default_bucket_count, + const hasher& = hasher(), + const key_equal& = key_equal(), + const allocator_type& = allocator_type()); - explicit unordered_multiset(allocator_type const& a) - : table_(boost::unordered_detail::default_bucket_count, - hasher(), key_equal(), a) - { - } + explicit unordered_multiset(allocator_type const&); - unordered_multiset(unordered_multiset const& other, - allocator_type const& a) - : table_(other.table_, a) - { - } + unordered_multiset(unordered_multiset const&, allocator_type const&); 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); - } + unordered_multiset(InputIt, InputIt); 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); - } + unordered_multiset( + InputIt, InputIt, + size_type, + const hasher& = hasher(), + const key_equal& = key_equal()); 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( + InputIt, InputIt, + size_type, + const hasher&, + const key_equal&, + const allocator_type&); - ~unordered_multiset() {} + ~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()) - { - } - - unordered_multiset(unordered_multiset&& other, allocator_type const& a) - : table_(other.table_, a, boost::unordered_detail::move_tag()) - { - } - - unordered_multiset& operator=(unordered_multiset const& x) - { - table_ = x.table_; - return *this; - } - - unordered_multiset& operator=(unordered_multiset&& x) - { - table_.move(x.table_); - return *this; - } + unordered_multiset(unordered_multiset const&); + unordered_multiset(unordered_multiset&&); + unordered_multiset(unordered_multiset&&, allocator_type const&); + unordered_multiset& operator=(unordered_multiset const&); + unordered_multiset& operator=(unordered_multiset&&); #else - unordered_multiset(boost::unordered_detail::move_from< - unordered_multiset - > other) - : table_(other.source.table_, boost::unordered_detail::move_tag()) - { - } + unordered_multiset(::boost::unordered::detail::move_from< + unordered_multiset + >); #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) - unordered_multiset& operator=(unordered_multiset x) - { - table_.move(x.table_); - return *this; - } + unordered_multiset& operator=(unordered_multiset); #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, a) - { - table_.insert_range(list.begin(), list.end()); - } + unordered_multiset( + std::initializer_list, + size_type = ::boost::unordered::detail::default_bucket_count, + const hasher& = hasher(), + const key_equal&l = key_equal(), + const allocator_type& = allocator_type()); - unordered_multiset& operator=(std::initializer_list list) - { - table_.clear(); - table_.insert_range(list.begin(), list.end()); - return *this; - } + unordered_multiset& operator=(std::initializer_list); #endif allocator_type get_allocator() const @@ -743,10 +487,7 @@ namespace boost return table_.size_; } - size_type max_size() const - { - return table_.max_size(); - } + size_type max_size() const; // iterators @@ -762,12 +503,12 @@ namespace boost iterator end() { - return iterator(table_.end()); + return iterator(); } const_iterator end() const { - return const_iterator(table_.end()); + return const_iterator(); } const_iterator cbegin() const @@ -777,35 +518,20 @@ namespace boost const_iterator cend() const { - return const_iterator(table_.end()); + return const_iterator(); } // modifiers #if defined(BOOST_UNORDERED_STD_FORWARD) template - iterator emplace(Args&&... args) - { - return iterator(table_.emplace(std::forward(args)...)); - } - + iterator emplace(Args&&...); template - iterator emplace_hint(const_iterator, Args&&... args) - { - return iterator(table_.emplace(std::forward(args)...)); - } + iterator emplace_hint(const_iterator, Args&&...); #else - iterator emplace(value_type const& v = value_type()) - { - return iterator(table_.emplace(v)); - } - - iterator emplace_hint(const_iterator, - value_type const& v = value_type()) - { - return iterator(table_.emplace(v)); - } + iterator emplace(value_type const& = value_type()); + iterator emplace_hint(const_iterator, value_type const& = value_type()); #define BOOST_UNORDERED_EMPLACE(z, n, _) \ template < \ @@ -813,23 +539,14 @@ namespace boost > \ 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, \ BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - return iterator(table_.emplace( \ - BOOST_UNORDERED_CALL_PARAMS(z, n) \ - )); \ - } + ); BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EMPLACE, _) @@ -838,105 +555,43 @@ namespace boost #endif - iterator insert(const value_type& obj) - { - return iterator(table_.emplace(obj)); - } - - iterator insert(const_iterator, const value_type& obj) - { - return iterator(table_.emplace(obj)); - } - + iterator insert(const value_type&); + iterator insert(const_iterator, const value_type&); template - void insert(InputIt first, InputIt last) - { - table_.insert_range(first, last); - } + void insert(InputIt, InputIt); #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) - void insert(std::initializer_list list) - { - table_.insert_range(list.begin(), list.end()); - } + void insert(std::initializer_list); #endif - iterator erase(const_iterator position) - { - return iterator(table_.erase_return_iterator(get(position))); - } + iterator erase(const_iterator); + size_type erase(const key_type&); + iterator erase(const_iterator, const_iterator); + void quick_erase(const_iterator position) { erase(position); } + void erase_return_void(const_iterator position) { erase(position); } - size_type erase(const key_type& k) - { - return table_.erase_key(k); - } - - iterator erase(const_iterator first, const_iterator last) - { - 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)); - } - - void clear() - { - table_.clear(); - } - - void swap(unordered_multiset& other) - { - table_.swap(other.table_); - } + void clear(); + void swap(unordered_multiset&); // observers - hasher hash_function() const - { - return table_.hash_function(); - } - - key_equal key_eq() const - { - return table_.key_eq(); - } + hasher hash_function() const; + key_equal key_eq() const; // lookup - const_iterator find(const key_type& k) const - { - return const_iterator(table_.find(k)); - } + const_iterator find(const key_type&) const; 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); - } + CompatibleKey const&, + CompatibleHash const&, + CompatiblePredicate const&) const; + size_type count(const key_type&) const; std::pair - equal_range(const key_type& k) const - { - return boost::unordered_detail::pair_cast< - const_iterator, const_iterator>( - table_.equal_range(k)); - } + equal_range(const key_type&) const; // bucket interface @@ -950,24 +605,23 @@ namespace boost return table_.max_bucket_count(); } - size_type bucket_size(size_type n) const - { - return table_.bucket_size(n); - } + size_type bucket_size(size_type) const; size_type bucket(const key_type& k) const { - return table_.bucket_index(k); + return table_.hash_function()(k) % table_.bucket_count_; } local_iterator begin(size_type n) { - return local_iterator(table_.bucket_begin(n)); + return local_iterator( + table_.bucket_begin(n), n, table_.bucket_count_); } const_local_iterator begin(size_type n) const { - return const_local_iterator(table_.bucket_begin(n)); + return const_local_iterator( + table_.bucket_begin(n), n, table_.bucket_count_); } local_iterator end(size_type) @@ -982,7 +636,8 @@ namespace boost const_local_iterator cbegin(size_type n) const { - return const_local_iterator(table_.bucket_begin(n)); + return const_local_iterator( + table_.bucket_begin(n), n, table_.bucket_count_); } const_local_iterator cend(size_type) const @@ -992,37 +647,791 @@ namespace boost // hash policy - float load_factor() const - { - return table_.load_factor(); - } - float max_load_factor() const { return table_.mlf_; } - void max_load_factor(float m) - { - table_.max_load_factor(m); - } - - void rehash(size_type n) - { - table_.rehash(n); - } + float load_factor() const; + void max_load_factor(float); + void rehash(size_type); #if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582) - friend bool operator==( - unordered_multiset const&, unordered_multiset const&); - friend bool operator!=( - unordered_multiset const&, unordered_multiset const&); + friend bool operator==( + unordered_multiset const&, unordered_multiset const&); + friend bool operator!=( + unordered_multiset const&, unordered_multiset const&); #endif }; // class template unordered_multiset +//////////////////////////////////////////////////////////////////////////////// + template - inline bool operator==(unordered_multiset const& m1, - unordered_multiset const& m2) + unordered_set::unordered_set( + size_type n, const hasher &hf, const key_equal &eql, + const allocator_type &a) + : table_(n, hf, eql, a) + { + } + + template + unordered_set::unordered_set(allocator_type const& a) + : table_(::boost::unordered::detail::default_bucket_count, + hasher(), key_equal(), a) + { + } + + template + unordered_set::unordered_set( + unordered_set const& other, allocator_type const& a) + : table_(other.table_, a) + { + } + + template + template + unordered_set::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 + template + unordered_set::unordered_set( + InputIt f, InputIt l, + size_type n, + const hasher &hf, + const key_equal &eql) + : table_(::boost::unordered::detail::initial_size(f, l, n), + hf, eql, allocator_type()) + { + table_.insert_range(f, l); + } + + template + template + unordered_set::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); + } + + template + unordered_set::~unordered_set() {} + +#if !defined(BOOST_NO_RVALUE_REFERENCES) + template + unordered_set::unordered_set(unordered_set const& other) + : table_(other.table_) + { + } + + template + unordered_set::unordered_set(unordered_set&& other) + : table_(other.table_, ::boost::unordered::detail::move_tag()) + { + } + + template + unordered_set::unordered_set( + unordered_set&& other, allocator_type const& a) + : table_(other.table_, a, ::boost::unordered::detail::move_tag()) + { + } + + template + unordered_set& unordered_set:: + operator=(unordered_set const& x) + { + table_ = x.table_; + return *this; + } + + template + unordered_set& unordered_set:: + operator=(unordered_set&& x) + { + table_.move(x.table_); + return *this; + } +#else + template + unordered_set::unordered_set( + ::boost::unordered::detail::move_from > + other) + : table_(other.source.table_, ::boost::unordered::detail::move_tag()) + { + } + +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) + template + unordered_set& unordered_set:: + operator=(unordered_set x) + { + table_.move(x.table_); + return *this; + } +#endif +#endif + +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + template + unordered_set::unordered_set( + std::initializer_list list, size_type n, + const hasher &hf, const key_equal &eql, const allocator_type &a) + : table_( + ::boost::unordered::detail::initial_size( + list.begin(), list.end(), n), + hf, eql, a) + { + table_.insert_range(list.begin(), list.end()); + } + + template + unordered_set& unordered_set::operator=( + std::initializer_list list) + { + table_.clear(); + table_.insert_range(list.begin(), list.end()); + return *this; + } +#endif + + // size and capacity + + template + std::size_t unordered_set::max_size() const + { + return table_.max_size(); + } + + // modifiers + +#if defined(BOOST_UNORDERED_STD_FORWARD) + template + template + std::pair::iterator, bool> + unordered_set::emplace(Args&&... args) + { + return BOOST_UNORDERED_PAIR_CAST(iterator, bool, + table_.emplace(std::forward(args)...)); + } + + template + template + BOOST_DEDUCED_TYPENAME unordered_set::iterator + unordered_set::emplace_hint(const_iterator, Args&&... args) + { + return iterator(table_.emplace(std::forward(args)...).first); + } +#else + + template + std::pair::iterator, bool> + unordered_set::emplace(value_type const& v) + { + return BOOST_UNORDERED_PAIR_CAST(iterator, bool, table_.emplace(v)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_set::iterator + unordered_set::emplace_hint( + const_iterator, value_type const& v) + { + return iterator(table_.emplace(v).first); + } + +#define BOOST_UNORDERED_EMPLACE(z, n, _) \ + template \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + std::pair< \ + BOOST_DEDUCED_TYPENAME unordered_set::iterator, \ + bool> \ + unordered_set::emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + return \ + BOOST_UNORDERED_PAIR_CAST(iterator, bool, \ + table_.emplace( \ + BOOST_UNORDERED_CALL_PARAMS(z, n))); \ + } \ + \ + template \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + BOOST_DEDUCED_TYPENAME unordered_set::iterator \ + unordered_set::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, + BOOST_UNORDERED_EMPLACE, _) + +#undef BOOST_UNORDERED_EMPLACE + +#endif + + template + std::pair::iterator, bool> + unordered_set::insert(const value_type& obj) + { + return BOOST_UNORDERED_PAIR_CAST(iterator, bool, table_.insert(obj)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_set::iterator + unordered_set::insert(const_iterator, const value_type& obj) + { + return iterator(table_.emplace(obj).first); + } + + template + template + void unordered_set::insert(InputIt first, InputIt last) + { + table_.insert_range(first, last); + } + +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + template + void unordered_set::insert(std::initializer_list list) + { + table_.insert_range(list.begin(), list.end()); + } +#endif + + template + BOOST_DEDUCED_TYPENAME unordered_set::iterator + unordered_set::erase(const_iterator position) + { + return iterator(table_.erase(get(position))); + } + + template + BOOST_DEDUCED_TYPENAME unordered_set::size_type + unordered_set::erase(const key_type& k) + { + return table_.erase_key(k); + } + + template + BOOST_DEDUCED_TYPENAME unordered_set::iterator + unordered_set::erase(const_iterator first, const_iterator last) + { + return iterator(table_.erase_range(get(first), get(last))); + } + + template + void unordered_set::clear() + { + table_.clear(); + } + + template + void unordered_set::swap(unordered_set& other) + { + table_.swap(other.table_); + } + + // observers + + template + BOOST_DEDUCED_TYPENAME unordered_set::hasher + unordered_set::hash_function() const + { + return table_.hash_function(); + } + + template + BOOST_DEDUCED_TYPENAME unordered_set::key_equal + unordered_set::key_eq() const + { + return table_.key_eq(); + } + + // lookup + + template + BOOST_DEDUCED_TYPENAME unordered_set::const_iterator + unordered_set::find(const key_type& k) const + { + return const_iterator(table_.find_node(k)); + } + + template + template + BOOST_DEDUCED_TYPENAME unordered_set::const_iterator + unordered_set::find( + CompatibleKey const& k, + CompatibleHash const& hash, + CompatiblePredicate const& eq) const + { + return const_iterator(table_.generic_find_node(k, hash, eq)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_set::size_type + unordered_set::count(const key_type& k) const + { + return table_.count(k); + } + + template + std::pair< + BOOST_DEDUCED_TYPENAME unordered_set::const_iterator, + BOOST_DEDUCED_TYPENAME unordered_set::const_iterator> + unordered_set::equal_range(const key_type& k) const + { + return BOOST_UNORDERED_PAIR_CAST(const_iterator, const_iterator, + table_.equal_range(k)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_set::size_type + unordered_set::bucket_size(size_type n) const + { + return table_.bucket_size(n); + } + + // hash policy + + template + float unordered_set::load_factor() const + { + return table_.load_factor(); + } + + template + void unordered_set::max_load_factor(float m) + { + table_.max_load_factor(m); + } + + template + void unordered_set::rehash(size_type n) + { + table_.rehash(n); + } + + template + 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_); + } + + template + 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_); + } + + template + 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 + unordered_multiset::unordered_multiset( + size_type n, const hasher &hf, const key_equal &eql, + const allocator_type &a) + : table_(n, hf, eql, a) + { + } + + template + unordered_multiset::unordered_multiset(allocator_type const& a) + : table_(::boost::unordered::detail::default_bucket_count, + hasher(), key_equal(), a) + { + } + + template + unordered_multiset::unordered_multiset( + unordered_multiset const& other, allocator_type const& a) + : table_(other.table_, a) + { + } + + template + template + unordered_multiset::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 + template + unordered_multiset::unordered_multiset( + InputIt f, InputIt l, + size_type n, + const hasher &hf, + const key_equal &eql) + : table_(::boost::unordered::detail::initial_size(f, l, n), + hf, eql, allocator_type()) + { + table_.insert_range(f, l); + } + + template + template + unordered_multiset::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); + } + + template + unordered_multiset::~unordered_multiset() {} + +#if !defined(BOOST_NO_RVALUE_REFERENCES) + template + unordered_multiset::unordered_multiset( + unordered_multiset const& other) + : table_(other.table_) + { + } + + template + unordered_multiset::unordered_multiset( + unordered_multiset&& other) + : table_(other.table_, ::boost::unordered::detail::move_tag()) + { + } + + template + unordered_multiset::unordered_multiset( + unordered_multiset&& other, allocator_type const& a) + : table_(other.table_, a, ::boost::unordered::detail::move_tag()) + { + } + + template + unordered_multiset& unordered_multiset:: + operator=(unordered_multiset const& x) + { + table_ = x.table_; + return *this; + } + + template + unordered_multiset& unordered_multiset:: + operator=(unordered_multiset&& x) + { + table_.move(x.table_); + return *this; + } + +#else + + template + unordered_multiset::unordered_multiset( + ::boost::unordered::detail::move_from > + other) + : table_(other.source.table_, ::boost::unordered::detail::move_tag()) + { + } + +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593) + template + unordered_multiset& unordered_multiset:: + operator=(unordered_multiset x) + { + table_.move(x.table_); + return *this; + } +#endif +#endif + +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + template + unordered_multiset::unordered_multiset( + std::initializer_list list, size_type n, + const hasher &hf, const key_equal &eql, const allocator_type &a) + : table_( + ::boost::unordered::detail::initial_size( + list.begin(), list.end(), n), + hf, eql, a) + { + table_.insert_range(list.begin(), list.end()); + } + + template + unordered_multiset& unordered_multiset::operator=( + std::initializer_list list) + { + table_.clear(); + table_.insert_range(list.begin(), list.end()); + return *this; + } +#endif + + // size and capacity + + template + std::size_t unordered_multiset::max_size() const + { + return table_.max_size(); + } + + // modifiers + +#if defined(BOOST_UNORDERED_STD_FORWARD) + + template + template + BOOST_DEDUCED_TYPENAME unordered_multiset::iterator + unordered_multiset::emplace(Args&&... args) + { + return iterator(table_.emplace(std::forward(args)...)); + } + + template + template + BOOST_DEDUCED_TYPENAME unordered_multiset::iterator + unordered_multiset::emplace_hint( + const_iterator, Args&&... args) + { + return iterator(table_.emplace(std::forward(args)...)); + } + +#else + + template + BOOST_DEDUCED_TYPENAME unordered_multiset::iterator + unordered_multiset::emplace(value_type const& v) + { + return iterator(table_.emplace(v)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multiset::iterator + unordered_multiset::emplace_hint( + const_iterator, value_type const& v) + { + return iterator(table_.emplace(v)); + } + +#define BOOST_UNORDERED_EMPLACE(z, n, _) \ + template \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + BOOST_DEDUCED_TYPENAME unordered_multiset::iterator \ + unordered_multiset::emplace( \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + return iterator(table_.emplace( \ + BOOST_UNORDERED_CALL_PARAMS(z, n))); \ + } \ + \ + template \ + template < \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ + > \ + BOOST_DEDUCED_TYPENAME unordered_multiset::iterator \ + unordered_multiset::emplace_hint( \ + const_iterator, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ + { \ + return iterator(table_.emplace( \ + BOOST_UNORDERED_CALL_PARAMS(z, n))); \ + } + + BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_EMPLACE, _) + +#undef BOOST_UNORDERED_EMPLACE + +#endif + + template + BOOST_DEDUCED_TYPENAME unordered_multiset::iterator + unordered_multiset::insert(const value_type& obj) + { + return iterator(table_.emplace(obj)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multiset::iterator + unordered_multiset::insert(const_iterator, const value_type& obj) + { + return iterator(table_.emplace(obj)); + } + + template + template + void unordered_multiset::insert(InputIt first, InputIt last) + { + table_.insert_range(first, last); + } + +#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) + template + void unordered_multiset::insert(std::initializer_list list) + { + table_.insert_range(list.begin(), list.end()); + } +#endif + + template + BOOST_DEDUCED_TYPENAME unordered_multiset::iterator + unordered_multiset::erase(const_iterator position) + { + return iterator(table_.erase(get(position))); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multiset::size_type + unordered_multiset::erase(const key_type& k) + { + return table_.erase_key(k); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multiset::iterator + unordered_multiset::erase(const_iterator first, const_iterator last) + { + return iterator(table_.erase_range(get(first), get(last))); + } + + template + void unordered_multiset::clear() + { + table_.clear(); + } + + template + void unordered_multiset::swap(unordered_multiset& other) + { + table_.swap(other.table_); + } + + // observers + + template + BOOST_DEDUCED_TYPENAME unordered_multiset::hasher + unordered_multiset::hash_function() const + { + return table_.hash_function(); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multiset::key_equal + unordered_multiset::key_eq() const + { + return table_.key_eq(); + } + + // lookup + + template + BOOST_DEDUCED_TYPENAME unordered_multiset::const_iterator + unordered_multiset::find(const key_type& k) const + { + return const_iterator(table_.find_node(k)); + } + + template + template + BOOST_DEDUCED_TYPENAME unordered_multiset::const_iterator + unordered_multiset::find( + CompatibleKey const& k, + CompatibleHash const& hash, + CompatiblePredicate const& eq) const + { + return const_iterator(table_.generic_find_node(k, hash, eq)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multiset::size_type + unordered_multiset::count(const key_type& k) const + { + return table_.count(k); + } + + template + std::pair< + BOOST_DEDUCED_TYPENAME unordered_multiset::const_iterator, + BOOST_DEDUCED_TYPENAME unordered_multiset::const_iterator> + unordered_multiset::equal_range(const key_type& k) const + { + return BOOST_UNORDERED_PAIR_CAST(const_iterator, const_iterator, + table_.equal_range(k)); + } + + template + BOOST_DEDUCED_TYPENAME unordered_multiset::size_type + unordered_multiset::bucket_size(size_type n) const + { + return table_.bucket_size(n); + } + + // hash policy + + template + float unordered_multiset::load_factor() const + { + return table_.load_factor(); + } + + template + void unordered_multiset::max_load_factor(float m) + { + table_.max_load_factor(m); + } + + template + void unordered_multiset::rehash(size_type n) + { + table_.rehash(n); + } + + template + inline bool operator==( + unordered_multiset const& m1, + unordered_multiset const& m2) { #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) struct dummy { unordered_multiset x; }; @@ -1031,8 +1440,9 @@ namespace boost } template - inline bool operator!=(unordered_multiset const& m1, - unordered_multiset const& m2) + inline bool operator!=( + unordered_multiset const& m1, + unordered_multiset const& m2) { #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) struct dummy { unordered_multiset x; }; @@ -1041,8 +1451,9 @@ namespace boost } template - inline void swap(unordered_multiset &m1, - unordered_multiset &m2) + inline void swap( + unordered_multiset &m1, + unordered_multiset &m2) { #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613)) struct dummy { unordered_multiset x; }; diff --git a/test/helpers/invariants.hpp b/test/helpers/invariants.hpp index a83d76be..2acb30e2 100644 --- a/test/helpers/invariants.hpp +++ b/test/helpers/invariants.hpp @@ -65,37 +65,32 @@ namespace test std::cerr<(*lit), key); ++lit) continue; - // if(lit == lend) - // BOOST_ERROR("Unable to find element with a local_iterator"); - // unsigned int count2 = 0; - // for(; lit != lend && eq(get_key(*lit), key); ++lit) ++count2; - // if(count != count2) - // 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."); - // break; - // } - // } + // 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); + for(; lit != lend && !eq(get_key(*lit), key); ++lit) continue; + if(lit == lend) + BOOST_ERROR("Unable to find element with a local_iterator"); + unsigned int count2 = 0; + for(; lit != lend && eq(get_key(*lit), key); ++lit) ++count2; + if(count != count2) + 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."); + break; + } + } }; // Finally, check that size matches up. - if(x1.size() != size) + if(x1.size() != size) { BOOST_ERROR("x1.size() doesn't match actual size."); + std::cout<(size) / static_cast(x1.bucket_count()); using namespace std; diff --git a/test/helpers/memory.hpp b/test/helpers/memory.hpp index 84c1787b..1402cfe4 100644 --- a/test/helpers/memory.hpp +++ b/test/helpers/memory.hpp @@ -70,7 +70,7 @@ namespace test template > struct memory_tracker { typedef BOOST_DEDUCED_TYPENAME - boost::unordered_detail::rebind_wrap >::type allocator_type; From 140e8852e89b29278f52c235aa3622e1f1d2cba9 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 17 Apr 2011 00:31:35 +0000 Subject: [PATCH 197/471] Unordered: fix some gcc issues. [SVN r71346] --- include/boost/unordered/detail/buckets.hpp | 28 +++++++++---------- include/boost/unordered/detail/equivalent.hpp | 18 ++++++------ include/boost/unordered/detail/table.hpp | 14 +++++----- include/boost/unordered/detail/unique.hpp | 18 ++++++------ 4 files changed, 38 insertions(+), 40 deletions(-) diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index ffa59560..ed100dff 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -15,7 +15,7 @@ namespace boost { namespace unordered { namespace detail { // // Now the main data structure: // - // buckets buffered_functions + // buckets functions // | | // +---------------+--------------+ // | @@ -323,10 +323,10 @@ namespace boost { namespace unordered { namespace detail { template class set_hash_functions; template - class buffered_functions + class functions { friend class set_hash_functions; - buffered_functions& operator=(buffered_functions const&); + functions& operator=(functions const&); typedef ::boost::compressed_pair function_pair; typedef BOOST_DEDUCED_TYPENAME ::boost::aligned_storage< @@ -358,19 +358,19 @@ namespace boost { namespace unordered { namespace detail { public: - buffered_functions(H const& hf, P const& eq) + functions(H const& hf, P const& eq) : current_(false) { construct(current_, hf, eq); } - buffered_functions(buffered_functions const& bf) + functions(functions const& bf) : current_(false) { construct(current_, bf.current()); } - ~buffered_functions() { + ~functions() { destroy(current_); } @@ -389,22 +389,20 @@ namespace boost { namespace unordered { namespace detail { set_hash_functions(set_hash_functions const&); set_hash_functions& operator=(set_hash_functions const&); - typedef buffered_functions buffered_functions; - buffered_functions& buffered_functions_; + functions& functions_; bool tmp_functions_; public: - set_hash_functions(buffered_functions& f, H const& h, P const& p) - : buffered_functions_(f), + set_hash_functions(functions& f, H const& h, P const& p) + : 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), + set_hash_functions(functions& f, functions const& other) + : functions_(f), tmp_functions_(!f.current_) { f.construct(tmp_functions_, other.current()); @@ -412,12 +410,12 @@ namespace boost { namespace unordered { namespace detail { ~set_hash_functions() { - buffered_functions_.destroy(tmp_functions_); + functions_.destroy(tmp_functions_); } void commit() { - buffered_functions_.current_ = tmp_functions_; + functions_.current_ = tmp_functions_; tmp_functions_ = !tmp_functions_; } }; diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 9da99ba7..9cf3bb0f 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -12,7 +12,7 @@ namespace boost { namespace unordered { namespace detail { template - class equivalent_table : public T::table + class equivalent_table : public T::table_base { public: typedef BOOST_DEDUCED_TYPENAME T::hasher hasher; @@ -20,7 +20,7 @@ namespace boost { namespace unordered { namespace detail { 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::table_base table_base; typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor; typedef BOOST_DEDUCED_TYPENAME T::node node; @@ -32,17 +32,17 @@ namespace boost { namespace unordered { namespace detail { equivalent_table(std::size_t n, hasher const& hf, key_equal const& eq, value_allocator const& a) - : table(n, hf, eq, a) {} + : table_base(n, hf, eq, a) {} equivalent_table(equivalent_table const& x) - : table(x, x.node_alloc()) {} + : table_base(x, x.node_alloc()) {} equivalent_table(equivalent_table const& x, value_allocator const& a) - : table(x, a) {} + : table_base(x, a) {} equivalent_table(equivalent_table& x, move_tag m) - : table(x, m) {} + : table_base(x, m) {} equivalent_table(equivalent_table& x, value_allocator const& a, move_tag m) - : table(x, a, m) {} + : table_base(x, a, m) {} ~equivalent_table() {} // Equality @@ -237,7 +237,7 @@ namespace boost { namespace unordered { namespace detail { false> { typedef equivalent_table > impl; - typedef table > table; + typedef table > table_base; }; template @@ -248,7 +248,7 @@ namespace boost { namespace unordered { namespace detail { false> { typedef equivalent_table > impl; - typedef table > table; + typedef table > table_base; }; }}} diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 07acb148..92cc9560 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -18,7 +18,7 @@ namespace boost { namespace unordered { namespace detail { // their declaration and implementation. template - class table : public T::buckets, public T::buffered_functions + class table : public T::buckets, public T::functions { table(table const&); public: @@ -27,7 +27,7 @@ namespace boost { namespace unordered { namespace detail { 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::functions functions; typedef BOOST_DEDUCED_TYPENAME T::buckets buckets; typedef BOOST_DEDUCED_TYPENAME T::extractor extractor; typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor; @@ -182,7 +182,7 @@ namespace boost { namespace unordered { namespace detail { key_equal const& eq, node_allocator const& a) : buckets(a, next_prime(num_buckets)), - base(hf, eq), + functions(hf, eq), size_(), mlf_(1.0f), max_load_(0) @@ -191,7 +191,7 @@ namespace boost { namespace unordered { namespace detail { table(table const& x, node_allocator const& a) : buckets(a, x.min_buckets_for_size(x.size_)), - base(x), + functions(x), size_(x.size_), mlf_(x.mlf_), max_load_(0) @@ -204,7 +204,7 @@ namespace boost { namespace unordered { namespace detail { table(table& x, move_tag) : buckets(x.node_alloc(), x.bucket_count_), - base(x), + functions(x), size_(0), mlf_(1.0f), max_load_(0) @@ -214,7 +214,7 @@ namespace boost { namespace unordered { namespace detail { table(table& x, node_allocator const& a, move_tag) : buckets(a, x.bucket_count_), - base(x), + functions(x), size_(0), mlf_(x.mlf_), max_load_(0) @@ -579,7 +579,7 @@ namespace boost { namespace unordered { namespace detail { typedef ::boost::unordered::detail::node_constructor node_constructor; typedef ::boost::unordered::detail::buckets buckets; - typedef ::boost::unordered::detail::buffered_functions buffered_functions; + typedef ::boost::unordered::detail::functions functions; typedef BOOST_DEDUCED_TYPENAME buckets::node node; typedef BOOST_DEDUCED_TYPENAME buckets::bucket bucket; diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index 988e3a3a..ac280671 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -12,7 +12,7 @@ namespace boost { namespace unordered { namespace detail { template - class unique_table : public T::table + class unique_table : public T::table_base { public: typedef BOOST_DEDUCED_TYPENAME T::hasher hasher; @@ -20,7 +20,7 @@ namespace boost { namespace unordered { namespace detail { 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::table_base table_base; typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor; typedef BOOST_DEDUCED_TYPENAME T::node node; @@ -34,16 +34,16 @@ namespace boost { namespace unordered { namespace detail { unique_table(std::size_t n, hasher const& hf, key_equal const& eq, value_allocator const& a) - : table(n, hf, eq, a) {} + : table_base(n, hf, eq, a) {} unique_table(unique_table const& x) - : table(x, x.node_alloc()) {} + : table_base(x, x.node_alloc()) {} unique_table(unique_table const& x, value_allocator const& a) - : table(x, a) {} + : table_base(x, a) {} unique_table(unique_table& x, move_tag m) - : table(x, m) {} + : table_base(x, m) {} unique_table(unique_table& x, value_allocator const& a, move_tag m) - : table(x, a, m) {} + : table_base(x, a, m) {} ~unique_table() {} // equals @@ -379,7 +379,7 @@ namespace boost { namespace unordered { namespace detail { true> { typedef ::boost::unordered::detail::unique_table > impl; - typedef ::boost::unordered::detail::table > table; + typedef ::boost::unordered::detail::table > table_base; }; template @@ -390,7 +390,7 @@ namespace boost { namespace unordered { namespace detail { true> { typedef ::boost::unordered::detail::unique_table > impl; - typedef ::boost::unordered::detail::table > table; + typedef ::boost::unordered::detail::table > table_base; }; }}} From f8e2a917f9be88b94e05bfa7606aea8f8863360f Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 17 Apr 2011 14:27:08 +0000 Subject: [PATCH 198/471] Unordered: 2 phase lookup fix for clang. [SVN r71352] --- include/boost/unordered/detail/table.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 92cc9560..12e0fab1 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -396,7 +396,7 @@ namespace boost { namespace unordered { namespace detail { { node_ptr node_to_delete = n; n = n->next_; - delete_node(node_to_delete); + this->delete_node(node_to_delete); } ++end; From e8714d79b2092153495c088eee487db0a92f7e25 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 17 Apr 2011 16:23:25 +0000 Subject: [PATCH 199/471] Unordered: Implement C++0x equality. [SVN r71354] --- include/boost/unordered/detail/equivalent.hpp | 71 ++++++++++++++++--- include/boost/unordered/detail/table.hpp | 2 + include/boost/unordered/detail/unique.hpp | 4 +- test/unordered/equality_tests.cpp | 8 ++- 4 files changed, 68 insertions(+), 17 deletions(-) diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 9cf3bb0f..6731fe7d 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -55,23 +55,72 @@ namespace boost { namespace unordered { namespace detail { for(node_ptr n1 = this->buckets_[this->bucket_count_].next_; n1;) { node_ptr n2 = other.find_matching_node(n1); - if(!n2) return false; - + if (!n2) return false; node_ptr end1 = node::next_group(n1); node_ptr end2 = node::next_group(n2); - - do { - if(!extractor::compare_mapped( - node::get_value(n1), node::get_value(n2))) - return false; - n1 = n1->next_; - n2 = n2->next_; - } while(n1 != end1 && n2 != end2); - if(n1 != end1 || n2 != end2) return false; + if (!group_equals(n1, end1, n2, end2)) return false; + n1 = end1; } return true; } + + static bool group_equals(node_ptr n1, node_ptr end1, + node_ptr n2, node_ptr end2) + { + for(;;) + { + if (node::get_value(n1) != node::get_value(n2)) + break; + + n1 = n1->next_; + n2 = n2->next_; + + if (n1 == end1) return n2 == end2; + if (n2 == end2) return false; + } + + for(node_ptr n1a = n1, n2a = n2;;) + { + n1a = n1a->next_; + n2a = n2a->next_; + + if (n1a == end1) + { + if (n2a == end2) break; + else return false; + } + if (n2a == end2) return false; + } + + node_ptr start = n1; + for(;n1 != end2; n1 = n1->next_) + { + value_type const& v = node::get_value(n1); + if (find(start, n1, v)) continue; + std::size_t matches = count(n2, end2, v); + if (!matches or matches != 1 + count(n1->next_, end1, v)) + return false; + } + + return true; + } + + static bool find(node_ptr n, node_ptr end, value_type const& v) + { + for(;n != end; n = n->next_) + if (node::get_value(n) == v) + return true; + return false; + } + + static std::size_t count(node_ptr n, node_ptr end, value_type const& v) + { + std::size_t count = 0; + for(;n != end; n = n->next_) + if (node::get_value(n) == v) ++count; + return count; + } //////////////////////////////////////////////////////////////////////// // A convenience method for adding nodes. diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 12e0fab1..f4bb23f3 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -625,6 +625,7 @@ namespace boost { namespace unordered { namespace iterator_detail { typedef cl_iterator const_local_iterator; friend class cl_iterator; + node_ptr ptr_; std::size_t bucket_; std::size_t bucket_count_; @@ -683,6 +684,7 @@ namespace boost { namespace unordered { namespace iterator_detail { typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr; typedef BOOST_DEDUCED_TYPENAME buckets::node node; typedef l_iterator local_iterator; + friend class l_iterator; node_ptr ptr_; diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index ac280671..2a1224b2 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -57,9 +57,7 @@ namespace boost { namespace unordered { namespace detail { n1; n1 = n1->next_) { node_ptr n2 = other.find_matching_node(n1); - if(!BOOST_UNORDERED_BORLAND_BOOL(n2)) return false; - if(!extractor::compare_mapped( - node::get_value(n1), node::get_value(n2))) + if(!n2 || node::get_value(n1) != node::get_value(n2)) return false; } diff --git a/test/unordered/equality_tests.cpp b/test/unordered/equality_tests.cpp index 6d9541b6..bd12ba9e 100644 --- a/test/unordered/equality_tests.cpp +++ b/test/unordered/equality_tests.cpp @@ -136,15 +136,17 @@ namespace equality_tests UNORDERED_EQUALITY_MULTIMAP_TEST( ((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_EQUALITY_MULTIMAP_TEST( + ((1)(2))((1)(1)), !=, ((1)(1))((1)(3))) } 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 From b1912055a92d00a527bb0590e2809fa0e5c2f562 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 17 Apr 2011 21:27:38 +0000 Subject: [PATCH 200/471] Unordered: Fix some errors in the equality tests. [SVN r71363] --- include/boost/unordered/detail/equivalent.hpp | 6 +++--- test/unordered/compile_map.cpp | 15 ++++++++------- test/unordered/compile_set.cpp | 14 +++++++------- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 6731fe7d..018ee80d 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -98,8 +98,8 @@ namespace boost { namespace unordered { namespace detail { { value_type const& v = node::get_value(n1); if (find(start, n1, v)) continue; - std::size_t matches = count(n2, end2, v); - if (!matches or matches != 1 + count(n1->next_, end1, v)) + std::size_t matches = count_equal(n2, end2, v); + if (!matches or matches != 1 + count_equal(n1->next_, end1, v)) return false; } @@ -114,7 +114,7 @@ namespace boost { namespace unordered { namespace detail { return false; } - static std::size_t count(node_ptr n, node_ptr end, value_type const& v) + static std::size_t count_equal(node_ptr n, node_ptr end, value_type const& v) { std::size_t count = 0; for(;n != end; n = n->next_) diff --git a/test/unordered/compile_map.cpp b/test/unordered/compile_map.cpp index 79eb8425..a006c7e4 100644 --- a/test/unordered/compile_map.cpp +++ b/test/unordered/compile_map.cpp @@ -68,16 +68,17 @@ UNORDERED_AUTO_TEST(test0) } UNORDERED_AUTO_TEST(equality_tests) { - typedef std::pair value_type; boost::unordered_map int_map; boost::unordered_map< - test::minimal::assignable, test::minimal::copy_constructible_equality_comparable, - test::minimal::hash, - test::minimal::equal_to, + test::minimal::copy_constructible_equality_comparable, + test::minimal::hash, + test::minimal::equal_to, test::minimal::allocator > map; equality_test(int_map); @@ -86,10 +87,10 @@ UNORDERED_AUTO_TEST(equality_tests) { boost::unordered_multimap int_multimap; boost::unordered_multimap< - test::minimal::assignable, test::minimal::copy_constructible_equality_comparable, - test::minimal::hash, - test::minimal::equal_to, + test::minimal::copy_constructible_equality_comparable, + test::minimal::hash, + test::minimal::equal_to, test::minimal::allocator > multimap; equality_test(int_multimap); diff --git a/test/unordered/compile_set.cpp b/test/unordered/compile_set.cpp index 95df1abf..96647162 100644 --- a/test/unordered/compile_set.cpp +++ b/test/unordered/compile_set.cpp @@ -56,14 +56,14 @@ UNORDERED_AUTO_TEST(test0) } UNORDERED_AUTO_TEST(equality_tests) { - typedef test::minimal::assignable value_type; + typedef test::minimal::copy_constructible_equality_comparable value_type; boost::unordered_set int_set; boost::unordered_set< - test::minimal::assignable, - test::minimal::hash, - test::minimal::equal_to, + test::minimal::copy_constructible_equality_comparable, + test::minimal::hash, + test::minimal::equal_to, test::minimal::allocator > set; equality_test(int_set); @@ -72,9 +72,9 @@ UNORDERED_AUTO_TEST(equality_tests) { boost::unordered_multiset int_multiset; boost::unordered_multiset< - test::minimal::assignable, - test::minimal::hash, - test::minimal::equal_to, + test::minimal::copy_constructible_equality_comparable, + test::minimal::hash, + test::minimal::equal_to, test::minimal::allocator > multiset; equality_test(int_multiset); From a40422fada223eb03ef21b159ed401fb52b87709 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 29 Apr 2011 11:03:29 +0000 Subject: [PATCH 201/471] Unordered: remove use of the 'or' keyword. [SVN r71602] --- include/boost/unordered/detail/equivalent.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 018ee80d..e650bf7d 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -99,7 +99,7 @@ namespace boost { namespace unordered { namespace detail { value_type const& v = node::get_value(n1); if (find(start, n1, v)) continue; std::size_t matches = count_equal(n2, end2, v); - if (!matches or matches != 1 + count_equal(n1->next_, end1, v)) + if (!matches || matches != 1 + count_equal(n1->next_, end1, v)) return false; } From 4777eaf36773094a53a6f9d589ba39e18dbea9cd Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 4 Jun 2011 16:15:27 +0000 Subject: [PATCH 202/471] Unordered: remove some dead, bad code. [SVN r72390] --- include/boost/unordered/detail/buckets.hpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index ed100dff..2469b03a 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -431,17 +431,6 @@ namespace boost { namespace unordered { namespace detail { 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, _) \ From 20e923ba0de920d00012aea4221ab4533b90528a Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 4 Jun 2011 16:17:07 +0000 Subject: [PATCH 203/471] Unordered: Move the implementation into a namespace. Although it typically won't prevent ADL, because of boost::hash. [SVN r72391] --- .../unordered/detail/allocator_helpers.hpp | 2 +- include/boost/unordered/detail/buckets.hpp | 20 +---- include/boost/unordered/detail/equivalent.hpp | 2 +- .../boost/unordered/detail/extract_key.hpp | 2 +- include/boost/unordered/detail/fwd.hpp | 87 +++++++++++++++++++ include/boost/unordered/detail/node.hpp | 2 +- include/boost/unordered/detail/table.hpp | 13 ++- include/boost/unordered/detail/unique.hpp | 2 +- include/boost/unordered/detail/util.hpp | 2 +- include/boost/unordered/unordered_map.hpp | 26 ++---- include/boost/unordered/unordered_map_fwd.hpp | 40 +-------- include/boost/unordered/unordered_set.hpp | 25 ++---- include/boost/unordered/unordered_set_fwd.hpp | 38 +------- 13 files changed, 129 insertions(+), 132 deletions(-) create mode 100644 include/boost/unordered/detail/fwd.hpp diff --git a/include/boost/unordered/detail/allocator_helpers.hpp b/include/boost/unordered/detail/allocator_helpers.hpp index 7393df1e..417c0870 100644 --- a/include/boost/unordered/detail/allocator_helpers.hpp +++ b/include/boost/unordered/detail/allocator_helpers.hpp @@ -1,5 +1,5 @@ -// Copyright 2005-2009 Daniel James. +// Copyright 2005-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) diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index 2469b03a..7c41397d 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -1,6 +1,6 @@ // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. -// Copyright (C) 2005-2009 Daniel James +// Copyright (C) 2005-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) @@ -635,24 +635,6 @@ namespace boost { namespace unordered { namespace detail { } } } - - /////////////////////////////////////////////////////////////////// - // - // Iterators - - // iterator_access is used to access the internal iterator without - // making it publicly available. - - class iterator_access - { - public: - template - static BOOST_DEDUCED_TYPENAME Iterator::node_ptr const& - get(Iterator const& it) - { - return it.node_; - } - }; }}} #endif diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index e650bf7d..78ad2cc5 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -1,6 +1,6 @@ // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. -// Copyright (C) 2005-2009 Daniel James +// Copyright (C) 2005-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) diff --git a/include/boost/unordered/detail/extract_key.hpp b/include/boost/unordered/detail/extract_key.hpp index ad90f940..97c4f4d0 100644 --- a/include/boost/unordered/detail/extract_key.hpp +++ b/include/boost/unordered/detail/extract_key.hpp @@ -1,5 +1,5 @@ -// Copyright (C) 2005-2009 Daniel James +// Copyright (C) 2005-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) diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp new file mode 100644 index 00000000..c923ace3 --- /dev/null +++ b/include/boost/unordered/detail/fwd.hpp @@ -0,0 +1,87 @@ + +// Copyright (C) 2008-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) + +#ifndef BOOST_UNORDERED_FWD_HPP_INCLUDED +#define BOOST_UNORDERED_FWD_HPP_INCLUDED + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include +#include +#include +#include + +namespace boost +{ +namespace unordered +{ + template , + class P = std::equal_to, + class A = std::allocator > > + class unordered_map; + template + inline bool operator==(unordered_map const&, + unordered_map const&); + template + inline bool operator!=(unordered_map const&, + unordered_map const&); + template + inline void swap(unordered_map&, + unordered_map&); + + template , + class P = std::equal_to, + class A = std::allocator > > + class unordered_multimap; + template + inline bool operator==(unordered_multimap const&, + unordered_multimap const&); + template + inline bool operator!=(unordered_multimap const&, + unordered_multimap const&); + template + inline void swap(unordered_multimap&, + unordered_multimap&); + + template , + class P = std::equal_to, + class A = std::allocator > + class unordered_set; + template + inline bool operator==(unordered_set const&, + unordered_set const&); + template + inline bool operator!=(unordered_set const&, + unordered_set const&); + template + inline void swap(unordered_set &m1, + unordered_set &m2); + + template , + class P = std::equal_to, + class A = std::allocator > + class unordered_multiset; + template + inline bool operator==(unordered_multiset const&, + unordered_multiset const&); + template + inline bool operator!=(unordered_multiset const&, + unordered_multiset const&); + template + inline void swap(unordered_multiset &m1, + unordered_multiset &m2); + +} +} + +#endif diff --git a/include/boost/unordered/detail/node.hpp b/include/boost/unordered/detail/node.hpp index 1a500029..7867bbad 100644 --- a/include/boost/unordered/detail/node.hpp +++ b/include/boost/unordered/detail/node.hpp @@ -1,6 +1,6 @@ // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. -// Copyright (C) 2005-2009 Daniel James +// Copyright (C) 2005-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) diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index f4bb23f3..d728580e 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -1,6 +1,6 @@ // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. -// Copyright (C) 2005-2009 Daniel James +// Copyright (C) 2005-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) @@ -801,7 +801,16 @@ namespace boost { namespace unordered { namespace iterator_detail { typedef ::boost::unordered::iterator_detail::iterator iterator; friend class ::boost::unordered::iterator_detail::iterator; - friend class ::boost::unordered::detail::iterator_access; + + template + friend class ::boost::unordered::unordered_map; + template + friend class ::boost::unordered::unordered_multimap; + template + friend class ::boost::unordered::unordered_set; + template + friend class ::boost::unordered::unordered_multiset; + node_ptr node_; public: diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index 2a1224b2..894406cf 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-2010 Daniel James +// Copyright (C) 2005-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) diff --git a/include/boost/unordered/detail/util.hpp b/include/boost/unordered/detail/util.hpp index 801df188..fa86c65b 100644 --- a/include/boost/unordered/detail/util.hpp +++ b/include/boost/unordered/detail/util.hpp @@ -1,6 +1,6 @@ // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. -// Copyright (C) 2005-2009 Daniel James +// Copyright (C) 2005-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) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 8b9e5e6e..251ae239 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -1,6 +1,6 @@ // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. -// Copyright (C) 2005-2009 Daniel James. +// Copyright (C) 2005-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) @@ -37,6 +37,8 @@ #endif namespace boost +{ +namespace unordered { template class unordered_map @@ -93,12 +95,6 @@ namespace boost table table_; - BOOST_DEDUCED_TYPENAME types::node_ptr const& - get(const_iterator const& it) - { - return ::boost::unordered::detail::iterator_access::get(it); - } - public: // construct/destroy/copy @@ -425,12 +421,6 @@ namespace boost table table_; - BOOST_DEDUCED_TYPENAME types::node_ptr const& - get(const_iterator const& it) - { - return ::boost::unordered::detail::iterator_access::get(it); - } - public: // construct/destroy/copy @@ -957,7 +947,7 @@ namespace boost BOOST_DEDUCED_TYPENAME unordered_map::iterator unordered_map::erase(const_iterator position) { - return iterator(table_.erase(get(position))); + return iterator(table_.erase(position.node_)); } template @@ -972,7 +962,7 @@ namespace boost unordered_map::erase( const_iterator first, const_iterator last) { - return iterator(table_.erase_range(get(first), get(last))); + return iterator(table_.erase_range(first.node_, last.node_)); } template @@ -1411,7 +1401,7 @@ namespace boost BOOST_DEDUCED_TYPENAME unordered_multimap::iterator unordered_multimap::erase(const_iterator position) { - return iterator(table_.erase(get(position))); + return iterator(table_.erase(position.node_)); } template @@ -1426,7 +1416,7 @@ namespace boost unordered_multimap::erase( const_iterator first, const_iterator last) { - return iterator(table_.erase_range(get(first), get(last))); + return iterator(table_.erase_range(first.node_, last.node_)); } template @@ -1584,7 +1574,7 @@ namespace boost m1.swap(m2); } - +} // namespace unordered } // namespace boost #if defined(BOOST_MSVC) diff --git a/include/boost/unordered/unordered_map_fwd.hpp b/include/boost/unordered/unordered_map_fwd.hpp index edecc5d9..ad4693e9 100644 --- a/include/boost/unordered/unordered_map_fwd.hpp +++ b/include/boost/unordered/unordered_map_fwd.hpp @@ -1,5 +1,5 @@ -// Copyright (C) 2008-2009 Daniel James. +// Copyright (C) 2008-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) @@ -10,44 +10,12 @@ # pragma once #endif -#include -#include -#include -#include +#include namespace boost { - template , - class P = std::equal_to, - class A = std::allocator > > - class unordered_map; - template - inline bool operator==(unordered_map const&, - unordered_map const&); - template - inline bool operator!=(unordered_map const&, - unordered_map const&); - template - inline void swap(unordered_map&, - unordered_map&); - - template , - class P = std::equal_to, - class A = std::allocator > > - class unordered_multimap; - template - inline bool operator==(unordered_multimap const&, - unordered_multimap const&); - template - inline bool operator!=(unordered_multimap const&, - unordered_multimap const&); - template - inline void swap(unordered_multimap&, - unordered_multimap&); + using ::boost::unordered::unordered_map; + using ::boost::unordered::unordered_multimap; } #endif diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index fae9a000..4f4b0675 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -1,6 +1,6 @@ // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. -// Copyright (C) 2005-2009 Daniel James. +// Copyright (C) 2005-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) @@ -37,6 +37,8 @@ #endif namespace boost +{ +namespace unordered { template class unordered_set @@ -90,12 +92,6 @@ namespace boost #endif table table_; - - BOOST_DEDUCED_TYPENAME types::node_ptr const& - get(const_iterator const& it) - { - return ::boost::unordered::detail::iterator_access::get(it); - } public: @@ -402,12 +398,6 @@ namespace boost #endif table table_; - - BOOST_DEDUCED_TYPENAME types::node_ptr const& - get(const_iterator const& it) - { - return ::boost::unordered::detail::iterator_access::get(it); - } public: @@ -919,7 +909,7 @@ namespace boost BOOST_DEDUCED_TYPENAME unordered_set::iterator unordered_set::erase(const_iterator position) { - return iterator(table_.erase(get(position))); + return iterator(table_.erase(position.node_)); } template @@ -933,7 +923,7 @@ namespace boost BOOST_DEDUCED_TYPENAME unordered_set::iterator unordered_set::erase(const_iterator first, const_iterator last) { - return iterator(table_.erase_range(get(first), get(last))); + return iterator(table_.erase_range(first.node_, last.node_)); } template @@ -1318,7 +1308,7 @@ namespace boost BOOST_DEDUCED_TYPENAME unordered_multiset::iterator unordered_multiset::erase(const_iterator position) { - return iterator(table_.erase(get(position))); + return iterator(table_.erase(position.node_)); } template @@ -1332,7 +1322,7 @@ namespace boost BOOST_DEDUCED_TYPENAME unordered_multiset::iterator unordered_multiset::erase(const_iterator first, const_iterator last) { - return iterator(table_.erase_range(get(first), get(last))); + return iterator(table_.erase_range(first.node_, last.node_)); } template @@ -1461,6 +1451,7 @@ namespace boost m1.swap(m2); } +} // namespace unordered } // namespace boost #if defined(BOOST_MSVC) diff --git a/include/boost/unordered/unordered_set_fwd.hpp b/include/boost/unordered/unordered_set_fwd.hpp index fead1243..b1737cbb 100644 --- a/include/boost/unordered/unordered_set_fwd.hpp +++ b/include/boost/unordered/unordered_set_fwd.hpp @@ -1,5 +1,5 @@ -// Copyright (C) 2008-2009 Daniel James. +// Copyright (C) 2008-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) @@ -10,42 +10,12 @@ # pragma once #endif -#include -#include -#include -#include +#include namespace boost { - template , - class P = std::equal_to, - class A = std::allocator > - class unordered_set; - template - inline bool operator==(unordered_set const&, - unordered_set const&); - template - inline bool operator!=(unordered_set const&, - unordered_set const&); - template - inline void swap(unordered_set &m1, - unordered_set &m2); - - template , - class P = std::equal_to, - class A = std::allocator > - class unordered_multiset; - template - inline bool operator==(unordered_multiset const&, - unordered_multiset const&); - template - inline bool operator!=(unordered_multiset const&, - unordered_multiset const&); - template - inline void swap(unordered_multiset &m1, - unordered_multiset &m2); + using ::boost::unordered::unordered_set; + using ::boost::unordered::unordered_multiset; } #endif From 8b610a6d345de92769041bdcc186a9021ede09d6 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 9 Jun 2011 19:48:34 +0000 Subject: [PATCH 204/471] Unordered: Work around for compilers which don't support template friend members. [SVN r72523] --- include/boost/unordered/detail/table.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index d728580e..328b8d25 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -802,6 +802,7 @@ namespace boost { namespace unordered { namespace iterator_detail { iterator; friend class ::boost::unordered::iterator_detail::iterator; +#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) template friend class ::boost::unordered::unordered_map; template @@ -810,6 +811,9 @@ namespace boost { namespace unordered { namespace iterator_detail { friend class ::boost::unordered::unordered_set; template friend class ::boost::unordered::unordered_multiset; +#else + public: +#endif node_ptr node_; From ff66f79721909315222e54a661fdc08288418739 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 4 Jul 2011 21:52:17 +0000 Subject: [PATCH 205/471] Unordered: Import functions into boost namespace. [SVN r72905] --- include/boost/unordered/detail/fwd.hpp | 37 ------------------- include/boost/unordered/unordered_map_fwd.hpp | 26 +++++++++++++ include/boost/unordered/unordered_set_fwd.hpp | 26 +++++++++++++ test/unordered/compile_tests.hpp | 3 ++ 4 files changed, 55 insertions(+), 37 deletions(-) diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index c923ace3..8185e4f5 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -25,15 +25,6 @@ namespace unordered class P = std::equal_to, class A = std::allocator > > class unordered_map; - template - inline bool operator==(unordered_map const&, - unordered_map const&); - template - inline bool operator!=(unordered_map const&, - unordered_map const&); - template - inline void swap(unordered_map&, - unordered_map&); template , class A = std::allocator > > class unordered_multimap; - template - inline bool operator==(unordered_multimap const&, - unordered_multimap const&); - template - inline bool operator!=(unordered_multimap const&, - unordered_multimap const&); - template - inline void swap(unordered_multimap&, - unordered_multimap&); template , class P = std::equal_to, class A = std::allocator > class unordered_set; - template - inline bool operator==(unordered_set const&, - unordered_set const&); - template - inline bool operator!=(unordered_set const&, - unordered_set const&); - template - inline void swap(unordered_set &m1, - unordered_set &m2); template , class P = std::equal_to, class A = std::allocator > class unordered_multiset; - template - inline bool operator==(unordered_multiset const&, - unordered_multiset const&); - template - inline bool operator!=(unordered_multiset const&, - unordered_multiset const&); - template - inline void swap(unordered_multiset &m1, - unordered_multiset &m2); - } } diff --git a/include/boost/unordered/unordered_map_fwd.hpp b/include/boost/unordered/unordered_map_fwd.hpp index ad4693e9..b98537eb 100644 --- a/include/boost/unordered/unordered_map_fwd.hpp +++ b/include/boost/unordered/unordered_map_fwd.hpp @@ -14,8 +14,34 @@ namespace boost { + namespace unordered + { + template + inline bool operator==(unordered_map const&, + unordered_map const&); + template + inline bool operator!=(unordered_map const&, + unordered_map const&); + template + inline void swap(unordered_map&, + unordered_map&); + + template + inline bool operator==(unordered_multimap const&, + unordered_multimap const&); + template + inline bool operator!=(unordered_multimap const&, + unordered_multimap const&); + template + inline void swap(unordered_multimap&, + unordered_multimap&); + } + using ::boost::unordered::unordered_map; using ::boost::unordered::unordered_multimap; + using ::boost::unordered::swap; + using ::boost::unordered::operator==; + using ::boost::unordered::operator!=; } #endif diff --git a/include/boost/unordered/unordered_set_fwd.hpp b/include/boost/unordered/unordered_set_fwd.hpp index b1737cbb..1935bc5d 100644 --- a/include/boost/unordered/unordered_set_fwd.hpp +++ b/include/boost/unordered/unordered_set_fwd.hpp @@ -14,8 +14,34 @@ namespace boost { + namespace unordered + { + template + inline bool operator==(unordered_set const&, + unordered_set const&); + template + inline bool operator!=(unordered_set const&, + unordered_set const&); + template + inline void swap(unordered_set &m1, + unordered_set &m2); + + template + inline bool operator==(unordered_multiset const&, + unordered_multiset const&); + template + inline bool operator!=(unordered_multiset const&, + unordered_multiset const&); + template + inline void swap(unordered_multiset &m1, + unordered_multiset &m2); + } + using ::boost::unordered::unordered_set; using ::boost::unordered::unordered_multiset; + using ::boost::unordered::swap; + using ::boost::unordered::operator==; + using ::boost::unordered::operator!=; } #endif diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index d22a9fc0..8d06e7d1 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -129,6 +129,7 @@ void container_test(X& r, T const&) test::check_return_type::equals(a_const.cend()); a.swap(b); + boost::swap(a, b); test::check_return_type::equals_ref(r = a); test::check_return_type::equals(a.size()); test::check_return_type::equals(a.max_size()); @@ -180,6 +181,8 @@ void equality_test(X& r) test::check_return_type::equals(a == b); test::check_return_type::equals(a != b); + test::check_return_type::equals(boost::operator==(a, b)); + test::check_return_type::equals(boost::operator!=(a, b)); } template From b4e1d32e85b045aed9e05d322710b543ffbc1dce Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 4 Jul 2011 21:55:40 +0000 Subject: [PATCH 206/471] Unordered: detab. [SVN r72906] --- include/boost/unordered/unordered_map_fwd.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/unordered_map_fwd.hpp b/include/boost/unordered/unordered_map_fwd.hpp index b98537eb..4700d589 100644 --- a/include/boost/unordered/unordered_map_fwd.hpp +++ b/include/boost/unordered/unordered_map_fwd.hpp @@ -37,8 +37,8 @@ namespace boost unordered_multimap&); } - using ::boost::unordered::unordered_map; - using ::boost::unordered::unordered_multimap; + using ::boost::unordered::unordered_map; + using ::boost::unordered::unordered_multimap; using ::boost::unordered::swap; using ::boost::unordered::operator==; using ::boost::unordered::operator!=; From 910cd41c47a31a963e58ada249956090f9f03b7a Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 3 Aug 2011 08:33:37 +0000 Subject: [PATCH 207/471] Unordered: Generate ref docs using php. [SVN r73501] --- doc/ref.php | 1039 +++++++++++++++++++++++++++++++++++++++++++++++++++ doc/ref.xml | 129 ++++--- 2 files changed, 1103 insertions(+), 65 deletions(-) create mode 100644 doc/ref.php diff --git a/doc/ref.php b/doc/ref.php new file mode 100644 index 00000000..6d399f62 --- /dev/null +++ b/doc/ref.php @@ -0,0 +1,1039 @@ + + + + + +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..0ddaeed5 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)