forked from boostorg/intrusive
Fixed ABI regression introduced in Boost 1.55
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2014-2014
|
||||
//
|
||||
// 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/detail/config_begin.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <cstddef>
|
||||
|
||||
#include <boost/intrusive/list.hpp>
|
||||
#include <boost/intrusive/slist.hpp>
|
||||
#include <boost/intrusive/set.hpp>
|
||||
#include <boost/intrusive/avl_set.hpp>
|
||||
#include <boost/intrusive/bs_set.hpp>
|
||||
#include <boost/intrusive/sg_set.hpp>
|
||||
#include <boost/intrusive/splay_set.hpp>
|
||||
#include <boost/intrusive/treap_set.hpp>
|
||||
#include <boost/intrusive/unordered_set.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
using namespace boost::intrusive;
|
||||
|
||||
template<bool Value>
|
||||
struct boolean
|
||||
{
|
||||
static const bool value = Value;
|
||||
};
|
||||
|
||||
template<class A, class B>
|
||||
struct pow2_and_equal_sizes
|
||||
{
|
||||
static const std::size_t a_size = sizeof(A);
|
||||
static const std::size_t b_size = sizeof(B);
|
||||
static const bool a_b_sizes_equal = a_size == b_size;
|
||||
static const bool value = !(a_size & (a_size - 1u));
|
||||
};
|
||||
|
||||
template<class Hook>
|
||||
struct node : Hook
|
||||
{};
|
||||
|
||||
//Avoid testing for uncommon architectures
|
||||
void test_sizes(boolean<false>, std::size_t)
|
||||
{}
|
||||
|
||||
template<class C>
|
||||
void test_iterator_sizes(C &, std::size_t size)
|
||||
{
|
||||
typedef typename C::iterator iterator;
|
||||
typedef typename C::const_iterator const_iterator;
|
||||
BOOST_TEST_EQ(sizeof(iterator), size);
|
||||
BOOST_TEST_EQ(sizeof(const_iterator), size);
|
||||
}
|
||||
|
||||
//Test sizes for common 32 and 64 bit architectures
|
||||
void test_sizes(boolean<true>, std::size_t wordsize)
|
||||
{
|
||||
{ //list
|
||||
list<node< node<list_base_hook<> > > > c;
|
||||
BOOST_TEST_EQ(sizeof(c), wordsize*3);
|
||||
test_iterator_sizes(c, wordsize);
|
||||
}
|
||||
{
|
||||
list<node< node<list_base_hook<> > >, constant_time_size<false> > c;
|
||||
BOOST_TEST_EQ(sizeof(c), wordsize*2);
|
||||
test_iterator_sizes(c, wordsize);
|
||||
}
|
||||
{ //slist
|
||||
slist<node< node< slist_base_hook<> > > > c;
|
||||
BOOST_TEST_EQ(sizeof(c), wordsize*2);
|
||||
test_iterator_sizes(c, wordsize);
|
||||
}
|
||||
{
|
||||
slist<node< node< slist_base_hook<> > > , constant_time_size<false> > c;
|
||||
BOOST_TEST_EQ(sizeof(c), wordsize*1);
|
||||
test_iterator_sizes(c, wordsize);
|
||||
}
|
||||
{
|
||||
slist<node< node< slist_base_hook<> > > , cache_last<true> > c;
|
||||
BOOST_TEST_EQ(sizeof(c), wordsize*3);
|
||||
test_iterator_sizes(c, wordsize);
|
||||
}
|
||||
{ //set
|
||||
set<node< node< set_base_hook<> > > > c;
|
||||
BOOST_TEST_EQ(sizeof(c), wordsize*5);
|
||||
test_iterator_sizes(c, wordsize);
|
||||
}
|
||||
{
|
||||
set<node< node< set_base_hook<> > > , constant_time_size<false> > c;
|
||||
BOOST_TEST_EQ(sizeof(c), wordsize*4);
|
||||
test_iterator_sizes(c, wordsize);
|
||||
}
|
||||
{
|
||||
set<node< node< set_base_hook<optimize_size<true> > > > , constant_time_size<false> > c;
|
||||
BOOST_TEST_EQ(sizeof(c), wordsize*3);
|
||||
test_iterator_sizes(c, wordsize);
|
||||
}
|
||||
{ //avl
|
||||
avl_set<node< node< avl_set_base_hook<> > > > c;
|
||||
BOOST_TEST_EQ(sizeof(c), wordsize*5);
|
||||
test_iterator_sizes(c, wordsize);
|
||||
}
|
||||
{
|
||||
avl_set<node< node< avl_set_base_hook<> > > , constant_time_size<false> > c;
|
||||
BOOST_TEST_EQ(sizeof(c), wordsize*4);
|
||||
test_iterator_sizes(c, wordsize);
|
||||
}
|
||||
{
|
||||
avl_set<node< node< avl_set_base_hook<optimize_size<true> > > > , constant_time_size<false> > c;
|
||||
BOOST_TEST_EQ(sizeof(c), wordsize*3);
|
||||
test_iterator_sizes(c, wordsize);
|
||||
}
|
||||
{ //splay
|
||||
splay_set<node< node< bs_set_base_hook<> > > > c;
|
||||
BOOST_TEST_EQ(sizeof(c), wordsize*4);
|
||||
test_iterator_sizes(c, wordsize);
|
||||
}
|
||||
{
|
||||
splay_set<node< node< bs_set_base_hook<> > > , constant_time_size<false> > c;
|
||||
BOOST_TEST_EQ(sizeof(c), wordsize*3);
|
||||
test_iterator_sizes(c, wordsize);
|
||||
}
|
||||
{ //scapegoat
|
||||
sg_set<node< bs_set_base_hook<> > > c;
|
||||
BOOST_TEST_EQ(sizeof(c), (wordsize*5+sizeof(float)*2));
|
||||
test_iterator_sizes(c, wordsize);
|
||||
}
|
||||
{ //treap
|
||||
treap_set<node< bs_set_base_hook<> > > c;
|
||||
BOOST_TEST_EQ(sizeof(c), wordsize*4);
|
||||
test_iterator_sizes(c, wordsize);
|
||||
}
|
||||
{
|
||||
treap_set<node< bs_set_base_hook<> > , constant_time_size<false> > c;
|
||||
BOOST_TEST_EQ(sizeof(c), wordsize*3);
|
||||
test_iterator_sizes(c, wordsize);
|
||||
}
|
||||
{ //unordered
|
||||
typedef unordered_set<node< unordered_set_base_hook<> > > cont_type;
|
||||
cont_type::bucket_type buckets[1];
|
||||
cont_type c(cont_type::bucket_traits(buckets, 1));
|
||||
BOOST_TEST_EQ(sizeof(c), wordsize*3);
|
||||
test_iterator_sizes(c, wordsize*2);
|
||||
}
|
||||
{
|
||||
typedef unordered_set<node< unordered_set_base_hook<> > , power_2_buckets<true> > cont_type;
|
||||
cont_type::bucket_type buckets[1];
|
||||
cont_type c(cont_type::bucket_traits(buckets, 1));
|
||||
BOOST_TEST_EQ(sizeof(c), wordsize*3);
|
||||
test_iterator_sizes(c, wordsize*2);
|
||||
}
|
||||
{
|
||||
typedef unordered_set<node< unordered_set_base_hook<> >, constant_time_size<false> > cont_type;
|
||||
cont_type::bucket_type buckets[1];
|
||||
cont_type c(cont_type::bucket_traits(buckets, 1));
|
||||
BOOST_TEST_EQ(sizeof(c), wordsize*2);
|
||||
test_iterator_sizes(c, wordsize*2);
|
||||
}
|
||||
{
|
||||
typedef unordered_set<node< unordered_set_base_hook< optimize_multikey<true> > >, constant_time_size<false> > cont_type;
|
||||
cont_type::bucket_type buckets[1];
|
||||
cont_type c(cont_type::bucket_traits(buckets, 1));
|
||||
BOOST_TEST_EQ(sizeof(c), wordsize*2);
|
||||
test_iterator_sizes(c, wordsize*2);
|
||||
}
|
||||
{
|
||||
typedef unordered_set<node< unordered_set_base_hook< optimize_multikey<true> > >, incremental<true> > cont_type;
|
||||
cont_type::bucket_type buckets[1];
|
||||
cont_type c(cont_type::bucket_traits(buckets, 1));
|
||||
BOOST_TEST_EQ(sizeof(c), wordsize*4);
|
||||
test_iterator_sizes(c, wordsize*2);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_sizes(boolean< pow2_and_equal_sizes<std::size_t, void*>::value >(), sizeof(std::size_t));
|
||||
return ::boost::report_errors();
|
||||
}
|
||||
|
||||
#include <boost/intrusive/detail/config_end.hpp>
|
||||
@@ -1,241 +0,0 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2007-2013
|
||||
//
|
||||
// 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/list.hpp>
|
||||
#include <boost/intrusive/slist.hpp>
|
||||
#include <boost/intrusive/rbtree.hpp>
|
||||
#include <boost/intrusive/hashtable.hpp>
|
||||
#include <boost/intrusive/pointer_traits.hpp>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
using namespace boost::intrusive;
|
||||
|
||||
class MyClass
|
||||
{
|
||||
public:
|
||||
int int_;
|
||||
|
||||
MyClass(int i = 0)
|
||||
: int_(i)
|
||||
{}
|
||||
friend bool operator > (const MyClass &l, const MyClass &r)
|
||||
{ return l.int_ > r.int_; }
|
||||
friend bool operator == (const MyClass &l, const MyClass &r)
|
||||
{ return l.int_ == r.int_; }
|
||||
friend std::size_t hash_value(const MyClass &v)
|
||||
{ return boost::hash_value(v.int_); }
|
||||
};
|
||||
|
||||
const int NumElements = 100;
|
||||
|
||||
template<class NodeTraits>
|
||||
struct external_traits
|
||||
{
|
||||
typedef NodeTraits node_traits;
|
||||
typedef typename node_traits::node node;
|
||||
typedef typename node_traits::node_ptr node_ptr;
|
||||
typedef typename node_traits::const_node_ptr const_node_ptr;
|
||||
typedef MyClass value_type;
|
||||
typedef typename pointer_traits<node_ptr>::
|
||||
template rebind_pointer<MyClass>::type pointer;
|
||||
typedef typename pointer_traits<node_ptr>::
|
||||
template rebind_pointer
|
||||
<const MyClass>::type const_pointer;
|
||||
static const link_mode_type link_mode = normal_link;
|
||||
|
||||
external_traits(pointer values, std::size_t NumElem)
|
||||
: values_(values), node_array_(NumElem)
|
||||
{}
|
||||
|
||||
node_ptr to_node_ptr (value_type &value)
|
||||
{ return (&node_array_[0]) + (&value - values_); }
|
||||
|
||||
const_node_ptr to_node_ptr (const value_type &value) const
|
||||
{ return &node_array_[0] + (&value - values_); }
|
||||
|
||||
pointer to_value_ptr(node_ptr n)
|
||||
{ return values_ + (n - &node_array_[0]); }
|
||||
|
||||
const_pointer to_value_ptr(const_node_ptr n) const
|
||||
{ return values_ + (n - &node_array_[0]); }
|
||||
|
||||
pointer values_;
|
||||
std::vector<node> node_array_;
|
||||
};
|
||||
|
||||
template<class NodeTraits>
|
||||
struct value_traits_proxy;
|
||||
|
||||
template<class T>
|
||||
struct traits_holder
|
||||
: public T
|
||||
{};
|
||||
|
||||
typedef value_traits_proxy<list_node_traits<void*> > list_value_traits_proxy;
|
||||
typedef value_traits_proxy<slist_node_traits<void*> > slist_value_traits_proxy;
|
||||
typedef value_traits_proxy<rbtree_node_traits<void*> > rbtree_value_traits_proxy;
|
||||
typedef value_traits_proxy<traits_holder<slist_node_traits<void*> > > hash_value_traits_proxy;
|
||||
|
||||
struct uset_bucket_traits
|
||||
{
|
||||
private:
|
||||
typedef unordered_bucket<value_traits<external_traits
|
||||
<traits_holder<slist_node_traits<void*> > > > >::type bucket_type;
|
||||
|
||||
//Non-copyable
|
||||
uset_bucket_traits(const uset_bucket_traits &other);
|
||||
uset_bucket_traits & operator=(const uset_bucket_traits &other);
|
||||
|
||||
public:
|
||||
static const std::size_t NumBuckets = 100;
|
||||
|
||||
uset_bucket_traits(){}
|
||||
|
||||
bucket_type * bucket_begin() const
|
||||
{ return buckets_; }
|
||||
|
||||
std::size_t bucket_count() const
|
||||
{ return NumBuckets; }
|
||||
|
||||
mutable bucket_type buckets_[NumBuckets];
|
||||
};
|
||||
|
||||
struct bucket_traits_proxy
|
||||
{
|
||||
static const bool external_bucket_traits = true;
|
||||
typedef uset_bucket_traits bucket_traits;
|
||||
|
||||
template<class Container>
|
||||
bucket_traits &get_bucket_traits(Container &cont);
|
||||
|
||||
template<class Container>
|
||||
const bucket_traits &get_bucket_traits(const Container &cont) const;
|
||||
};
|
||||
|
||||
//Define a list that will store MyClass using the external hook
|
||||
typedef list<MyClass, value_traits<list_value_traits_proxy> > List;
|
||||
//Define a slist that will store MyClass using the external hook
|
||||
typedef slist<MyClass, value_traits<slist_value_traits_proxy> > Slist;
|
||||
//Define a rbtree that will store MyClass using the external hook
|
||||
typedef rbtree< MyClass
|
||||
, value_traits<rbtree_value_traits_proxy>
|
||||
, compare<std::greater<MyClass> > > Rbtree;
|
||||
//Define a hashtable that will store MyClass using the external hook
|
||||
|
||||
typedef hashtable< MyClass
|
||||
, value_traits<hash_value_traits_proxy>
|
||||
, bucket_traits<bucket_traits_proxy>
|
||||
> Hash;
|
||||
|
||||
template<class NodeTraits>
|
||||
struct value_traits_proxy
|
||||
{
|
||||
static const bool external_value_traits = true;
|
||||
typedef external_traits<NodeTraits> value_traits;
|
||||
|
||||
template<class Container>
|
||||
const value_traits &get_value_traits(const Container &cont) const;
|
||||
|
||||
template<class Container>
|
||||
value_traits &get_value_traits(Container &cont);
|
||||
};
|
||||
|
||||
struct ContainerHolder
|
||||
: public uset_bucket_traits
|
||||
, public List
|
||||
, public external_traits<list_node_traits<void*> >
|
||||
, public Slist
|
||||
, public external_traits<slist_node_traits<void*> >
|
||||
, public Rbtree
|
||||
, public external_traits<rbtree_node_traits<void*> >
|
||||
, public Hash
|
||||
, public external_traits<traits_holder<slist_node_traits<void*> > >
|
||||
{
|
||||
static const std::size_t NumBucket = 100;
|
||||
ContainerHolder(MyClass *values, std::size_t num_elem)
|
||||
: uset_bucket_traits()
|
||||
, List()
|
||||
, external_traits<list_node_traits<void*> >(values, num_elem)
|
||||
, Slist()
|
||||
, external_traits<slist_node_traits<void*> >(values, num_elem)
|
||||
, Rbtree()
|
||||
, external_traits<rbtree_node_traits<void*> >(values, num_elem)
|
||||
, Hash(Hash::bucket_traits())
|
||||
, external_traits<traits_holder<slist_node_traits<void*> > >(values, num_elem)
|
||||
{}
|
||||
};
|
||||
|
||||
template<class NodeTraits>
|
||||
template<class Container>
|
||||
typename value_traits_proxy<NodeTraits>::value_traits &
|
||||
value_traits_proxy<NodeTraits>::get_value_traits(Container &cont)
|
||||
{ return static_cast<value_traits&>(static_cast<ContainerHolder&>(cont)); }
|
||||
|
||||
template<class NodeTraits>
|
||||
template<class Container>
|
||||
const typename value_traits_proxy<NodeTraits>::value_traits &
|
||||
value_traits_proxy<NodeTraits>::get_value_traits(const Container &cont) const
|
||||
{ return static_cast<const value_traits&>(static_cast<const ContainerHolder&>(cont)); }
|
||||
|
||||
template<class Container>
|
||||
typename bucket_traits_proxy::bucket_traits &
|
||||
bucket_traits_proxy::get_bucket_traits(Container &cont)
|
||||
{ return static_cast<bucket_traits&>(static_cast<ContainerHolder&>(cont)); }
|
||||
|
||||
template<class Container>
|
||||
const typename bucket_traits_proxy::bucket_traits &
|
||||
bucket_traits_proxy::get_bucket_traits(const Container &cont) const
|
||||
{ return static_cast<const bucket_traits&>(static_cast<const ContainerHolder&>(cont)); }
|
||||
|
||||
int main()
|
||||
{
|
||||
MyClass values [NumElements];
|
||||
//Create several MyClass objects, each one with a different value
|
||||
for(int i = 0; i < NumElements; ++i)
|
||||
values[i].int_ = i;
|
||||
|
||||
ContainerHolder cont_holder(values, NumElements);
|
||||
List &my_list = static_cast<List &> (cont_holder);
|
||||
Slist &my_slist = static_cast<Slist &> (cont_holder);
|
||||
Rbtree &my_rbtree = static_cast<Rbtree &> (cont_holder);
|
||||
Hash &my_hash = static_cast<Hash &> (cont_holder);
|
||||
|
||||
//Now insert them in containers
|
||||
for(MyClass * it(&values[0]), *itend(&values[NumElements])
|
||||
; it != itend; ++it){
|
||||
my_list.push_front(*it);
|
||||
my_slist.push_front(*it);
|
||||
my_rbtree.insert_unique(*it);
|
||||
my_hash.insert_unique(*it);
|
||||
}
|
||||
|
||||
//Now test containers
|
||||
{
|
||||
List::const_iterator list_it (my_list.cbegin());
|
||||
Slist::const_iterator slist_it (my_slist.cbegin());
|
||||
Rbtree::const_iterator rbtree_it (my_rbtree.cbegin());
|
||||
Hash::const_iterator hash_it (my_hash.cbegin());
|
||||
MyClass *it_val(&values[NumElements] - 1), *it_rbeg_val(&values[0]-1);
|
||||
|
||||
//Test inserted objects
|
||||
for(; it_val != it_rbeg_val; --it_val, ++list_it, ++slist_it, ++rbtree_it){
|
||||
if(&*list_it != &*it_val) return 1;
|
||||
if(&*slist_it != &*it_val) return 1;
|
||||
if(&*rbtree_it != &*it_val) return 1;
|
||||
hash_it = my_hash.find(*it_val);
|
||||
if(hash_it == my_hash.cend() || &*hash_it != &*it_val)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user