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)) +) }