Fixes Trac #11994: Support intrusive container key extractors that return the key by value

Change tests to return key by value.
This commit is contained in:
Ion Gaztañaga
2016-07-04 22:11:52 +02:00
parent 56e2e4345a
commit 4014562502
7 changed files with 78 additions and 160 deletions

View File

@@ -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<false>]]

View File

@@ -24,10 +24,14 @@
#include <boost/intrusive/detail/mpl.hpp>
#include <boost/intrusive/detail/ebo_functor_holder.hpp>
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<value_type>
, KeyOfValue
>::type key_of_value;
typedef typename key_of_value::type key_type;
key_nodeptr_comp(KeyTypeKeyCompare kcomp, const ValueTraits *traits)
template <class P1>
struct is_same_or_nodeptr_convertible
{
static const bool same_type = is_same<P1,const_node_ptr>::value || is_same<P1,node_ptr>::value;
static const bool value = same_type || is_convertible<P1, const_node_ptr>::value;
};
BOOST_INTRUSIVE_FORCEINLINE key_nodeptr_comp(KeyTypeKeyCompare kcomp, const ValueTraits *traits)
: base_t(kcomp), traits_(traits)
{}
template<class T>
struct is_node_ptr
{
static const bool value = is_same<T, const_node_ptr>::value || is_same<T, node_ptr>::value;
};
//pred(pnode)
template<class T1>
BOOST_INTRUSIVE_FORCEINLINE bool operator()(const T1 &t1, typename enable_if_c< is_same_or_nodeptr_convertible<T1>::value >::type* =0) const
{ return base_t::get()(key_of_value()(*traits_->to_value_ptr(t1))); }
//key_forward
template<class T>
typename enable_if<is_node_ptr<T>, const key_type &>::type key_forward(const T &node) const
{ return key_of_value()(*traits_->to_value_ptr(node)); }
template<class T>
#if defined(BOOST_MOVE_HELPERS_RETURN_SFINAE_BROKEN)
const T &key_forward (const T &key, typename disable_if<is_node_ptr<T> >::type* =0) const
#else
typename disable_if<is_node_ptr<T>, const T &>::type key_forward(const T &key) const
#endif
{ return key; }
//operator() 1 arg
template<class KeyType>
bool operator()(const KeyType &key1) const
{ return base_t::get()(this->key_forward(key1)); }
template<class KeyType>
bool operator()(const KeyType &key1)
{ return base_t::get()(this->key_forward(key1)); }
template<class T1>
BOOST_INTRUSIVE_FORCEINLINE bool operator()(const T1 &t1, typename enable_if_c< is_same_or_nodeptr_convertible<T1>::value >::type* =0)
{ return base_t::get()(key_of_value()(*traits_->to_value_ptr(t1))); }
//operator() 2 arg
template<class KeyType, class KeyType2>
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<class T1, class T2>
BOOST_INTRUSIVE_FORCEINLINE bool operator()(const T1 &t1, const T2 &t2, typename enable_if_c< is_same_or_nodeptr_convertible<T1>::value && is_same_or_nodeptr_convertible<T2>::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<class KeyType, class KeyType2>
bool operator()(const KeyType &key1, const KeyType2 &key2)
{ return base_t::get()(this->key_forward(key1), this->key_forward(key2)); }
template<class T1, class T2>
BOOST_INTRUSIVE_FORCEINLINE bool operator()(const T1 &t1, const T2 &t2, typename enable_if_c< is_same_or_nodeptr_convertible<T1>::value && is_same_or_nodeptr_convertible<T2>::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<class T1, class T2>
BOOST_INTRUSIVE_FORCEINLINE bool operator()(const T1 &t1, const T2 &t2, typename enable_if_c< is_same_or_nodeptr_convertible<T1>::value && !is_same_or_nodeptr_convertible<T2>::value >::type* =0) const
{ return base_t::get()(key_of_value()(*traits_->to_value_ptr(t1)), t2); }
template<class T1, class T2>
BOOST_INTRUSIVE_FORCEINLINE bool operator()(const T1 &t1, const T2 &t2, typename enable_if_c< is_same_or_nodeptr_convertible<T1>::value && !is_same_or_nodeptr_convertible<T2>::value >::type* =0)
{ return base_t::get()(key_of_value()(*traits_->to_value_ptr(t1)), t2); }
//pred(key, pnode)
template<class T1, class T2>
BOOST_INTRUSIVE_FORCEINLINE bool operator()(const T1 &t1, const T2 &t2, typename enable_if_c< !is_same_or_nodeptr_convertible<T1>::value && is_same_or_nodeptr_convertible<T2>::value >::type* =0) const
{ return base_t::get()(t1, key_of_value()(*traits_->to_value_ptr(t2))); }
template<class T1, class T2>
BOOST_INTRUSIVE_FORCEINLINE bool operator()(const T1 &t1, const T2 &t2, typename enable_if_c< !is_same_or_nodeptr_convertible<T1>::value && is_same_or_nodeptr_convertible<T2>::value >::type* =0)
{ return base_t::get()(t1, key_of_value()(*traits_->to_value_ptr(t2))); }
//pred(key, key)
template<class T1, class T2>
BOOST_INTRUSIVE_FORCEINLINE bool operator()(const T1 &t1, const T2 &t2, typename enable_if_c< !is_same_or_nodeptr_convertible<T1>::value && !is_same_or_nodeptr_convertible<T2>::value >::type* =0) const
{ return base_t::get()(t1, t2); }
template<class T1, class T2>
BOOST_INTRUSIVE_FORCEINLINE bool operator()(const T1 &t1, const T2 &t2, typename enable_if_c< !is_same_or_nodeptr_convertible<T1>::value && !is_same_or_nodeptr_convertible<T2>::value >::type* =0)
{ return base_t::get()(t1, t2); }
const ValueTraits *const traits_;
};

View File

@@ -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<class Key, class T, class KeyCompare, class KeyOfValue>
struct tree_value_compare
: public boost::intrusive::detail::ebo_functor_holder<KeyCompare>
@@ -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<const U, const key_type>
{};
template<class U>
const key_type & key_forward
(const U &key, typename boost::intrusive::detail::enable_if<is_key<U> >::type* = 0) const
{ return key; }
template<class U, class V>
BOOST_INTRUSIVE_FORCEINLINE bool operator()(const U &key1, const V &key2) const
{ return key_compare::operator()(KeyOfValue()(key1), KeyOfValue()(key2)); }
template<class U>
BOOST_INTRUSIVE_FORCEINLINE const key_type & key_forward
(const U &key, typename boost::intrusive::detail::disable_if<is_key<U> >::type* = 0) const
{ return KeyOfValue()(key); }
template<class KeyType, class KeyType2>
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<class KeyType, class KeyType2>
BOOST_INTRUSIVE_FORCEINLINE bool operator()(const KeyType &key1, const KeyType2 &key2)
{ return key_compare::operator()(this->key_forward(key1), this->key_forward(key2)); }
template<class U, class V>
BOOST_INTRUSIVE_FORCEINLINE bool operator()(const U &key1, const V &key2)
{ return key_compare::operator()(KeyOfValue()(key1), KeyOfValue()(key2)); }
};
} //namespace intrusive{

