Merge branch 'fix_voidptr_keys' of https://github.com/Lastique/intrusive into Lastique-fix_voidptr_keys

This commit is contained in:
Ion Gaztañaga
2019-01-02 02:17:16 +01:00
3 changed files with 123 additions and 20 deletions

View File

@@ -147,7 +147,7 @@ BOOST_INTRUSIVE_FORCEINLINE typename iterator_enable_if_tag<InputIt, std::input_
iterator_advance(InputIt& it, Distance n)
{
while(n--)
++it;
++it;
}
template<class InputIt, class Distance>
@@ -155,7 +155,7 @@ typename iterator_enable_if_tag<InputIt, std::forward_iterator_tag>::type
iterator_advance(InputIt& it, Distance n)
{
while(n--)
++it;
++it;
}
template<class InputIt, class Distance>
@@ -163,9 +163,9 @@ BOOST_INTRUSIVE_FORCEINLINE typename iterator_enable_if_tag<InputIt, std::bidire
iterator_advance(InputIt& it, Distance n)
{
for (; 0 < n; --n)
++it;
++it;
for (; n < 0; ++n)
--it;
--it;
}
template<class InputIt, class Distance>
@@ -181,7 +181,7 @@ BOOST_INTRUSIVE_FORCEINLINE typename iterator_enable_if_convertible_tag
iterator_advance(InputIt& it, Distance n)
{
while(n--)
++it;
++it;
}
template<class InputIt, class Distance>
@@ -190,7 +190,7 @@ BOOST_INTRUSIVE_FORCEINLINE typename iterator_enable_if_convertible_tag
iterator_advance(InputIt& it, Distance n)
{
while(n--)
++it;
++it;
}
template<class InputIt, class Distance>
@@ -199,7 +199,7 @@ BOOST_INTRUSIVE_FORCEINLINE typename iterator_enable_if_convertible_tag
iterator_advance(InputIt& it, Distance n)
{
while(n--)
++it;
++it;
}
template<class InputIt, class Distance>
@@ -208,9 +208,9 @@ BOOST_INTRUSIVE_FORCEINLINE typename iterator_enable_if_convertible_tag
iterator_advance(InputIt& it, Distance n)
{
for (; 0 < n; --n)
++it;
++it;
for (; n < 0; ++n)
--it;
--it;
}
class fake{};
@@ -233,7 +233,7 @@ typename iterator_disable_if_tag_difference_type
{
typename iterator_traits<InputIt>::difference_type off = 0;
while(first != last){
++off;
++off;
++first;
}
return off;

View File

@@ -27,7 +27,7 @@ namespace boost{
namespace intrusive{
//Needed to support smart references to value types
template <class From, class ValuePtr>
template <class From, class ValuePtr, class R = void>
struct disable_if_smartref_to
: detail::disable_if_c
< detail::is_same
@@ -39,7 +39,8 @@ struct disable_if_smartref_to
< typename pointer_rebind
< ValuePtr
, const typename boost::movelib::pointer_element<ValuePtr>::type>::type>
::reference>::value
::reference>::value,
R
>
{};
@@ -51,6 +52,10 @@ template< class ValuePtr, class KeyCompare, class KeyOfValue, class Ret = bool
struct tree_value_compare
: public boost::intrusive::detail::ebo_functor_holder<KeyCompare>
{
private:
struct sfinae_type;
public:
typedef typename
boost::movelib::pointer_element<ValuePtr>::type value_type;
typedef KeyCompare key_compare;
@@ -88,7 +93,7 @@ struct tree_value_compare
template<class U>
BOOST_INTRUSIVE_FORCEINLINE Ret operator()( const U &nonkey
, typename disable_if_smartref_to<U, ValuePtr>::type* = 0) const
, typename disable_if_smartref_to<U, ValuePtr, sfinae_type*>::type = 0) const
{ return this->key_comp()(nonkey); }
BOOST_INTRUSIVE_FORCEINLINE Ret operator()(const key_type &key1, const key_type &key2) const
@@ -105,22 +110,22 @@ struct tree_value_compare
template<class U>
BOOST_INTRUSIVE_FORCEINLINE Ret operator()( const key_type &key1, const U &nonkey2
, typename disable_if_smartref_to<U, ValuePtr>::type* = 0) const
, typename disable_if_smartref_to<U, ValuePtr, sfinae_type*>::type = 0) const
{ return this->key_comp()(key1, nonkey2); }
template<class U>
BOOST_INTRUSIVE_FORCEINLINE Ret operator()( const U &nonkey1, const key_type &key2
, typename disable_if_smartref_to<U, ValuePtr>::type* = 0) const
, typename disable_if_smartref_to<U, ValuePtr, sfinae_type*>::type = 0) const
{ return this->key_comp()(nonkey1, key2); }
template<class U>
BOOST_INTRUSIVE_FORCEINLINE Ret operator()( const value_type &value1, const U &nonvalue2
, typename disable_if_smartref_to<U, ValuePtr>::type* = 0) const
, typename disable_if_smartref_to<U, ValuePtr, sfinae_type*>::type = 0) const
{ return this->key_comp()(KeyOfValue()(value1), nonvalue2); }
template<class U>
BOOST_INTRUSIVE_FORCEINLINE Ret operator()( const U &nonvalue1, const value_type &value2
, typename disable_if_smartref_to<U, ValuePtr>::type* = 0) const
, typename disable_if_smartref_to<U, ValuePtr, sfinae_type*>::type = 0) const
{ return this->key_comp()(nonvalue1, KeyOfValue()(value2)); }
};
@@ -128,6 +133,10 @@ template<class ValuePtr, class KeyCompare, class KeyOfValue, class Ret>
struct tree_value_compare<ValuePtr, KeyCompare, KeyOfValue, Ret, true>
: public boost::intrusive::detail::ebo_functor_holder<KeyCompare>
{
private:
struct sfinae_type;
public:
typedef typename
boost::movelib::pointer_element<ValuePtr>::type value_type;
typedef KeyCompare key_compare;
@@ -163,7 +172,7 @@ struct tree_value_compare<ValuePtr, KeyCompare, KeyOfValue, Ret, true>
template<class U>
BOOST_INTRUSIVE_FORCEINLINE Ret operator()( const U &nonkey
, typename disable_if_smartref_to<U, ValuePtr>::type* = 0) const
, typename disable_if_smartref_to<U, ValuePtr, sfinae_type*>::type = 0) const
{ return this->key_comp()(nonkey); }
BOOST_INTRUSIVE_FORCEINLINE Ret operator()(const key_type &key1, const key_type &key2) const
@@ -171,12 +180,12 @@ struct tree_value_compare<ValuePtr, KeyCompare, KeyOfValue, Ret, true>
template<class U>
BOOST_INTRUSIVE_FORCEINLINE Ret operator()( const key_type &key1, const U &nonkey2
, typename disable_if_smartref_to<U, ValuePtr>::type* = 0) const
, typename disable_if_smartref_to<U, ValuePtr, sfinae_type*>::type = 0) const
{ return this->key_comp()(key1, nonkey2); }
template<class U>
BOOST_INTRUSIVE_FORCEINLINE Ret operator()(const U &nonkey1, const key_type &key2
, typename disable_if_smartref_to<U, ValuePtr>::type* = 0) const
, typename disable_if_smartref_to<U, ValuePtr, sfinae_type*>::type = 0) const
{ return this->key_comp()(nonkey1, key2); }
};

