forked from boostorg/intrusive
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:
@@ -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>]]
|
||||
|
||||
|
@@ -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_;
|
||||
};
|
||||
|
@@ -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{
|
||||
|
@@ -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)
|
||||
|
||||
|
@@ -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(); }
|
||||
};
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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();
|
||||
}
|
||||
*/
|
||||
|
||||
|
Reference in New Issue
Block a user