View File

@@ -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)

View File

@@ -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(); }
};

View File

@@ -132,18 +132,18 @@ template <class Type>
bool priority_order(const Type& t1, const Type& t2)
{
std::size_t hash1 = boost::hash<int>()((&t1)->int_value());
boost::hash_combine(hash1, &t1);
boost::hash_combine(hash1, -hash1);
std::size_t hash2 = boost::hash<int>()((&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<int>()(t1);
boost::hash_combine(hash1, &t1);
boost::hash_combine(hash1, -hash1);
std::size_t hash2 = boost::hash<int>()(t2);
boost::hash_combine(hash2, &t2);
boost::hash_combine(hash2, -hash2);
return hash1 < hash2;
}

View File

@@ -761,98 +761,3 @@ void test_unordered<ValueTraits, ContainerDefiner>
} //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<ValueTraits, DefaultHolder, Map> common_t;
template < class Option1 =void
, class Option2 =void
>
struct container
{
typedef unordered_multiset
< typename common_t::value_type
, value_traits<ValueTraits>
, constant_time_size<ConstantTimeSize>
, cache_begin<CacheBegin>
, compare_hash<CompareHash>
, incremental<Incremental>
, typename common_t::holder_opt
, typename common_t::key_of_value_opt
, Option1
, Option2
> type;
BOOST_STATIC_ASSERT((key_type_tester<typename common_t::key_of_value_opt, type>::value));
};
};
template<class VoidPointer, bool ConstantTimeSize, bool Map, bool DefaultHolder>
class test_main_template
{
public:
static void execute()
{
typedef testvalue<unordered_hooks<VoidPointer> > 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<VoidPointer> > 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<true>
>::type base_hook_t;
test::test_unordered_multiset
< base_hook_t //cache_begin, compare_hash, incremental
, rebinder<base_hook_t, ConstantTimeSize, ConstantTimeSize, !ConstantTimeSize, !!ConstantTimeSize, Map, DefaultHolder>
>::test_all(data);
//member
typedef typename detail::if_c
< ConstantTimeSize
, typename testval_traits_t::member_value_traits //optimize_multikey<true>
, typename testval_traits_t::auto_member_value_traits //store_hash<true>, optimize_multikey<true>
>::type member_hook_t;
test::test_unordered_multiset
< member_hook_t //cache_begin, compare_hash, incremental
, rebinder<member_hook_t, ConstantTimeSize, false, !ConstantTimeSize, false, !ConstantTimeSize, DefaultHolder>
>::test_all(data);
//nonmember
test::test_unordered_multiset
< typename testval_traits_t::nonhook_value_traits //cache_begin, compare_hash, incremental
, rebinder<typename testval_traits_t::nonhook_value_traits, ConstantTimeSize, false, false, false, Map, DefaultHolder>
>::test_all(data);
}
};
int main()
{
//VoidPointer x ConstantTimeSize x Map x DefaultHolder
//void pointer
test_main_template<void*, false, false, false>::execute();
test_main_template<void*, false, true, false>::execute();
test_main_template<void*, true, false, false>::execute();
test_main_template<void*, true, true, false>::execute();
//smart_ptr
test_main_template<smart_ptr<void>, false, false, false>::execute();
test_main_template<smart_ptr<void>, false, true, false>::execute();
test_main_template<smart_ptr<void>, true, false, false>::execute();
test_main_template<smart_ptr<void>, 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();
}
*/