94
test/voidptr_key_test.cpp Normal file
View File

@@ -0,0 +1,94 @@
/////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Andrey Semashev 2018.
//
// 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)
//
// See http://www.boost.org/libs/intrusive for documentation.
//
/////////////////////////////////////////////////////////////////////////////
#include <boost/intrusive/options.hpp>
#include <boost/intrusive/set.hpp>
#include <boost/intrusive/set_hook.hpp>
#include <boost/config.hpp>
#include <boost/core/lightweight_test.hpp>
#include <functional> // std::less
// The test verifies that the set implementation does not use void* as auxiliary arguments for SFINAE
// in internal functions, which would make overload resolution ambiguous if user's key type is also void*.
typedef boost::intrusive::set_base_hook<
boost::intrusive::link_mode< boost::intrusive::safe_link >,
boost::intrusive::tag< struct for_set_element_lookup_by_key >,
boost::intrusive::optimize_size< true >
> set_element_hook_t;
struct set_element :
public set_element_hook_t
{
struct order_by_key
{
typedef bool result_type;
result_type operator() (set_element const& left, set_element const& right) const
{
return std::less< void* >()(left.m_key, right.m_key);
}
result_type operator() (void* left, set_element const& right) const
{
return std::less< void* >()(left, right.m_key);
}
result_type operator() (set_element const& left, void* right) const
{
return std::less< void* >()(left.m_key, right);
}
};
void* m_key;
explicit set_element(void* key) : m_key(key) {}
BOOST_DELETED_FUNCTION(set_element(set_element const&))
BOOST_DELETED_FUNCTION(set_element& operator=(set_element const&))
};
typedef boost::intrusive::set<
set_element,
boost::intrusive::base_hook< set_element_hook_t >,
boost::intrusive::compare< set_element::order_by_key >,
boost::intrusive::constant_time_size< true >
> set_t;
void test_set()
{
int v1 = 0, v2 = 1, v3 = 2;
set_element e1(&v1), e2(&v2), e3(&v3);
set_t s;
s.insert(e1);
s.insert(e2);
set_t::iterator it = s.find(e1);
BOOST_TEST(it != s.end() && &*it == &e1);
it = s.find((void*)&v2, set_element::order_by_key());
BOOST_TEST(it != s.end() && &*it == &e2);
it = s.find(e3);
BOOST_TEST(it == s.end());
it = s.find((void*)&v3, set_element::order_by_key());
BOOST_TEST(it == s.end());
s.clear();
}
int main()
{
test_set();
return boost::report_errors();
}