From 4014562502d7a9fb9a13b09a908e0d757e368969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 4 Jul 2016 22:11:52 +0200 Subject: [PATCH] Fixes Trac #11994: Support intrusive container key extractors that return the key by value Change tests to return key by value. --- doc/intrusive.qbk | 2 + .../intrusive/detail/key_nodeptr_comp.hpp | 87 ++++++++++------- .../intrusive/detail/tree_value_compare.hpp | 36 +++---- include/boost/intrusive/options.hpp | 8 +- test/int_holder.hpp | 2 +- test/itestvalue.hpp | 8 +- test/unordered_test.hpp | 95 ------------------- 7 files changed, 78 insertions(+), 160 deletions(-) diff --git a/doc/intrusive.qbk b/doc/intrusive.qbk index f440928..2eecd34 100644 --- a/doc/intrusive.qbk +++ b/doc/intrusive.qbk @@ -3838,6 +3838,8 @@ to be inserted in intrusive containers are allocated using `std::vector` or `std [section:release_notes_boost_1_62_00 Boost 1.62 Release] * Fixed bugs: + * [@https://svn.boost.org/trac/boost/ticket/11994 Boost Trac #11994: ['Support intrusive container key extractors that return the key by value]] + * [@https://svn.boost.org/trac/boost/ticket/12184 Boost Trac #12184: ['clang -Wdocumentation warning]] * [@https://svn.boost.org/trac/boost/ticket/12190 Boost Trac #12190: ['Intrusive List + Flat Map combination crashes]] * [@https://svn.boost.org/trac/boost/ticket/12245 Boost Trac #12245: ['bstree uses a shared static size_traits for constant_time_size]] diff --git a/include/boost/intrusive/detail/key_nodeptr_comp.hpp b/include/boost/intrusive/detail/key_nodeptr_comp.hpp index 1a5ec32..2feb5ed 100644 --- a/include/boost/intrusive/detail/key_nodeptr_comp.hpp +++ b/include/boost/intrusive/detail/key_nodeptr_comp.hpp @@ -24,10 +24,14 @@ #include #include + namespace boost { namespace intrusive { namespace detail { + +//This function object transforms a key comparison type to +//a function that can compare nodes or nodes with nodes or keys. template < class KeyTypeKeyCompare , class ValueTraits , class KeyOfValue = void @@ -46,48 +50,63 @@ struct key_nodeptr_comp , detail::identity , KeyOfValue >::type key_of_value; - typedef typename key_of_value::type key_type; - key_nodeptr_comp(KeyTypeKeyCompare kcomp, const ValueTraits *traits) + template + struct is_same_or_nodeptr_convertible + { + static const bool same_type = is_same::value || is_same::value; + static const bool value = same_type || is_convertible::value; + }; + + BOOST_INTRUSIVE_FORCEINLINE key_nodeptr_comp(KeyTypeKeyCompare kcomp, const ValueTraits *traits) : base_t(kcomp), traits_(traits) {} - template - struct is_node_ptr - { - static const bool value = is_same::value || is_same::value; - }; + //pred(pnode) + template + BOOST_INTRUSIVE_FORCEINLINE bool operator()(const T1 &t1, typename enable_if_c< is_same_or_nodeptr_convertible::value >::type* =0) const + { return base_t::get()(key_of_value()(*traits_->to_value_ptr(t1))); } - //key_forward - template - typename enable_if, const key_type &>::type key_forward(const T &node) const - { return key_of_value()(*traits_->to_value_ptr(node)); } - - template - #if defined(BOOST_MOVE_HELPERS_RETURN_SFINAE_BROKEN) - const T &key_forward (const T &key, typename disable_if >::type* =0) const - #else - typename disable_if, const T &>::type key_forward(const T &key) const - #endif - { return key; } - - //operator() 1 arg - template - bool operator()(const KeyType &key1) const - { return base_t::get()(this->key_forward(key1)); } - - template - bool operator()(const KeyType &key1) - { return base_t::get()(this->key_forward(key1)); } + template + BOOST_INTRUSIVE_FORCEINLINE bool operator()(const T1 &t1, typename enable_if_c< is_same_or_nodeptr_convertible::value >::type* =0) + { return base_t::get()(key_of_value()(*traits_->to_value_ptr(t1))); } //operator() 2 arg - template - bool operator()(const KeyType &key1, const KeyType2 &key2) const - { return base_t::get()(this->key_forward(key1), this->key_forward(key2)); } + //pred(pnode, pnode) + template + BOOST_INTRUSIVE_FORCEINLINE bool operator()(const T1 &t1, const T2 &t2, typename enable_if_c< is_same_or_nodeptr_convertible::value && is_same_or_nodeptr_convertible::value >::type* =0) const + { return base_t::get()(key_of_value()(*traits_->to_value_ptr(t1)), key_of_value()(*traits_->to_value_ptr(t2))); } - template - bool operator()(const KeyType &key1, const KeyType2 &key2) - { return base_t::get()(this->key_forward(key1), this->key_forward(key2)); } + template + BOOST_INTRUSIVE_FORCEINLINE bool operator()(const T1 &t1, const T2 &t2, typename enable_if_c< is_same_or_nodeptr_convertible::value && is_same_or_nodeptr_convertible::value >::type* =0) + { return base_t::get()(key_of_value()(*traits_->to_value_ptr(t1)), key_of_value()(*traits_->to_value_ptr(t2))); } + + //pred(pnode, key) + template + BOOST_INTRUSIVE_FORCEINLINE bool operator()(const T1 &t1, const T2 &t2, typename enable_if_c< is_same_or_nodeptr_convertible::value && !is_same_or_nodeptr_convertible::value >::type* =0) const + { return base_t::get()(key_of_value()(*traits_->to_value_ptr(t1)), t2); } + + template + BOOST_INTRUSIVE_FORCEINLINE bool operator()(const T1 &t1, const T2 &t2, typename enable_if_c< is_same_or_nodeptr_convertible::value && !is_same_or_nodeptr_convertible::value >::type* =0) + { return base_t::get()(key_of_value()(*traits_->to_value_ptr(t1)), t2); } + + //pred(key, pnode) + template + BOOST_INTRUSIVE_FORCEINLINE bool operator()(const T1 &t1, const T2 &t2, typename enable_if_c< !is_same_or_nodeptr_convertible::value && is_same_or_nodeptr_convertible::value >::type* =0) const + { return base_t::get()(t1, key_of_value()(*traits_->to_value_ptr(t2))); } + + template + BOOST_INTRUSIVE_FORCEINLINE bool operator()(const T1 &t1, const T2 &t2, typename enable_if_c< !is_same_or_nodeptr_convertible::value && is_same_or_nodeptr_convertible::value >::type* =0) + { return base_t::get()(t1, key_of_value()(*traits_->to_value_ptr(t2))); } + + //pred(key, key) + template + BOOST_INTRUSIVE_FORCEINLINE bool operator()(const T1 &t1, const T2 &t2, typename enable_if_c< !is_same_or_nodeptr_convertible::value && !is_same_or_nodeptr_convertible::value >::type* =0) const + { return base_t::get()(t1, t2); } + + template + BOOST_INTRUSIVE_FORCEINLINE bool operator()(const T1 &t1, const T2 &t2, typename enable_if_c< !is_same_or_nodeptr_convertible::value && !is_same_or_nodeptr_convertible::value >::type* =0) + { return base_t::get()(t1, t2); } const ValueTraits *const traits_; }; diff --git a/include/boost/intrusive/detail/tree_value_compare.hpp b/include/boost/intrusive/detail/tree_value_compare.hpp index 810d894..ebce307 100644 --- a/include/boost/intrusive/detail/tree_value_compare.hpp +++ b/include/boost/intrusive/detail/tree_value_compare.hpp @@ -25,6 +25,9 @@ namespace boost{ namespace intrusive{ + +//This function object takes a KeyCompare function object +//and compares values that contains keys using KeyOfValue template struct tree_value_compare : public boost::intrusive::detail::ebo_functor_holder @@ -35,23 +38,22 @@ struct tree_value_compare typedef KeyOfValue key_of_value; typedef Key key_type; - - tree_value_compare() + BOOST_INTRUSIVE_FORCEINLINE tree_value_compare() : base_t() {} - explicit tree_value_compare(const key_compare &kcomp) + BOOST_INTRUSIVE_FORCEINLINE explicit tree_value_compare(const key_compare &kcomp) : base_t(kcomp) {} - tree_value_compare (const tree_value_compare &x) + BOOST_INTRUSIVE_FORCEINLINE tree_value_compare (const tree_value_compare &x) : base_t(x.base_t::get()) {} - tree_value_compare &operator=(const tree_value_compare &x) + BOOST_INTRUSIVE_FORCEINLINE tree_value_compare &operator=(const tree_value_compare &x) { this->base_t::get() = x.base_t::get(); return *this; } - tree_value_compare &operator=(const key_compare &x) + BOOST_INTRUSIVE_FORCEINLINE tree_value_compare &operator=(const key_compare &x) { this->base_t::get() = x; return *this; } BOOST_INTRUSIVE_FORCEINLINE const key_compare &key_comp() const @@ -65,23 +67,13 @@ struct tree_value_compare : boost::intrusive::detail::is_same {}; - template - const key_type & key_forward - (const U &key, typename boost::intrusive::detail::enable_if >::type* = 0) const - { return key; } + template + BOOST_INTRUSIVE_FORCEINLINE bool operator()(const U &key1, const V &key2) const + { return key_compare::operator()(KeyOfValue()(key1), KeyOfValue()(key2)); } - template - BOOST_INTRUSIVE_FORCEINLINE const key_type & key_forward - (const U &key, typename boost::intrusive::detail::disable_if >::type* = 0) const - { return KeyOfValue()(key); } - - template - BOOST_INTRUSIVE_FORCEINLINE bool operator()(const KeyType &key1, const KeyType2 &key2) const - { return key_compare::operator()(this->key_forward(key1), this->key_forward(key2)); } - - template - BOOST_INTRUSIVE_FORCEINLINE bool operator()(const KeyType &key1, const KeyType2 &key2) - { return key_compare::operator()(this->key_forward(key1), this->key_forward(key2)); } + template + BOOST_INTRUSIVE_FORCEINLINE bool operator()(const U &key1, const V &key2) + { return key_compare::operator()(KeyOfValue()(key1), KeyOfValue()(key2)); } }; } //namespace intrusive{ diff --git a/include/boost/intrusive/options.hpp b/include/boost/intrusive/options.hpp index fdcb5cb..6523ffb 100644 --- a/include/boost/intrusive/options.hpp +++ b/include/boost/intrusive/options.hpp @@ -61,12 +61,12 @@ BOOST_INTRUSIVE_OPTION_TYPE(size_type, SizeType, SizeType, size_type) //!comparison functor for the value type BOOST_INTRUSIVE_OPTION_TYPE(compare, Compare, Compare, compare) -//!This option setter specifies the a function object +//!This option setter specifies a function object //!that specifies the type of the key of an associative //!container and an operator to obtain it from a value type. //! -//!This function object must the define a `key_type` and -//!a member with signature `const key_type & operator()(const value_type &) const` +//!This function object must the define a `type` member typedef and +//!a member with signature `type [const&] operator()(const value_type &) const` //!that will return the key from a value_type of an associative container BOOST_INTRUSIVE_OPTION_TYPE(key_of_value, KeyOfValue, KeyOfValue, key_of_value) @@ -88,7 +88,7 @@ BOOST_INTRUSIVE_OPTION_CONSTANT(floating_point, bool, Enabled, floating_point) //!functor for the value type BOOST_INTRUSIVE_OPTION_TYPE(equal, Equal, Equal, equal) -//!This option setter specifies the equality +//!This option setter specifies the priority comparison //!functor for the value type BOOST_INTRUSIVE_OPTION_TYPE(priority, Priority, Priority, priority) diff --git a/test/int_holder.hpp b/test/int_holder.hpp index 412217d..cff862e 100644 --- a/test/int_holder.hpp +++ b/test/int_holder.hpp @@ -96,7 +96,7 @@ struct int_holder_key_of_value { typedef int_holder type; - const type &operator()(const ValueType &tv) + type operator()(const ValueType &tv) { return tv.get_int_holder(); } }; diff --git a/test/itestvalue.hpp b/test/itestvalue.hpp index 2f76c4e..5344532 100644 --- a/test/itestvalue.hpp +++ b/test/itestvalue.hpp @@ -132,18 +132,18 @@ template bool priority_order(const Type& t1, const Type& t2) { std::size_t hash1 = boost::hash()((&t1)->int_value()); - boost::hash_combine(hash1, &t1); + boost::hash_combine(hash1, -hash1); std::size_t hash2 = boost::hash()((&t2)->int_value()); - boost::hash_combine(hash2, &t2); + boost::hash_combine(hash2, -hash2); return hash1 < hash2; } bool priority_order(int t1, int t2) { std::size_t hash1 = boost::hash()(t1); - boost::hash_combine(hash1, &t1); + boost::hash_combine(hash1, -hash1); std::size_t hash2 = boost::hash()(t2); - boost::hash_combine(hash2, &t2); + boost::hash_combine(hash2, -hash2); return hash1 < hash2; } diff --git a/test/unordered_test.hpp b/test/unordered_test.hpp index 246b716..fb586cd 100644 --- a/test/unordered_test.hpp +++ b/test/unordered_test.hpp @@ -761,98 +761,3 @@ void test_unordered } //namespace test{ } //namespace intrusive{ } //namespace boost{ -/* -template < class ValueTraits, bool ConstantTimeSize, bool CacheBegin, bool CompareHash, bool Incremental, bool Map, bool DefaultHolder > -struct rebinder -{ - typedef unordered_rebinder_common common_t; - - template < class Option1 =void - , class Option2 =void - > - struct container - { - typedef unordered_multiset - < typename common_t::value_type - , value_traits - , constant_time_size - , cache_begin - , compare_hash - , incremental - , typename common_t::holder_opt - , typename common_t::key_of_value_opt - , Option1 - , Option2 - > type; - BOOST_STATIC_ASSERT((key_type_tester::value)); - }; -}; - -template -class test_main_template -{ - public: - static void execute() - { - typedef testvalue > value_type; - static const int random_init[6] = { 3, 2, 4, 1, 5, 2 }; - typedef typename ValueContainer< value_type >::type value_cont_type; - value_cont_type data (6); - for (int i = 0; i < 6; ++i) - data[i].value_ = random_init[i]; - - typedef testvalue_traits< unordered_hooks > testval_traits_t; - //base - typedef typename detail::if_c - < ConstantTimeSize - , typename testval_traits_t::base_value_traits - , typename testval_traits_t::auto_base_value_traits //store_hash - >::type base_hook_t; - test::test_unordered_multiset - < base_hook_t //cache_begin, compare_hash, incremental - , rebinder - >::test_all(data); - //member - typedef typename detail::if_c - < ConstantTimeSize - , typename testval_traits_t::member_value_traits //optimize_multikey - , typename testval_traits_t::auto_member_value_traits //store_hash, optimize_multikey - >::type member_hook_t; - test::test_unordered_multiset - < member_hook_t //cache_begin, compare_hash, incremental - , rebinder - >::test_all(data); - //nonmember - test::test_unordered_multiset - < typename testval_traits_t::nonhook_value_traits //cache_begin, compare_hash, incremental - , rebinder - >::test_all(data); - } -}; - -int main() -{ - //VoidPointer x ConstantTimeSize x Map x DefaultHolder - - //void pointer - test_main_template::execute(); - test_main_template::execute(); - test_main_template::execute(); - test_main_template::execute(); - - //smart_ptr - test_main_template, false, false, false>::execute(); - test_main_template, false, true, false>::execute(); - test_main_template, true, false, false>::execute(); - test_main_template, true, true, false>::execute(); - - ////bounded_ptr (bool ConstantTimeSize, bool Map) - //test_main_template_bptr< false, false >::execute(); - //test_main_template_bptr< false, true >::execute(); - //test_main_template_bptr< true, false >::execute(); - test_main_template_bptr< true, true >::execute(); - - return boost::report_errors(); -} -*/ -