Rewritten hash semi-intrusive containers to improve compilation times and runtime performance. Added experimental "linear_buckets" option.

This commit is contained in:
Ion Gaztañaga
2022-05-04 23:36:34 +02:00
parent d376c8b453
commit 3c5c8cec3f
17 changed files with 1390 additions and 941 deletions

View File

@@ -3886,6 +3886,12 @@ to be inserted in intrusive containers are allocated using `std::vector` or `std
[section:release_notes Release Notes]
[section:release_notes_boost_1_80_00 Boost 1.80 Release]
* Semi-intrusive hash containers rewritten to reduce compilation times and improve runtime performance.
[endsect]
[section:release_notes_boost_1_79_00 Boost 1.79 Release]
* The library now compiles without warnings with GCC's -Wcast-align=strict

View File

@@ -52,37 +52,6 @@ class exception_disposer
}
};
template<class Container, class Disposer, class SizeType>
class exception_array_disposer
{
Container *cont_;
Disposer &disp_;
SizeType &constructed_;
exception_array_disposer(const exception_array_disposer&);
exception_array_disposer &operator=(const exception_array_disposer&);
public:
exception_array_disposer
(Container &cont, Disposer &disp, SizeType &constructed)
: cont_(&cont), disp_(disp), constructed_(constructed)
{}
BOOST_INTRUSIVE_FORCEINLINE void release()
{ cont_ = 0; }
~exception_array_disposer()
{
SizeType n = constructed_;
if(cont_){
while(n--){
cont_[n].clear_and_dispose(disp_);
}
}
}
};
} //namespace detail{
} //namespace intrusive{
} //namespace boost{

View File

@@ -26,7 +26,10 @@
#include <boost/intrusive/pointer_traits.hpp>
#include <boost/intrusive/detail/mpl.hpp>
#include <boost/intrusive/trivial_value_traits.hpp>
#include <boost/intrusive/slist.hpp> //make_slist
#include <boost/intrusive/detail/common_slist_algorithms.hpp>
#include <boost/intrusive/detail/iiterator.hpp>
#include <boost/intrusive/detail/slist_iterator.hpp>
#include <boost/move/detail/to_raw_pointer.hpp>
#include <cstddef>
#include <climits>
#include <boost/move/core.hpp>
@@ -35,10 +38,20 @@
namespace boost {
namespace intrusive {
template <class Slist>
struct bucket_impl : public Slist
template <class NodeTraits>
struct bucket_impl
: public NodeTraits::node
{
typedef Slist slist_type;
public:
typedef NodeTraits node_traits;
private:
typedef typename node_traits::node_ptr node_ptr;
typedef typename node_traits::const_node_ptr const_node_ptr;
typedef detail::common_slist_algorithms<NodeTraits> algo_t;
public:
BOOST_INTRUSIVE_FORCEINLINE bucket_impl()
{}
@@ -46,68 +59,22 @@ struct bucket_impl : public Slist
{}
BOOST_INTRUSIVE_FORCEINLINE ~bucket_impl()
{
//This bucket is still being used!
BOOST_INTRUSIVE_INVARIANT_ASSERT(Slist::empty());
}
{}
BOOST_INTRUSIVE_FORCEINLINE bucket_impl &operator=(const bucket_impl&)
{
//This bucket is still in use!
BOOST_INTRUSIVE_INVARIANT_ASSERT(Slist::empty());
return *this;
}
{ return *this; }
BOOST_INTRUSIVE_FORCEINLINE node_ptr get_node_ptr()
{ return pointer_traits<node_ptr>::pointer_to(*this); }
BOOST_INTRUSIVE_FORCEINLINE const_node_ptr get_node_ptr() const
{ return pointer_traits<const_node_ptr>::pointer_to(*this); }
BOOST_INTRUSIVE_FORCEINLINE node_ptr begin_ptr()
{ return node_traits::get_next(get_node_ptr()); }
};
template<class Slist>
struct bucket_traits_impl
{
private:
BOOST_COPYABLE_AND_MOVABLE(bucket_traits_impl)
public:
/// @cond
typedef typename pointer_traits
<typename Slist::pointer>::template rebind_pointer
< bucket_impl<Slist> >::type bucket_ptr;
typedef Slist slist;
typedef typename Slist::size_type size_type;
/// @endcond
BOOST_INTRUSIVE_FORCEINLINE bucket_traits_impl(bucket_ptr buckets, size_type len)
: buckets_(buckets), buckets_len_(len)
{}
BOOST_INTRUSIVE_FORCEINLINE bucket_traits_impl(const bucket_traits_impl &x)
: buckets_(x.buckets_), buckets_len_(x.buckets_len_)
{}
BOOST_INTRUSIVE_FORCEINLINE bucket_traits_impl(BOOST_RV_REF(bucket_traits_impl) x)
: buckets_(x.buckets_), buckets_len_(x.buckets_len_)
{ x.buckets_ = bucket_ptr(); x.buckets_len_ = 0; }
BOOST_INTRUSIVE_FORCEINLINE bucket_traits_impl& operator=(BOOST_RV_REF(bucket_traits_impl) x)
{
buckets_ = x.buckets_; buckets_len_ = x.buckets_len_;
x.buckets_ = bucket_ptr(); x.buckets_len_ = 0; return *this;
}
BOOST_INTRUSIVE_FORCEINLINE bucket_traits_impl& operator=(BOOST_COPY_ASSIGN_REF(bucket_traits_impl) x)
{
buckets_ = x.buckets_; buckets_len_ = x.buckets_len_; return *this;
}
BOOST_INTRUSIVE_FORCEINLINE bucket_ptr bucket_begin() const
{ return buckets_; }
BOOST_INTRUSIVE_FORCEINLINE size_type bucket_count() const BOOST_NOEXCEPT
{ return buckets_len_; }
private:
bucket_ptr buckets_;
size_type buckets_len_;
};
template <class NodeTraits>
struct hash_reduced_slist_node_traits
@@ -133,22 +100,7 @@ struct reduced_slist_node_traits
>::type type;
};
template<class NodeTraits>
struct get_slist_impl
{
typedef trivial_value_traits<NodeTraits, normal_link> trivial_traits;
//Reducing symbol length
struct type : make_slist
< typename NodeTraits::node
, boost::intrusive::value_traits<trivial_traits>
, boost::intrusive::constant_time_size<false>
, boost::intrusive::size_type<std::size_t>
>::type
{};
};
template<class BucketValueTraits, bool IsConst>
template<class BucketValueTraits, bool LinearBuckets, bool IsConst>
class hashtable_iterator
{
typedef typename BucketValueTraits::value_traits value_traits;
@@ -166,24 +118,25 @@ class hashtable_iterator
private:
typedef typename value_traits::node_traits node_traits;
typedef typename node_traits::node_ptr node_ptr;
typedef typename get_slist_impl
< typename reduced_slist_node_traits
<node_traits>::type >::type slist_impl;
typedef typename slist_impl::iterator siterator;
typedef typename slist_impl::const_iterator const_siterator;
typedef bucket_impl<slist_impl> bucket_type;
typedef typename BucketValueTraits::bucket_type bucket_type;
typedef typename bucket_type::node_traits slist_node_traits;
typedef typename slist_node_traits::node_ptr slist_node_ptr;
typedef trivial_value_traits
<slist_node_traits, normal_link> slist_value_traits;
typedef slist_iterator<slist_value_traits, false> siterator;
typedef slist_iterator<slist_value_traits, true> const_siterator;
typedef circular_slist_algorithms<slist_node_traits> slist_node_algorithms;
typedef typename pointer_traits
<pointer>::template rebind_pointer
< const BucketValueTraits >::type const_bucketvaltraits_ptr;
typedef typename slist_impl::size_type size_type;
class nat;
typedef typename
detail::if_c< IsConst
, hashtable_iterator<BucketValueTraits, false>
, hashtable_iterator<BucketValueTraits, LinearBuckets, false>
, nat>::type nonconst_iterator;
BOOST_INTRUSIVE_FORCEINLINE static node_ptr downcast_bucket(typename bucket_type::node_ptr p)
BOOST_INTRUSIVE_FORCEINLINE static node_ptr downcast_bucket(typename bucket_type::node_traits::node_ptr p)
{
return pointer_traits<node_ptr>::
pointer_to(static_cast<typename node_traits::node&>(*p));
@@ -211,8 +164,8 @@ class hashtable_iterator
BOOST_INTRUSIVE_FORCEINLINE const siterator &slist_it() const
{ return slist_it_; }
BOOST_INTRUSIVE_FORCEINLINE hashtable_iterator<BucketValueTraits, false> unconst() const
{ return hashtable_iterator<BucketValueTraits, false>(this->slist_it(), this->get_bucket_value_traits()); }
BOOST_INTRUSIVE_FORCEINLINE hashtable_iterator<BucketValueTraits, LinearBuckets, false> unconst() const
{ return hashtable_iterator<BucketValueTraits, LinearBuckets, false>(this->slist_it(), this->get_bucket_value_traits()); }
BOOST_INTRUSIVE_FORCEINLINE hashtable_iterator& operator++()
{ this->increment(); return *this; }
@@ -252,33 +205,36 @@ class hashtable_iterator
{ return traitsptr_->priv_bucket_traits(); }
private:
void increment()
{
const bucket_traits &rbuck_traits = this->priv_bucket_traits();
bucket_type* const buckets = boost::movelib::to_raw_pointer(rbuck_traits.bucket_begin());
const size_type buckets_len = rbuck_traits.bucket_count();
const std::size_t buckets_len = rbuck_traits.bucket_count();
++slist_it_;
const typename slist_impl::node_ptr n = slist_it_.pointed_node();
const siterator first_bucket_bbegin = buckets->end();
if(first_bucket_bbegin.pointed_node() <= n && n <= buckets[buckets_len-1].cend().pointed_node()){
const slist_node_ptr n = slist_it_.pointed_node();
const siterator first_bucket_bbegin(buckets->get_node_ptr());
if(first_bucket_bbegin.pointed_node() <= n && n <= buckets[buckets_len-1].get_node_ptr()){
//If one-past the node is inside the bucket then look for the next non-empty bucket
//1. get the bucket_impl from the iterator
const bucket_type &b = static_cast<const bucket_type&>
(bucket_type::slist_type::container_from_end_iterator(slist_it_));
const bucket_type &b = static_cast<const bucket_type&>(*n);
//2. Now just calculate the index b has in the bucket array
size_type n_bucket = static_cast<size_type>(&b - buckets);
std::size_t n_bucket = static_cast<std::size_t>(&b - buckets);
//3. Iterate until a non-empty bucket is found
slist_node_ptr bucket_nodeptr = buckets->get_node_ptr();
do{
if (++n_bucket >= buckets_len){ //bucket overflow, return end() iterator
slist_it_ = buckets->before_begin();
slist_it_ = first_bucket_bbegin;
return;
}
bucket_nodeptr = buckets[n_bucket].get_node_ptr();
}
while (buckets[n_bucket].empty());
slist_it_ = buckets[n_bucket].begin();
while (slist_node_algorithms::is_empty(bucket_nodeptr));
slist_it_ = siterator(bucket_nodeptr);
++slist_it_;
}
else{
//++slist_it_ yield to a valid object
@@ -289,6 +245,134 @@ class hashtable_iterator
const_bucketvaltraits_ptr traitsptr_;
};
template<class BucketValueTraits, bool IsConst>
class hashtable_iterator<BucketValueTraits, true, IsConst>
{
typedef typename BucketValueTraits::value_traits value_traits;
typedef typename BucketValueTraits::bucket_traits bucket_traits;
typedef iiterator< value_traits, IsConst
, std::forward_iterator_tag> types_t;
public:
typedef typename types_t::iterator_type::difference_type difference_type;
typedef typename types_t::iterator_type::value_type value_type;
typedef typename types_t::iterator_type::pointer pointer;
typedef typename types_t::iterator_type::reference reference;
typedef typename types_t::iterator_type::iterator_category iterator_category;
private:
typedef typename value_traits::node_traits node_traits;
typedef typename node_traits::node_ptr node_ptr;
typedef typename BucketValueTraits::bucket_type bucket_type;
typedef typename BucketValueTraits::bucket_ptr bucket_ptr;
typedef typename bucket_type::node_traits slist_node_traits;
typedef linear_slist_algorithms<slist_node_traits> slist_node_algorithms;
typedef typename slist_node_traits::node_ptr slist_node_ptr;
typedef trivial_value_traits
<slist_node_traits, normal_link> slist_value_traits;
typedef slist_iterator<slist_value_traits, false> siterator;
typedef slist_iterator<slist_value_traits, true> const_siterator;
static const bool stateful_value_traits =
detail::is_stateful_value_traits<value_traits>::value;
typedef typename pointer_traits
<pointer>::template rebind_pointer
< const value_traits >::type const_value_traits_ptr;
class nat;
typedef typename
detail::if_c< IsConst
, hashtable_iterator<BucketValueTraits, true, false>
, nat>::type nonconst_iterator;
BOOST_INTRUSIVE_FORCEINLINE static node_ptr downcast_bucket(slist_node_ptr p)
{
return pointer_traits<node_ptr>::
pointer_to(static_cast<typename node_traits::node&>(*p));
}
public:
BOOST_INTRUSIVE_FORCEINLINE hashtable_iterator ()
: slist_it_() //Value initialization to achieve "null iterators" (N3644)
, members_()
{}
BOOST_INTRUSIVE_FORCEINLINE explicit hashtable_iterator(siterator ptr, bucket_ptr bp, const_value_traits_ptr traits_ptr)
: slist_it_ (ptr)
, members_ (bp, traits_ptr)
{}
BOOST_INTRUSIVE_FORCEINLINE hashtable_iterator(const hashtable_iterator &other)
: slist_it_(other.slist_it()), members_(other.get_bucket_ptr(), other.get_value_traits())
{}
BOOST_INTRUSIVE_FORCEINLINE hashtable_iterator(const nonconst_iterator &other)
: slist_it_(other.slist_it()), members_(other.get_bucket_ptr(), other.get_value_traits())
{}
BOOST_INTRUSIVE_FORCEINLINE const siterator &slist_it() const
{ return slist_it_; }
BOOST_INTRUSIVE_FORCEINLINE hashtable_iterator<BucketValueTraits, true, false> unconst() const
{ return hashtable_iterator<BucketValueTraits, true, false>(this->slist_it(), members_.nodeptr_, members_.get_ptr()); }
BOOST_INTRUSIVE_FORCEINLINE hashtable_iterator& operator++()
{ this->increment(); return *this; }
BOOST_INTRUSIVE_FORCEINLINE hashtable_iterator &operator=(const hashtable_iterator &other)
{ slist_it_ = other.slist_it(); members_ = other.members_; return *this; }
BOOST_INTRUSIVE_FORCEINLINE hashtable_iterator operator++(int)
{
hashtable_iterator result (*this);
this->increment();
return result;
}
BOOST_INTRUSIVE_FORCEINLINE friend bool operator== (const hashtable_iterator& i, const hashtable_iterator& i2)
{ return i.slist_it_ == i2.slist_it_; }
BOOST_INTRUSIVE_FORCEINLINE friend bool operator!= (const hashtable_iterator& i, const hashtable_iterator& i2)
{ return !(i == i2); }
BOOST_INTRUSIVE_FORCEINLINE reference operator*() const
{ return *this->operator ->(); }
BOOST_INTRUSIVE_FORCEINLINE pointer operator->() const
{ return this->operator_arrow(detail::bool_<stateful_value_traits>()); }
BOOST_INTRUSIVE_FORCEINLINE const_value_traits_ptr get_value_traits() const
{ return members_.get_ptr(); }
BOOST_INTRUSIVE_FORCEINLINE bucket_ptr get_bucket_ptr() const
{ return members_.nodeptr_; }
private:
BOOST_INTRUSIVE_FORCEINLINE pointer operator_arrow(detail::false_) const
{ return value_traits::to_value_ptr(downcast_bucket(slist_it_.pointed_node())); }
BOOST_INTRUSIVE_FORCEINLINE pointer operator_arrow(detail::true_) const
{ return this->get_value_traits()->to_value_ptr(downcast_bucket(slist_it_.pointed_node())); }
void increment()
{
++slist_it_;
if (slist_it_ == siterator()){
slist_node_ptr bucket_nodeptr;
do {
++members_.nodeptr_;
bucket_nodeptr = members_.nodeptr_->get_node_ptr();
}while(slist_node_algorithms::is_empty(bucket_nodeptr));
slist_it_ = siterator(slist_node_traits::get_next(bucket_nodeptr));
}
}
siterator slist_it_;
iiterator_members<bucket_ptr, const_value_traits_ptr, stateful_value_traits> members_;
};
} //namespace intrusive {
} //namespace boost {

File diff suppressed because it is too large Load Diff

View File

@@ -570,6 +570,7 @@ template
, class O8 = void
, class O9 = void
, class O10 = void
, class O11 = void
>
#else
template<class T, class ...Options>
@@ -589,6 +590,7 @@ template
, class O8 = void
, class O9 = void
, class O10 = void
, class O11 = void
>
#else
template<class T, class ...Options>

View File

@@ -241,6 +241,11 @@ BOOST_INTRUSIVE_OPTION_CONSTANT(compare_hash, bool, Enabled, compare_hash)
//!(rehashing the whole bucket array) is not admisible.
BOOST_INTRUSIVE_OPTION_CONSTANT(incremental, bool, Enabled, incremental)
//!This option setter specifies if the buckets (which form a singly linked lists of nodes)
//!are linear (true) or circular (false, default value). Linear buckets can improve performance
//!in some cases, but the container loses some features like obtaining an iterator from a value.
BOOST_INTRUSIVE_OPTION_CONSTANT(linear_buckets, bool, Enabled, linear_buckets)
/// @cond
struct hook_defaults

View File

@@ -28,8 +28,13 @@ namespace intrusive {
/// @cond
template<class U>
void priority_order();
namespace adldft {
template<class T, class U>
BOOST_INTRUSIVE_FORCEINLINE bool priority_order(const T &t, const U &u)
{ return t < u; }
} //namespace adldft {
/// @endcond
@@ -43,6 +48,7 @@ struct priority_compare
BOOST_INTRUSIVE_FORCEINLINE bool operator()(const T &val, const T &val2) const
{
using adldft::priority_order;
return priority_order(val, val2);
}
};
@@ -53,6 +59,7 @@ struct priority_compare<void>
template<class T, class U>
BOOST_INTRUSIVE_FORCEINLINE bool operator()(const T &t, const U &u) const
{
using adldft::priority_order;
return priority_order(t, u);
}
};

View File

@@ -67,7 +67,9 @@ template<class T, class ...Options>
template<class ValueTraits, class VoidOrKeyOfValue, class VoidOrKeyHash, class VoidOrKeyEqual, class SizeType, class BucketTraits, std::size_t BoolFlags>
#endif
class unordered_set_impl
#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
: public hashtable_impl<ValueTraits, VoidOrKeyOfValue, VoidOrKeyHash, VoidOrKeyEqual, BucketTraits, SizeType, BoolFlags|hash_bool_flags::unique_keys_pos>
#endif
{
/// @cond
private:
@@ -115,7 +117,6 @@ class unordered_set_impl
typedef typename implementation_defined::node node;
typedef typename implementation_defined::node_ptr node_ptr;
typedef typename implementation_defined::const_node_ptr const_node_ptr;
typedef typename implementation_defined::node_algorithms node_algorithms;
public:
@@ -420,6 +421,7 @@ template<class T, class O1 = void, class O2 = void
, class O5 = void, class O6 = void
, class O7 = void, class O8 = void
, class O9 = void, class O10= void
, class O11 = void
>
#endif
struct make_unordered_set
@@ -428,7 +430,7 @@ struct make_unordered_set
typedef typename pack_options
< hashtable_defaults,
#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
O1, O2, O3, O4, O5, O6, O7, O8, O9, O10
O1, O2, O3, O4, O5, O6, O7, O8, O9, O10, O11
#else
Options...
#endif
@@ -438,7 +440,7 @@ struct make_unordered_set
<T, typename packed_options::proto_value_traits>::type value_traits;
typedef typename make_bucket_traits
<T, true, packed_options>::type bucket_traits;
<T, packed_options>::type bucket_traits;
typedef unordered_set_impl
< value_traits
@@ -453,6 +455,7 @@ struct make_unordered_set
| (std::size_t(packed_options::cache_begin)*hash_bool_flags::cache_begin_pos)
| (std::size_t(packed_options::compare_hash)*hash_bool_flags::compare_hash_pos)
| (std::size_t(packed_options::incremental)*hash_bool_flags::incremental_pos)
| (std::size_t(packed_options::linear_buckets)*hash_bool_flags::linear_buckets_pos)
> implementation_defined;
/// @endcond
@@ -462,27 +465,26 @@ struct make_unordered_set
#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
template<class T, class O1, class O2, class O3, class O4, class O5, class O6, class O7, class O8, class O9, class O10>
template<class T, class O1, class O2, class O3, class O4, class O5, class O6, class O7, class O8, class O9, class O10, class O11>
#else
template<class T, class ...Options>
#endif
class unordered_set
: public make_unordered_set<T,
#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
O1, O2, O3, O4, O5, O6, O7, O8, O9, O10
O1, O2, O3, O4, O5, O6, O7, O8, O9, O10, O11
#else
Options...
#endif
>::type
{
typedef typename make_unordered_set
<T,
typedef typename make_unordered_set<T,
#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
O1, O2, O3, O4, O5, O6, O7, O8, O9, O10
O1, O2, O3, O4, O5, O6, O7, O8, O9, O10, O11
#else
Options...
#endif
>::type Base;
>::type Base;
//Assert if passed value traits are compatible with the type
BOOST_STATIC_ASSERT((detail::is_same<typename Base::value_traits::value_type, T>::value));
@@ -526,11 +528,11 @@ class unordered_set
template <class Cloner, class Disposer>
BOOST_INTRUSIVE_FORCEINLINE void clone_from(const unordered_set &src, Cloner cloner, Disposer disposer)
{ Base::clone_from(src, cloner, disposer); }
{ this->Base::clone_from(src, cloner, disposer); }
template <class Cloner, class Disposer>
BOOST_INTRUSIVE_FORCEINLINE void clone_from(BOOST_RV_REF(unordered_set) src, Cloner cloner, Disposer disposer)
{ Base::clone_from(BOOST_MOVE_BASE(Base, src), cloner, disposer); }
{ this->Base::clone_from(BOOST_MOVE_BASE(Base, src), cloner, disposer); }
};
#endif
@@ -577,7 +579,9 @@ template<class T, class ...Options>
template<class ValueTraits, class VoidOrKeyOfValue, class VoidOrKeyHash, class VoidOrKeyEqual, class SizeType, class BucketTraits, std::size_t BoolFlags>
#endif
class unordered_multiset_impl
#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
: public hashtable_impl<ValueTraits, VoidOrKeyOfValue, VoidOrKeyHash, VoidOrKeyEqual, BucketTraits, SizeType, BoolFlags>
#endif
{
/// @cond
private:
@@ -613,7 +617,6 @@ class unordered_multiset_impl
typedef typename implementation_defined::node node;
typedef typename implementation_defined::node_ptr node_ptr;
typedef typename implementation_defined::const_node_ptr const_node_ptr;
typedef typename implementation_defined::node_algorithms node_algorithms;
public:
@@ -872,6 +875,7 @@ template<class T, class O1 = void, class O2 = void
, class O5 = void, class O6 = void
, class O7 = void, class O8 = void
, class O9 = void, class O10= void
, class O11 = void
>
#endif
struct make_unordered_multiset
@@ -880,7 +884,7 @@ struct make_unordered_multiset
typedef typename pack_options
< hashtable_defaults,
#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
O1, O2, O3, O4, O5, O6, O7, O8, O9, O10
O1, O2, O3, O4, O5, O6, O7, O8, O9, O10, O11
#else
Options...
#endif
@@ -890,7 +894,7 @@ struct make_unordered_multiset
<T, typename packed_options::proto_value_traits>::type value_traits;
typedef typename make_bucket_traits
<T, true, packed_options>::type bucket_traits;
<T, packed_options>::type bucket_traits;
typedef unordered_multiset_impl
< value_traits
@@ -905,6 +909,7 @@ struct make_unordered_multiset
| (std::size_t(packed_options::cache_begin)*hash_bool_flags::cache_begin_pos)
| (std::size_t(packed_options::compare_hash)*hash_bool_flags::compare_hash_pos)
| (std::size_t(packed_options::incremental)*hash_bool_flags::incremental_pos)
| (std::size_t(packed_options::linear_buckets)*hash_bool_flags::linear_buckets_pos)
> implementation_defined;
/// @endcond
@@ -914,14 +919,14 @@ struct make_unordered_multiset
#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
template<class T, class O1, class O2, class O3, class O4, class O5, class O6, class O7, class O8, class O9, class O10>
template<class T, class O1, class O2, class O3, class O4, class O5, class O6, class O7, class O8, class O9, class O10, class O11>
#else
template<class T, class ...Options>
#endif
class unordered_multiset
: public make_unordered_multiset<T,
#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
O1, O2, O3, O4, O5, O6, O7, O8, O9, O10
O1, O2, O3, O4, O5, O6, O7, O8, O9, O10, O11
#else
Options...
#endif
@@ -977,11 +982,11 @@ class unordered_multiset
template <class Cloner, class Disposer>
BOOST_INTRUSIVE_FORCEINLINE void clone_from(const unordered_multiset &src, Cloner cloner, Disposer disposer)
{ Base::clone_from(src, cloner, disposer); }
{ this->Base::clone_from(src, cloner, disposer); }
template <class Cloner, class Disposer>
BOOST_INTRUSIVE_FORCEINLINE void clone_from(BOOST_RV_REF(unordered_multiset) src, Cloner cloner, Disposer disposer)
{ Base::clone_from(BOOST_MOVE_BASE(Base, src), cloner, disposer); }
{ this->Base::clone_from(BOOST_MOVE_BASE(Base, src), cloner, disposer); }
};
#endif

View File

@@ -108,10 +108,10 @@ struct unordered_group_adapter
typedef typename NodeTraits::node_ptr node_ptr;
typedef typename NodeTraits::const_node_ptr const_node_ptr;
static node_ptr get_next(const_node_ptr n)
BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_next(const_node_ptr n)
{ return NodeTraits::get_prev_in_group(n); }
static void set_next(node_ptr n, node_ptr next)
BOOST_INTRUSIVE_FORCEINLINE static void set_next(node_ptr n, node_ptr next)
{ NodeTraits::set_prev_in_group(n, next); }
};

View File

@@ -22,8 +22,6 @@
#include <boost/intrusive/link_mode.hpp>
namespace boost {
namespace intrusive {
struct BPtr_Value
{
@@ -210,6 +208,8 @@ struct ValueContainer< BPtr_Value >
typedef bounded_reference_cont< BPtr_Value > type;
};
namespace boost {
namespace intrusive {
namespace test{
template <>

View File

@@ -14,9 +14,6 @@
#include <boost/functional/hash/hash.hpp>
namespace boost{
namespace intrusive{
struct int_holder
{
explicit int_holder(int value = 0)
@@ -111,7 +108,4 @@ struct int_priority_of_value
{ return tv.int_value(); }
};
} //namespace boost{
} //namespace intrusive{
#endif //BOOST_INTRUSIVE_DETAIL_INT_HOLDER_HPP

View File

@@ -22,9 +22,6 @@
#include <boost/intrusive/detail/get_value_traits.hpp>
#include <boost/container/vector.hpp>
namespace boost{
namespace intrusive{
struct testvalue_filler
{
void *dummy_[3];
@@ -134,35 +131,48 @@ struct testvalue
boost::hash<int> hasher;
return hasher((&t)->int_value());
}
/*
static std::size_t priority_hash(const testvalue &t)
{ return boost::hash<int>()((&t)->int_value()); }
static std::size_t priority_hash(int i)
{ return boost::hash<int>()(i); }
template <class T, class U>
static bool priority_order_impl(const T& t1, const U& t2)
{
std::size_t hash1 = (priority_hash)(t1);
boost::hash_combine(hash1, -hash1);
std::size_t hash2 = (priority_hash)(t2);
boost::hash_combine(hash2, -hash2);
return hash1 < hash2;
}
friend bool priority_order(const testvalue &t1, int t2)
{ return (priority_order_impl)(t1, t2); }
friend bool priority_order(int t1, const testvalue &t2)
{ return (priority_order_impl)(t1, t2); }
*/
template < typename Node_Algorithms >
friend void swap_nodes(testvalue& lhs, testvalue& rhs)
{ lhs.swap_nodes(rhs); }
friend std::ostream& operator<<
(std::ostream& s, const testvalue& t)
{ return s << t.value_.int_value(); }
};
template<class T>
std::size_t priority_hash(const T &t)
{ return boost::hash<int>()((&t)->int_value()); }
std::size_t priority_hash(int i)
{ return boost::hash<int>()(i); }
template <class T, class U>
bool priority_order(const T& t1, const U& t2)
/*
bool priority_order(int t1, int t2)
{
std::size_t hash1 = (priority_hash)(t1);
boost::hash_combine(hash1, -hash1);
std::size_t hash2 = (priority_hash)(t2);
boost::hash_combine(hash2, -hash2);
std::size_t hash1 = boost::hash<int>()(t1);
boost::hash_combine(hash1, &t1);
std::size_t hash2 = boost::hash<int>()(t2);
boost::hash_combine(hash2, &t2);
return hash1 < hash2;
}
template < typename Node_Algorithms, class Hooks>
void swap_nodes(testvalue<Hooks>& lhs, testvalue<Hooks>& rhs)
{
lhs.swap_nodes(rhs);
}
template<class Hooks>
std::ostream& operator<<
(std::ostream& s, const testvalue<Hooks>& t)
{ return s << t.value_.int_value(); }
*/
struct even_odd
{
@@ -206,13 +216,14 @@ struct ValueContainer< testvalue<Hooks> >
template < typename Pointer >
class heap_node_holder
{
typedef typename pointer_traits<Pointer>::element_type element_type;
typedef boost::intrusive::pointer_traits<Pointer> ptrtraits_t;
typedef typename ptrtraits_t::element_type element_type;
typedef Pointer pointer;
typedef typename pointer_rebind<pointer, const element_type>::type const_pointer;
typedef typename boost::intrusive::pointer_rebind<pointer, const element_type>::type const_pointer;
public:
heap_node_holder()
: m_ptr(pointer_traits<Pointer>::pointer_to(*new element_type))
: m_ptr(ptrtraits_t::pointer_to(*new element_type))
{}
~heap_node_holder()
@@ -235,50 +246,38 @@ struct testvalue_traits
typedef testvalue< Hooks > value_type;
//base
typedef typename detail::get_base_value_traits
typedef typename boost::intrusive::detail::get_base_value_traits
< value_type
, typename Hooks::base_hook_type
>::type base_value_traits;
//auto-base
typedef typename detail::get_base_value_traits
typedef typename boost::intrusive::detail::get_base_value_traits
< value_type
, typename Hooks::auto_base_hook_type
>::type auto_base_value_traits;
//member
typedef typename detail::get_member_value_traits
< member_hook
typedef typename boost::intrusive::detail::get_member_value_traits
< boost::intrusive::member_hook
< value_type
, typename Hooks::member_hook_type
, &value_type::node_
>
>::type member_value_traits;
//auto-member
typedef typename detail::get_member_value_traits
< member_hook
typedef typename boost::intrusive::detail::get_member_value_traits
< boost::intrusive::member_hook
< value_type
, typename Hooks::auto_member_hook_type
, &value_type::auto_node_
>
>::type auto_member_value_traits;
//nonmember
typedef nonhook_node_member_value_traits
typedef boost::intrusive::nonhook_node_member_value_traits
< value_type
, typename Hooks::nonhook_node_member_type
, &value_type::nhn_member_
, safe_link
, boost::intrusive::safe_link
> nonhook_value_traits;
};
} //namespace intrusive{
} //namespace boost{
bool priority_order(int t1, int t2)
{
std::size_t hash1 = boost::hash<int>()(t1);
boost::hash_combine(hash1, &t1);
std::size_t hash2 = boost::hash<int>()(t2);
boost::hash_combine(hash2, &t2);
return hash1 < hash2;
}
#endif

View File

@@ -113,8 +113,8 @@ int main()
Slist my_slist(slist_traits(values, slist_hook_array));
Set my_set (std::less<MyClass>(), rbtree_traits(values, rbtree_hook_array));
Uset my_uset ( Uset::bucket_traits(buckets, NumElements)
, boost::hash<MyClass>()
, std::equal_to<MyClass>()
, Uset::hasher()
, Uset::key_equal()
, slist_traits(values, uset_hook_array)
);

View File

@@ -240,12 +240,15 @@ void test_common_unordered_and_associative_container(Container & c, Data & d, bo
//
//Maximum fallbacks to the highest possible value
typename Container::size_type sz = Container::suggested_upper_bucket_count(size_type(-1));
BOOST_TEST( sz > size_type(-1)/2 );
//In the rest of cases the upper bound is returned
sz = Container::suggested_upper_bucket_count(size_type(-1)/2);
BOOST_TEST( sz >= size_type(-1)/2 );
//If size_type is big enough the upper bound is returned
BOOST_IF_CONSTEXPR(sizeof(size_type) < sizeof(std::size_t)){
sz = Container::suggested_upper_bucket_count(size_type(-1)/2);
BOOST_TEST( sz >= size_type(-1)/2 );
}
sz = Container::suggested_upper_bucket_count(size_type(-1)/4);
BOOST_TEST( sz >= size_type(-1)/4 );
sz = Container::suggested_upper_bucket_count(size_type(-1) / 8);
BOOST_TEST(sz >= size_type(-1) / 8);
sz = Container::suggested_upper_bucket_count(0);
BOOST_TEST( sz > 0 );
//

View File

@@ -27,7 +27,8 @@
using namespace boost::intrusive;
template < class ValueTraits, bool ConstantTimeSize, bool CacheBegin, bool CompareHash, bool Incremental, bool Map, bool DefaultHolder >
template < class ValueTraits, bool ConstantTimeSize, bool CacheBegin, bool CompareHash
, bool Incremental, bool Map, bool DefaultHolder, bool LinearBuckets>
struct rebinder
{
typedef unordered_rebinder_common<ValueTraits, DefaultHolder, Map> common_t;
@@ -45,6 +46,7 @@ struct rebinder
, cache_begin<CacheBegin>
, compare_hash<CompareHash>
, incremental<Incremental>
, linear_buckets<LinearBuckets>
, typename common_t::holder_opt
, typename common_t::key_of_value_opt
, Option1
@@ -62,11 +64,11 @@ enum HookType
NonMember
};
template<class VoidPointer, bool ConstantTimeSize, bool DefaultHolder, bool Map, HookType Type>
template<class VoidPointer, bool ConstantTimeSize, bool DefaultHolder, bool Map, HookType Type, bool LinearBuckets>
class test_main_template;
template<class VoidPointer, bool ConstantTimeSize, bool DefaultHolder, bool Map>
class test_main_template<VoidPointer, ConstantTimeSize, DefaultHolder, Map, Base>
template<class VoidPointer, bool ConstantTimeSize, bool DefaultHolder, bool Map, bool LinearBuckets>
class test_main_template<VoidPointer, ConstantTimeSize, DefaultHolder, Map, Base, LinearBuckets>
{
public:
static void execute()
@@ -87,13 +89,14 @@ class test_main_template<VoidPointer, ConstantTimeSize, DefaultHolder, Map, Base
>::type base_hook_t;
test::test_unordered
< //cache_begin, compare_hash, incremental
rebinder<base_hook_t, ConstantTimeSize, ConstantTimeSize, !ConstantTimeSize, !!ConstantTimeSize, Map, DefaultHolder>
rebinder< base_hook_t, ConstantTimeSize, ConstantTimeSize
, !ConstantTimeSize, !!ConstantTimeSize, Map, DefaultHolder, LinearBuckets>
>::test_all(data);
}
};
template<class VoidPointer, bool ConstantTimeSize, bool DefaultHolder, bool Map>
class test_main_template<VoidPointer, ConstantTimeSize, DefaultHolder, Map, Member>
template<class VoidPointer, bool ConstantTimeSize, bool DefaultHolder, bool Map, bool LinearBuckets>
class test_main_template<VoidPointer, ConstantTimeSize, DefaultHolder, Map, Member, LinearBuckets>
{
public:
static void execute()
@@ -114,13 +117,14 @@ class test_main_template<VoidPointer, ConstantTimeSize, DefaultHolder, Map, Memb
>::type member_hook_t;
test::test_unordered
< //cache_begin, compare_hash, incremental
rebinder<member_hook_t, ConstantTimeSize, false, !ConstantTimeSize, false, !ConstantTimeSize, DefaultHolder>
rebinder <member_hook_t, ConstantTimeSize, false
, !ConstantTimeSize, false, !ConstantTimeSize, DefaultHolder, LinearBuckets>
>::test_all(data);
}
};
template<class VoidPointer, bool ConstantTimeSize, bool DefaultHolder, bool Map>
class test_main_template<VoidPointer, ConstantTimeSize, DefaultHolder, Map, NonMember>
template<class VoidPointer, bool ConstantTimeSize, bool DefaultHolder, bool Map, bool LinearBuckets>
class test_main_template<VoidPointer, ConstantTimeSize, DefaultHolder, Map, NonMember, LinearBuckets>
{
public:
@@ -137,7 +141,8 @@ class test_main_template<VoidPointer, ConstantTimeSize, DefaultHolder, Map, NonM
//nonmember
test::test_unordered
< //cache_begin, compare_hash, incremental
rebinder<typename testval_traits_t::nonhook_value_traits, ConstantTimeSize, false, false, false, Map, DefaultHolder>
rebinder< typename testval_traits_t::nonhook_value_traits
, ConstantTimeSize, false, false, false, Map, DefaultHolder, LinearBuckets>
>::test_all(data);
}
};
@@ -147,21 +152,31 @@ int main()
//VoidPointer x ConstantTimeSize x Map x DefaultHolder
//void pointer
test_main_template<void*, false, false, false, Base>::execute();
test_main_template<void*, false, true, false, Member>::execute();
test_main_template<void*, true, false, false, NonMember>::execute();
test_main_template<void*, true, true, false, Base>::execute();
test_main_template<void*, false, false, false, Base, false>::execute();
test_main_template<void*, false, true, false, Member, false>::execute();
test_main_template<void*, true, false, false, NonMember, false>::execute();
test_main_template<void*, true, true, false, Base, false>::execute();
test_main_template<void*, false, false, false, Base, true>::execute();
test_main_template<void*, false, true, false, Member, true>::execute();
test_main_template<void*, true, false, false, NonMember, true>::execute();
test_main_template<void*, true, true, false, Base, true>::execute();
//smart_ptr
test_main_template<smart_ptr<void>, false, false, false, Member>::execute();
test_main_template<smart_ptr<void>, false, true, false, NonMember>::execute();
test_main_template<smart_ptr<void>, true, false, false, Base>::execute();
test_main_template<smart_ptr<void>, true, true, false, Member>::execute();
test_main_template<smart_ptr<void>, false, false, false, Member, false>::execute();
test_main_template<smart_ptr<void>, false, true, false, NonMember, false>::execute();
test_main_template<smart_ptr<void>, true, false, false, Base, false>::execute();
test_main_template<smart_ptr<void>, true, true, false, Member, false>::execute();
test_main_template<smart_ptr<void>, true, true, false, Base, true>::execute();
test_main_template<smart_ptr<void>, false, false, false, Member, true>::execute();
test_main_template<smart_ptr<void>, false, true, false, NonMember, true>::execute();
test_main_template<smart_ptr<void>, true, false, false, Base, true>::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();
}

View File

@@ -25,7 +25,8 @@
using namespace boost::intrusive;
template < class ValueTraits, bool ConstantTimeSize, bool CacheBegin, bool CompareHash, bool Incremental, bool Map, bool DefaultHolder >
template < class ValueTraits, bool ConstantTimeSize, bool CacheBegin, bool CompareHash
, bool Incremental, bool Map, bool DefaultHolder, bool LinearBuckets >
struct rebinder
{
typedef unordered_rebinder_common<ValueTraits, DefaultHolder, Map> common_t;
@@ -43,6 +44,7 @@ struct rebinder
, cache_begin<CacheBegin>
, compare_hash<CompareHash>
, incremental<Incremental>
, linear_buckets<LinearBuckets>
, typename common_t::holder_opt
, typename common_t::key_of_value_opt
, size_type<unsigned short>
@@ -61,11 +63,11 @@ enum HookType
NonMember
};
template<class VoidPointer, bool ConstantTimeSize, bool DefaultHolder, bool Map, HookType Type>
template<class VoidPointer, bool ConstantTimeSize, bool DefaultHolder, bool Map, HookType Type, bool LinearBuckets>
class test_main_template;
template<class VoidPointer, bool ConstantTimeSize, bool DefaultHolder, bool Map>
class test_main_template<VoidPointer, ConstantTimeSize, DefaultHolder, Map, Base>
template<class VoidPointer, bool ConstantTimeSize, bool DefaultHolder, bool Map, bool LinearBuckets>
class test_main_template<VoidPointer, ConstantTimeSize, DefaultHolder, Map, Base, LinearBuckets>
{
public:
static void execute()
@@ -86,13 +88,14 @@ class test_main_template<VoidPointer, ConstantTimeSize, DefaultHolder, Map, Base
>::type base_hook_t;
test::test_unordered
< //cache_begin, compare_hash, incremental
rebinder<base_hook_t, ConstantTimeSize, ConstantTimeSize, !ConstantTimeSize, !!ConstantTimeSize, Map, DefaultHolder>
rebinder< base_hook_t, ConstantTimeSize, ConstantTimeSize
, !ConstantTimeSize, !!ConstantTimeSize, Map, DefaultHolder, LinearBuckets>
>::test_all(data);
}
};
template<class VoidPointer, bool ConstantTimeSize, bool DefaultHolder, bool Map>
class test_main_template<VoidPointer, ConstantTimeSize, DefaultHolder, Map, Member>
template<class VoidPointer, bool ConstantTimeSize, bool DefaultHolder, bool Map, bool LinearBuckets>
class test_main_template<VoidPointer, ConstantTimeSize, DefaultHolder, Map, Member, LinearBuckets>
{
public:
static void execute()
@@ -113,13 +116,13 @@ class test_main_template<VoidPointer, ConstantTimeSize, DefaultHolder, Map, Memb
>::type member_hook_t;
test::test_unordered
< //cache_begin, compare_hash, incremental
rebinder<member_hook_t, ConstantTimeSize, false, !ConstantTimeSize, false, !ConstantTimeSize, DefaultHolder>
rebinder<member_hook_t, ConstantTimeSize, false, !ConstantTimeSize, false, !ConstantTimeSize, DefaultHolder, LinearBuckets>
>::test_all(data);
}
};
template<class VoidPointer, bool ConstantTimeSize, bool DefaultHolder, bool Map>
class test_main_template<VoidPointer, ConstantTimeSize, DefaultHolder, Map, NonMember>
template<class VoidPointer, bool ConstantTimeSize, bool DefaultHolder, bool Map, bool LinearBuckets>
class test_main_template<VoidPointer, ConstantTimeSize, DefaultHolder, Map, NonMember, LinearBuckets>
{
public:
@@ -136,7 +139,7 @@ class test_main_template<VoidPointer, ConstantTimeSize, DefaultHolder, Map, NonM
//nonmember
test::test_unordered
< //cache_begin, compare_hash, incremental
rebinder<typename testval_traits_t::nonhook_value_traits, ConstantTimeSize, false, false, false, Map, DefaultHolder>
rebinder<typename testval_traits_t::nonhook_value_traits, ConstantTimeSize, false, false, false, Map, DefaultHolder, LinearBuckets>
>::test_all(data);
}
};
@@ -146,16 +149,25 @@ int main()
//VoidPointer x ConstantTimeSize x Map x DefaultHolder
//void pointer
test_main_template<void*, false, false, false, Base>::execute();
test_main_template<void*, false, true, false, Member>::execute();
test_main_template<void*, true, false, false, NonMember>::execute();
test_main_template<void*, true, true, false, Base>::execute();
test_main_template<void*, false, false, false, Base, false>::execute();
test_main_template<void*, false, true, false, Member, false>::execute();
test_main_template<void*, true, false, false, NonMember, false>::execute();
test_main_template<void*, true, true, false, Base, false>::execute();
test_main_template<void*, false, false, false, Base, true>::execute();
test_main_template<void*, false, true, false, Member, true>::execute();
test_main_template<void*, true, false, false, NonMember, true>::execute();
test_main_template<void*, true, true, false, Base, true>::execute();
//smart_ptr
test_main_template<smart_ptr<void>, false, false, false, Member>::execute();
test_main_template<smart_ptr<void>, false, true, false, NonMember>::execute();
test_main_template<smart_ptr<void>, true, false, false, Base>::execute();
test_main_template<smart_ptr<void>, true, true, false, Member>::execute();
test_main_template<smart_ptr<void>, false, false, false, Member, false>::execute();
test_main_template<smart_ptr<void>, false, true, false, NonMember, false>::execute();
test_main_template<smart_ptr<void>, true, false, false, Base, false>::execute();
test_main_template<smart_ptr<void>, true, true, false, Member, false>::execute();
test_main_template<smart_ptr<void>, false, false, false, Member, true>::execute();
test_main_template<smart_ptr<void>, false, true, false, NonMember, true>::execute();
test_main_template<smart_ptr<void>, true, false, false, Base, true>::execute();
////bounded_ptr (bool ConstantTimeSize, bool Map)
//test_main_template_bptr< false, false >::execute();

View File

@@ -50,12 +50,15 @@ void test_unordered<ContainerDefiner>::test_all (value_cont_type& values)
{
typedef typename ContainerDefiner::template container
<>::type unordered_type;
const std::size_t ExtraBuckets = unordered_type::bucket_overhead;
typedef typename unordered_type::bucket_traits bucket_traits;
typedef typename unordered_type::bucket_ptr bucket_ptr;
{
typename unordered_type::bucket_type buckets [BucketSize];
typename unordered_type::bucket_type buckets [BucketSize + ExtraBuckets];
unordered_type testset
(bucket_traits(pointer_traits<bucket_ptr>::pointer_to(buckets[0]), BucketSize));
(bucket_traits(pointer_traits<bucket_ptr>::pointer_to(buckets[0]), sizeof(buckets)/sizeof(*buckets)));
testset.insert(values.begin(), values.end());
test::test_container(testset);
testset.clear();
@@ -74,9 +77,9 @@ void test_unordered<ContainerDefiner>::test_all (value_cont_type& values)
value_cont_type vals(BucketSize);
for (std::size_t i = 0; i < BucketSize; ++i)
(&vals[i])->value_ = (int)i;
typename unordered_type::bucket_type buckets [BucketSize];
typename unordered_type::bucket_type buckets[BucketSize + ExtraBuckets];
unordered_type testset(bucket_traits(
pointer_traits<bucket_ptr>::pointer_to(buckets[0]), BucketSize));
pointer_traits<bucket_ptr>::pointer_to(buckets[0]), sizeof(buckets)/sizeof(*buckets)));
testset.insert(vals.begin(), vals.end());
test::test_iterator_forward(testset);
}
@@ -95,6 +98,8 @@ void test_unordered<ContainerDefiner>::test_impl()
{
typedef typename ContainerDefiner::template container
<>::type unordered_type;
const std::size_t ExtraBuckets = unordered_type::bucket_overhead;
typedef typename unordered_type::bucket_traits bucket_traits;
typedef typename unordered_type::bucket_ptr bucket_ptr;
@@ -102,9 +107,9 @@ void test_unordered<ContainerDefiner>::test_impl()
for (std::size_t i = 0u; i < 5u; ++i)
values[i].value_ = (int)i;
typename unordered_type::bucket_type buckets [BucketSize];
typename unordered_type::bucket_type buckets[BucketSize + ExtraBuckets];
unordered_type testset(bucket_traits(
pointer_traits<bucket_ptr>::pointer_to(buckets[0]), BucketSize));
pointer_traits<bucket_ptr>::pointer_to(buckets[0]), sizeof(buckets)/sizeof(*buckets)));
for (std::size_t i = 0u; i < 5u; ++i)
testset.insert (values[i]);
@@ -123,13 +128,15 @@ void test_unordered<ContainerDefiner>::test_sort(value_cont_type& values)
{
typedef typename ContainerDefiner::template container
<>::type unordered_type;
const std::size_t ExtraBuckets = unordered_type::bucket_overhead;
typedef typename unordered_type::bucket_traits bucket_traits;
typedef typename unordered_type::bucket_ptr bucket_ptr;
typename unordered_type::bucket_type buckets [BucketSize];
typename unordered_type::bucket_type buckets[BucketSize + ExtraBuckets];
unordered_type testset1
(values.begin(), values.end(), bucket_traits
(pointer_traits<bucket_ptr>::pointer_to(buckets[0]), BucketSize));
(pointer_traits<bucket_ptr>::pointer_to(buckets[0]), sizeof(buckets)/sizeof(*buckets)));
if(unordered_type::incremental){
{ int init_values [] = { 4, 5, 1, 2, 2, 3 };
@@ -147,16 +154,16 @@ void test_unordered<ContainerDefiner>::test_sort(value_cont_type& values)
template<class ContainerDefiner>
void test_unordered<ContainerDefiner>::test_insert(value_cont_type& values, detail::false_) //not multikey
{
typedef typename ContainerDefiner::template container
<>::type unordered_set_type;
typedef typename unordered_set_type::bucket_traits bucket_traits;
typedef typename unordered_set_type::key_of_value key_of_value;
typename unordered_set_type::bucket_type buckets [BucketSize];
const std::size_t ExtraBuckets = unordered_set_type::bucket_overhead;
typename unordered_set_type::bucket_type buckets[BucketSize + ExtraBuckets];
unordered_set_type testset(bucket_traits(
pointer_traits<typename unordered_set_type::bucket_ptr>::
pointer_to(buckets[0]), BucketSize));
pointer_to(buckets[0]), sizeof(buckets)/sizeof(*buckets)));
testset.insert(&values[0] + 2, &values[0] + 5);
typename unordered_set_type::insert_commit_data commit_data;
@@ -206,15 +213,16 @@ void test_unordered<ContainerDefiner>::test_insert(value_cont_type& values, deta
{
typedef typename ContainerDefiner::template container
<>::type unordered_type;
const std::size_t ExtraBuckets = unordered_type::bucket_overhead;
typedef typename unordered_type::bucket_traits bucket_traits;
typedef typename unordered_type::bucket_ptr bucket_ptr;
typedef typename unordered_type::iterator iterator;
typedef typename unordered_type::key_type key_type;
{
typename unordered_type::bucket_type buckets [BucketSize];
typename unordered_type::bucket_type buckets[BucketSize + ExtraBuckets];
unordered_type testset(bucket_traits(
pointer_traits<bucket_ptr>::pointer_to(buckets[0]), BucketSize));
pointer_traits<bucket_ptr>::pointer_to(buckets[0]), sizeof(buckets)/sizeof(*buckets)));
testset.insert(&values[0] + 2, &values[0] + 5);
@@ -251,9 +259,9 @@ void test_unordered<ContainerDefiner>::test_insert(value_cont_type& values, deta
BOOST_TEST (testset.empty() == true);
//Now with a single bucket
typename unordered_type::bucket_type single_bucket[1];
typename unordered_type::bucket_type single_bucket[1u + ExtraBuckets];
unordered_type testset2(bucket_traits(
pointer_traits<bucket_ptr>::pointer_to(single_bucket[0]), 1));
pointer_traits<bucket_ptr>::pointer_to(single_bucket[0]), sizeof(single_bucket)/sizeof(*single_bucket)));
testset2.insert(&values[0], &values[0] + values.size());
BOOST_TEST (testset2.erase(key_type(5)) == 1);
BOOST_TEST (testset2.erase(key_type(2)) == 2);
@@ -294,9 +302,9 @@ void test_unordered<ContainerDefiner>::test_insert(value_cont_type& values, deta
BOOST_TEST (testset.empty() == true);
//Now with a single bucket
typename unordered_type::bucket_type single_bucket[1];
typename unordered_type::bucket_type single_bucket[1u + ExtraBuckets];
unordered_type testset2(bucket_traits(
pointer_traits<bucket_ptr>::pointer_to(single_bucket[0]), 1));
pointer_traits<bucket_ptr>::pointer_to(single_bucket[0]), sizeof(single_bucket)/sizeof(*single_bucket)));
testset2.insert(&values[0], &values[0] + values.size());
BOOST_TEST (testset2.erase(key_type(5)) == 1);
BOOST_TEST (testset2.erase(key_type(2)) == 2);
@@ -310,13 +318,13 @@ void test_unordered<ContainerDefiner>::test_insert(value_cont_type& values, deta
//Now erase just one per loop
const int random_init[] = { 3, 2, 4, 1, 5, 2, 2 };
const std::size_t random_size = sizeof(random_init)/sizeof(random_init[0]);
typename unordered_type::bucket_type single_bucket[1];
typename unordered_type::bucket_type single_bucket[1u + ExtraBuckets];
for(std::size_t i = 0u, max = random_size; i != max; ++i){
value_cont_type data (random_size);
for (std::size_t j = 0; j < random_size; ++j)
data[j].value_ = random_init[j];
unordered_type testset_new(bucket_traits(
pointer_traits<bucket_ptr>::pointer_to(single_bucket[0]), 1));
pointer_traits<bucket_ptr>::pointer_to(single_bucket[0]), sizeof(single_bucket)/sizeof(*single_bucket)));
testset_new.insert(&data[0], &data[0]+max);
testset_new.erase(testset_new.iterator_to(data[i]));
BOOST_TEST (testset_new.size() == (max -1));
@@ -327,16 +335,14 @@ void test_unordered<ContainerDefiner>::test_insert(value_cont_type& values, deta
const std::size_t LoadFactor = 3;
const std::size_t NumIterations = BucketSize*LoadFactor;
value_cont_type random_init(NumIterations);//Preserve memory
value_cont_type set_tester;
set_tester.reserve(NumIterations);
//Initialize values
for (std::size_t i = 0u; i < NumIterations; ++i){
random_init[i].value_ = (int)i*2;//(i/LoadFactor)*LoadFactor;
random_init[i].value_ = (int)i*2;
}
typename unordered_type::bucket_type buckets [BucketSize];
bucket_traits btraits(pointer_traits<bucket_ptr>::pointer_to(buckets[0]), BucketSize);
typename unordered_type::bucket_type buckets[BucketSize + ExtraBuckets];
bucket_traits btraits(pointer_traits<bucket_ptr>::pointer_to(buckets[0]), sizeof(buckets)/sizeof(*buckets));
for(std::size_t initial_pos = 0; initial_pos != (NumIterations+1u); ++initial_pos){
for(std::size_t final_pos = initial_pos; final_pos != (NumIterations+1); ++final_pos){
@@ -370,20 +376,25 @@ void test_unordered<ContainerDefiner>::test_insert(value_cont_type& values, deta
//Now test...
BOOST_TEST ((random_init.size() - erased_cnt) == testset.size());
//Create an ordered copy of the intrusive container
set_tester.insert(set_tester.end(), testset.begin(), testset.end());
std::sort(set_tester.begin(), set_tester.end());
{
typename value_cont_type::iterator it = set_tester.begin(), itend = set_tester.end();
typename value_cont_type::iterator random_init_it(random_init.begin());
for( ; it != itend; ++it){
while(!random_init_it->is_linked())
//for non-linear buckets is_linked is a reliable marker for a node
//inserted in a hash map, but not for linear buckets, which are null-ended
BOOST_IF_CONSTEXPR(!unordered_type::linear_buckets){
value_cont_type set_tester;
set_tester.reserve(NumIterations);
//Create an ordered copy of the intrusive container
set_tester.insert(set_tester.end(), testset.begin(), testset.end());
std::sort(set_tester.begin(), set_tester.end());
{
typename value_cont_type::iterator it = set_tester.begin(), itend = set_tester.end();
typename value_cont_type::iterator random_init_it(random_init.begin());
for( ; it != itend; ++it){
while(!random_init_it->is_linked())
++random_init_it;
BOOST_TEST(*it == *random_init_it);
++random_init_it;
BOOST_TEST(*it == *random_init_it);
++random_init_it;
}
}
}
set_tester.clear();
}
}
}
@@ -395,16 +406,17 @@ void test_unordered<ContainerDefiner>::test_swap(value_cont_type& values)
{
typedef typename ContainerDefiner::template container
<>::type unordered_type;
const std::size_t ExtraBuckets = unordered_type::bucket_overhead;
typedef typename unordered_type::bucket_traits bucket_traits;
typedef typename unordered_type::bucket_ptr bucket_ptr;
typename unordered_type::bucket_type buckets [BucketSize];
typename unordered_type::bucket_type buckets[BucketSize + ExtraBuckets];
typename unordered_type::bucket_type buckets2 [BucketSize];
typename unordered_type::bucket_type buckets2[BucketSize + ExtraBuckets];
unordered_type testset1(&values[0], &values[0] + 2,
bucket_traits(pointer_traits<bucket_ptr>::pointer_to(buckets[0]), BucketSize));
bucket_traits(pointer_traits<bucket_ptr>::pointer_to(buckets[0]), sizeof(buckets)/sizeof(*buckets)));
unordered_type testset2(bucket_traits(
pointer_traits<bucket_ptr>::pointer_to(buckets2[0]), BucketSize));
pointer_traits<bucket_ptr>::pointer_to(buckets2[0]), sizeof(buckets2)/sizeof(*buckets2)));
testset2.insert (&values[0] + 2, &values[0] + 6);
testset1.swap (testset2);
@@ -443,14 +455,16 @@ void test_unordered<ContainerDefiner>::test_rehash(value_cont_type& values, deta
typedef typename ContainerDefiner::template container
<>::type unordered_type;
const std::size_t ExtraBuckets = unordered_type::bucket_overhead;
typedef typename unordered_type::bucket_traits bucket_traits;
typedef typename unordered_type::bucket_ptr bucket_ptr;
//Build a uset
typename unordered_type::bucket_type buckets1 [BucketSize];
typename unordered_type::bucket_type buckets2 [BucketSize*2];
typename unordered_type::bucket_type buckets1[BucketSize + ExtraBuckets];
typename unordered_type::bucket_type buckets2[BucketSize*2u + ExtraBuckets];
unordered_type testset1(&values[0], &values[0] + values.size(),
bucket_traits(pointer_traits<bucket_ptr>::
pointer_to(buckets1[0]), BucketSize));
pointer_to(buckets1[0]), sizeof(buckets1)/sizeof(*buckets1)));
//Test current state
BOOST_TEST(testset1.split_count() == BucketSize/2);
{ int init_values [] = { 4, 5, 1, 2, 2, 3 };
@@ -478,8 +492,8 @@ void test_unordered<ContainerDefiner>::test_rehash(value_cont_type& values, deta
//
//This incremental rehash should fail because the new size is not twice the original
BOOST_TEST(testset1.incremental_rehash(bucket_traits(
pointer_traits<bucket_ptr>::
pointer_to(buckets1[0]), BucketSize)) == false);
pointer_traits<bucket_ptr>::pointer_to(buckets1[0])
, sizeof(buckets1)/sizeof(*buckets1))) == false);
BOOST_TEST(testset1.split_count() == BucketSize);
{ int init_values [] = { 1, 2, 2, 3, 4, 5 };
TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
@@ -490,7 +504,8 @@ void test_unordered<ContainerDefiner>::test_rehash(value_cont_type& values, deta
//This incremental rehash should fail because the new size is not twice the original
BOOST_TEST(testset1.incremental_rehash(bucket_traits(
pointer_traits<bucket_ptr>::
pointer_to(buckets2[0]), BucketSize)) == false);
pointer_to(buckets2[0])
, BucketSize + ExtraBuckets)) == false);
BOOST_TEST(testset1.split_count() == BucketSize);
{ int init_values [] = { 1, 2, 2, 3, 4, 5 };
TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
@@ -499,7 +514,8 @@ void test_unordered<ContainerDefiner>::test_rehash(value_cont_type& values, deta
//and split_count is the same as the old bucket count
BOOST_TEST(testset1.incremental_rehash(bucket_traits(
pointer_traits<bucket_ptr>::
pointer_to(buckets2[0]), BucketSize*2)) == true);
pointer_to(buckets2[0])
, sizeof(buckets2)/sizeof(*buckets2))) == true);
BOOST_TEST(testset1.split_count() == BucketSize);
{ int init_values [] = { 1, 2, 2, 3, 4, 5 };
TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
@@ -508,7 +524,8 @@ void test_unordered<ContainerDefiner>::test_rehash(value_cont_type& values, deta
//and split_count is the same as the new bucket count
BOOST_TEST(testset1.incremental_rehash(bucket_traits(
pointer_traits<bucket_ptr>::
pointer_to(buckets1[0]), BucketSize)) == true);
pointer_to(buckets1[0])
, sizeof(buckets1)/sizeof(*buckets1))) == true);
BOOST_TEST(testset1.split_count() == BucketSize);
{ int init_values [] = { 1, 2, 2, 3, 4, 5 };
TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
@@ -516,7 +533,8 @@ void test_unordered<ContainerDefiner>::test_rehash(value_cont_type& values, deta
//Shrink rehash
testset1.rehash(bucket_traits(
pointer_traits<bucket_ptr>::
pointer_to(buckets1[0]), 4));
pointer_to(buckets1[0])
, (sizeof(buckets1) / sizeof(*buckets1)- ExtraBuckets) / 2u + ExtraBuckets));
BOOST_TEST (testset1.incremental_rehash() == false);
{ int init_values [] = { 4, 5, 1, 2, 2, 3 };
TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
@@ -524,7 +542,8 @@ void test_unordered<ContainerDefiner>::test_rehash(value_cont_type& values, deta
//Shrink rehash again
testset1.rehash(bucket_traits(
pointer_traits<bucket_ptr>::
pointer_to(buckets1[0]), 2));
pointer_to(buckets1[0])
, (sizeof(buckets1) / sizeof(*buckets1) - ExtraBuckets) / 4u + ExtraBuckets));
BOOST_TEST (testset1.incremental_rehash() == false);
{ int init_values [] = { 2, 2, 4, 3, 5, 1 };
TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
@@ -532,7 +551,11 @@ void test_unordered<ContainerDefiner>::test_rehash(value_cont_type& values, deta
//Growing rehash
testset1.rehash(bucket_traits(
pointer_traits<bucket_ptr>::
pointer_to(buckets1[0]), BucketSize));
pointer_to(buckets1[0])
, sizeof(buckets1)/sizeof(*buckets1)));
{ int init_values [] = { 1, 2, 2, 3, 4, 5 };
TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
//Full rehash (no effects)
testset1.full_rehash();
@@ -571,39 +594,40 @@ void test_unordered<ContainerDefiner>::test_rehash(value_cont_type& values, deta
{
typedef typename ContainerDefiner::template container
<>::type unordered_type;
const std::size_t ExtraBuckets = unordered_type::bucket_overhead;
typedef typename unordered_type::bucket_traits bucket_traits;
typedef typename unordered_type::bucket_ptr bucket_ptr;
typename unordered_type::bucket_type buckets1 [BucketSize];
typename unordered_type::bucket_type buckets2 [2];
typename unordered_type::bucket_type buckets3 [BucketSize*2];
typename unordered_type::bucket_type buckets1[BucketSize + ExtraBuckets];
typename unordered_type::bucket_type buckets2 [2 + ExtraBuckets];
typename unordered_type::bucket_type buckets3[BucketSize*2 + ExtraBuckets];
unordered_type testset1(&values[0], &values[0] + 6, bucket_traits(
pointer_traits<bucket_ptr>::
pointer_to(buckets1[0]), BucketSize));
pointer_to(buckets1[0]), sizeof(buckets1)/sizeof(*buckets1)));
{ int init_values [] = { 1, 2, 2, 3, 4, 5 };
TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
testset1.rehash(bucket_traits(
pointer_traits<bucket_ptr>::pointer_to(buckets2[0]), 2));
pointer_traits<bucket_ptr>::pointer_to(buckets2[0]), BucketSize/4 + ExtraBuckets));
{ int init_values [] = { 4, 2, 2, 5, 3, 1 };
TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
testset1.rehash(bucket_traits(
pointer_traits<bucket_ptr>::pointer_to(buckets3[0]), BucketSize*2));
pointer_traits<bucket_ptr>::pointer_to(buckets3[0]), sizeof(buckets3) / sizeof(*buckets3)));
{ int init_values [] = { 1, 2, 2, 3, 4, 5 };
TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
//Now rehash reducing the buckets
testset1.rehash(bucket_traits(
pointer_traits<bucket_ptr>::pointer_to(buckets3[0]), 2));
pointer_traits<bucket_ptr>::pointer_to(buckets3[0]), BucketSize / 4 + ExtraBuckets));
{ int init_values [] = { 4, 2, 2, 5, 3, 1 };
TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
//Now rehash increasing the buckets
testset1.rehash(bucket_traits(
pointer_traits<bucket_ptr>::pointer_to(buckets3[0]), BucketSize*2));
pointer_traits<bucket_ptr>::pointer_to(buckets3[0]), sizeof(buckets3) / sizeof(*buckets3)));
{ int init_values [] = { 1, 2, 2, 3, 4, 5 };
TEST_INTRUSIVE_SEQUENCE_MAYBEUNIQUE( init_values, testset1 ); }
@@ -625,10 +649,11 @@ void test_unordered<ContainerDefiner>::test_find(value_cont_type& values)
typedef typename unordered_type::bucket_ptr bucket_ptr;
typedef typename unordered_type::key_of_value key_of_value;
const bool is_multikey = boost::intrusive::test::is_multikey_true<unordered_type>::value;
const std::size_t ExtraBuckets = unordered_type::bucket_overhead;
typename unordered_type::bucket_type buckets[BucketSize];
typename unordered_type::bucket_type buckets[BucketSize + ExtraBuckets];
unordered_type testset(values.begin(), values.end(), bucket_traits(
pointer_traits<bucket_ptr>::pointer_to(buckets[0]), BucketSize));
pointer_traits<bucket_ptr>::pointer_to(buckets[0]), sizeof(buckets)/sizeof(*buckets)));
typedef typename unordered_type::iterator iterator;
@@ -657,6 +682,8 @@ void test_unordered<ContainerDefiner>::test_clone(value_cont_type& values)
{
typedef typename ContainerDefiner::template container
<>::type unordered_type;
const std::size_t ExtraBuckets = unordered_type::bucket_overhead;
typedef typename unordered_type::value_type value_type;
typedef std::multiset<value_type> std_multiset_t;
@@ -665,12 +692,12 @@ void test_unordered<ContainerDefiner>::test_clone(value_cont_type& values)
{
//Test with equal bucket arrays
typename unordered_type::bucket_type buckets1 [BucketSize];
typename unordered_type::bucket_type buckets2 [BucketSize];
typename unordered_type::bucket_type buckets1[BucketSize + ExtraBuckets];
typename unordered_type::bucket_type buckets2[BucketSize + ExtraBuckets];
unordered_type testset1 (values.begin(), values.end(), bucket_traits(
pointer_traits<bucket_ptr>::pointer_to(buckets1[0]), BucketSize));
pointer_traits<bucket_ptr>::pointer_to(buckets1[0]), sizeof(buckets1)/sizeof(*buckets1)));
unordered_type testset2 (bucket_traits(
pointer_traits<bucket_ptr>::pointer_to(buckets2[0]), BucketSize));
pointer_traits<bucket_ptr>::pointer_to(buckets2[0]), sizeof(buckets2)/sizeof(*buckets2)));
testset2.clone_from(testset1, test::new_cloner<value_type>(), test::delete_disposer<value_type>());
BOOST_TEST(testset1 == testset2);
@@ -692,12 +719,12 @@ void test_unordered<ContainerDefiner>::test_clone(value_cont_type& values)
}
{
//Test with bigger source bucket arrays
typename unordered_type::bucket_type buckets1 [BucketSize*2];
typename unordered_type::bucket_type buckets2 [BucketSize];
typename unordered_type::bucket_type buckets1[BucketSize*2u + ExtraBuckets];
typename unordered_type::bucket_type buckets2[BucketSize + ExtraBuckets];
unordered_type testset1 (values.begin(), values.end(), bucket_traits(
pointer_traits<bucket_ptr>::pointer_to(buckets1[0]), BucketSize*2));
pointer_traits<bucket_ptr>::pointer_to(buckets1[0]), sizeof(buckets1)/sizeof(*buckets1)));
unordered_type testset2 (bucket_traits(
pointer_traits<bucket_ptr>::pointer_to(buckets2[0]), BucketSize));
pointer_traits<bucket_ptr>::pointer_to(buckets2[0]), sizeof(buckets2)/sizeof(*buckets2)));
testset2.clone_from(testset1, test::new_cloner<value_type>(), test::delete_disposer<value_type>());
BOOST_TEST(testset1 == testset2);
@@ -719,12 +746,12 @@ void test_unordered<ContainerDefiner>::test_clone(value_cont_type& values)
}
{
//Test with smaller source bucket arrays
typename unordered_type::bucket_type buckets1 [BucketSize];
typename unordered_type::bucket_type buckets2 [BucketSize*2];
typename unordered_type::bucket_type buckets1[BucketSize + ExtraBuckets];
typename unordered_type::bucket_type buckets2[BucketSize*2u + ExtraBuckets];
unordered_type testset1 (values.begin(), values.end(), bucket_traits(
pointer_traits<bucket_ptr>::pointer_to(buckets1[0]), BucketSize));
pointer_traits<bucket_ptr>::pointer_to(buckets1[0]), sizeof(buckets1)/sizeof(*buckets1)));
unordered_type testset2 (bucket_traits(
pointer_traits<bucket_ptr>::pointer_to(buckets2[0]), BucketSize*2));
pointer_traits<bucket_ptr>::pointer_to(buckets2[0]), sizeof(buckets2)/sizeof(*buckets2)));
testset2.clone_from(testset1, test::new_cloner<value_type>(), test::delete_disposer<value_type>());
BOOST_TEST(testset1 == testset2);