Unordered/Hash: Merge from trunk.

[SVN r78319]
This commit is contained in:
Daniel James
2012-05-03 22:05:21 +00:00
parent fa3d93ddbc
commit a8cd8cdd0b
50 changed files with 862 additions and 625 deletions

View File

@ -175,4 +175,21 @@ C++11 support has resulted in some breaking changes:
* Fix warning due to accidental odd assignment.
* Slightly better error messages.
[h2 Boost 1.50.0]
* Fix equality for `unordered_multiset` and `unordered_multimap`.
* [@http://svn.boost.org/trac/boost/ticket/6771 Ticket 6771]:
Avoid gcc's `-Wfloat-equal` warning.
* [@http://svn.boost.org/trac/boost/ticket/6784 Ticket 6784]:
Fix some Sun specific code.
* Remove some of the smaller prime number of buckets, as they may make
collisions quite probable (e.g. multiples of 5 are very common because
we used base 10).
* On old versions of Visual C++, use the container library's implementation
of `allocator_traits`, as it's more likely to work.
* On machines with 64 bit std::size_t, use power of 2 buckets, with Thomas
Wang's hash function to pick which one to use. As modulus is very slow
for 64 bit values.
* Some internal changes.
[endsect]

View File

@ -27,11 +27,34 @@
#include <boost/utility/addressof.hpp>
#if !defined(BOOST_UNORDERED_USE_ALLOCATOR_TRAITS)
#define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 0
// An allocator_traits test is currently failing for gcc 4.7 on mingw. I think
// this is because it's an older development version. Temporarily disabling
// std::allocator_traits in order ot get clean test results. Will reactivate
// later.
/*
# if defined(__GXX_EXPERIMENTAL_CXX0X__) && \
(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
# define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 1
# endif
*/
// Use container's allocator_traits for older versions of Visual C++ as I don't
// test with them.
# if defined(BOOST_MSVC) && BOOST_MSVC < 1400
# define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 2
# endif
#endif
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS
#if !defined(BOOST_UNORDERED_USE_ALLOCATOR_TRAITS)
# define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 0
#endif
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1
# include <memory>
#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 2
# include <boost/container/allocator/allocator_traits.hpp>
#endif
#if !defined(BOOST_NO_0X_HDR_TYPE_TRAITS)
@ -194,7 +217,7 @@ namespace boost { namespace unordered { namespace detail {
// Uses the standard versions if available.
// (although untested as I don't have access to a standard version yet)
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1
template <typename Alloc>
struct allocator_traits : std::allocator_traits<Alloc> {};
@ -206,6 +229,18 @@ namespace boost { namespace unordered { namespace detail {
template rebind_alloc<T> type;
};
#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 2
template <typename Alloc>
struct allocator_traits :
boost::container::allocator_traits<Alloc> {};
template <typename Alloc, typename T>
struct rebind_wrap :
boost::container::allocator_traits<Alloc>::
template portable_rebind_alloc<T>
{};
#else
// TODO: Does this match std::allocator_traits<Alloc>::rebind_alloc<T>?

View File

@ -18,6 +18,8 @@
#include <boost/type_traits/alignment_of.hpp>
#include <boost/swap.hpp>
#include <boost/assert.hpp>
#include <boost/limits.hpp>
#include <boost/iterator.hpp>
#if defined(BOOST_MSVC)
#pragma warning(push)
@ -29,7 +31,10 @@ namespace boost { namespace unordered { namespace detail {
template <typename Types> struct table;
template <typename NodePointer> struct bucket;
struct ptr_bucket;
template <typename A, typename Bucket, typename Node> struct buckets;
template <typename A, typename Bucket, typename Node, typename Policy>
struct buckets;
template <typename Types> struct table_impl;
template <typename Types> struct grouped_table_impl;
///////////////////////////////////////////////////////////////////
//
@ -178,13 +183,364 @@ namespace boost { namespace unordered { namespace detail {
enum { extra_node = false };
};
}}}
namespace boost { namespace unordered { namespace iterator_detail {
////////////////////////////////////////////////////////////////////////////
// Iterators
//
// all no throw
template <typename NodePointer, typename Value> struct iterator;
template <typename ConstNodePointer, typename NodePointer,
typename Value> struct c_iterator;
template <typename NodePointer, typename Value, typename Policy>
struct l_iterator;
template <typename ConstNodePointer, typename NodePointer,
typename Value, typename Policy> struct cl_iterator;
// Local Iterators
//
// all no throw
template <typename NodePointer, typename Value, typename Policy>
struct l_iterator
: public boost::iterator<
std::forward_iterator_tag, Value, std::ptrdiff_t,
NodePointer, Value&>
{
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
template <typename ConstNodePointer, typename NodePointer2,
typename Value2, typename Policy2>
friend struct boost::unordered::iterator_detail::cl_iterator;
private:
#endif
typedef NodePointer node_pointer;
typedef boost::unordered::iterator_detail::iterator<NodePointer, Value>
iterator;
node_pointer ptr_;
std::size_t bucket_;
std::size_t bucket_count_;
public:
l_iterator() : ptr_() {}
l_iterator(iterator x, std::size_t b, std::size_t c)
: ptr_(x.node_), bucket_(b), bucket_count_(c) {}
Value& operator*() const {
return ptr_->value();
}
Value* operator->() const {
return ptr_->value_ptr();
}
l_iterator& operator++() {
ptr_ = static_cast<node_pointer>(ptr_->next_);
if (ptr_ && Policy::to_bucket(bucket_count_, ptr_->hash_)
!= bucket_)
ptr_ = node_pointer();
return *this;
}
l_iterator operator++(int) {
l_iterator tmp(*this);
++(*this);
return tmp;
}
bool operator==(l_iterator x) const {
return ptr_ == x.ptr_;
}
bool operator!=(l_iterator x) const {
return ptr_ != x.ptr_;
}
};
template <typename ConstNodePointer, typename NodePointer, typename Value,
typename Policy>
struct cl_iterator
: public boost::iterator<
std::forward_iterator_tag, Value, std::ptrdiff_t,
ConstNodePointer, Value const&>
{
friend struct boost::unordered::iterator_detail::l_iterator
<NodePointer, Value, Policy>;
private:
typedef NodePointer node_pointer;
typedef boost::unordered::iterator_detail::iterator<NodePointer, Value>
iterator;
node_pointer ptr_;
std::size_t bucket_;
std::size_t bucket_count_;
public:
cl_iterator() : ptr_() {}
cl_iterator(iterator x, std::size_t b, std::size_t c) :
ptr_(x.node_), bucket_(b), bucket_count_(c) {}
cl_iterator(boost::unordered::iterator_detail::l_iterator<
NodePointer, Value, Policy> const& x) :
ptr_(x.ptr_), bucket_(x.bucket_), bucket_count_(x.bucket_count_)
{}
Value const&
operator*() const {
return ptr_->value();
}
Value const* operator->() const {
return ptr_->value_ptr();
}
cl_iterator& operator++() {
ptr_ = static_cast<node_pointer>(ptr_->next_);
if (ptr_ && Policy::to_bucket(bucket_count_, ptr_->hash_)
!= bucket_)
ptr_ = node_pointer();
return *this;
}
cl_iterator operator++(int) {
cl_iterator tmp(*this);
++(*this);
return tmp;
}
friend bool operator==(cl_iterator const& x, cl_iterator const& y) {
return x.ptr_ == y.ptr_;
}
friend bool operator!=(cl_iterator const& x, cl_iterator const& y) {
return x.ptr_ != y.ptr_;
}
};
template <typename NodePointer, typename Value>
struct iterator
: public boost::iterator<
std::forward_iterator_tag, Value, std::ptrdiff_t,
NodePointer, Value&>
{
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
template <typename, typename, typename>
friend struct boost::unordered::iterator_detail::c_iterator;
template <typename, typename, typename>
friend struct boost::unordered::iterator_detail::l_iterator;
template <typename, typename, typename, typename>
friend struct boost::unordered::iterator_detail::cl_iterator;
template <typename>
friend struct boost::unordered::detail::table;
template <typename, typename, typename, typename>
friend struct boost::unordered::detail::buckets;
template <typename>
friend struct boost::unordered::detail::table_impl;
template <typename>
friend struct boost::unordered::detail::grouped_table_impl;
private:
#endif
typedef NodePointer node_pointer;
node_pointer node_;
public:
iterator() : node_() {}
explicit iterator(node_pointer const& x) : node_(x) {}
Value& operator*() const {
return node_->value();
}
Value* operator->() const {
return &node_->value();
}
iterator& operator++() {
node_ = static_cast<node_pointer>(node_->next_);
return *this;
}
iterator operator++(int) {
iterator tmp(node_);
node_ = static_cast<node_pointer>(node_->next_);
return tmp;
}
bool operator==(iterator const& x) const {
return node_ == x.node_;
}
bool operator!=(iterator const& x) const {
return node_ != x.node_;
}
};
template <typename ConstNodePointer, typename NodePointer, typename Value>
struct c_iterator
: public boost::iterator<
std::forward_iterator_tag, Value, std::ptrdiff_t,
ConstNodePointer, Value const&>
{
friend struct boost::unordered::iterator_detail::iterator<
NodePointer, Value>;
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
template <typename>
friend struct boost::unordered::detail::table;
template <typename, typename, typename, typename>
friend struct boost::unordered::detail::buckets;
template <typename>
friend struct boost::unordered::detail::table_impl;
template <typename>
friend struct boost::unordered::detail::grouped_table_impl;
private:
#endif
typedef NodePointer node_pointer;
typedef boost::unordered::iterator_detail::iterator<NodePointer, Value>
iterator;
node_pointer node_;
public:
c_iterator() : node_() {}
explicit c_iterator(node_pointer const& x) : node_(x) {}
c_iterator(boost::unordered::iterator_detail::iterator<
NodePointer, Value> const& x) : node_(x.node_) {}
Value const& operator*() const {
return node_->value();
}
Value const* operator->() const {
return &node_->value();
}
c_iterator& operator++() {
node_ = static_cast<node_pointer>(node_->next_);
return *this;
}
c_iterator operator++(int) {
c_iterator tmp(node_);
node_ = static_cast<node_pointer>(node_->next_);
return tmp;
}
friend bool operator==(c_iterator const& x, c_iterator const& y) {
return x.node_ == y.node_;
}
friend bool operator!=(c_iterator const& x, c_iterator const& y) {
return x.node_ != y.node_;
}
};
}}}
namespace boost { namespace unordered { namespace detail {
///////////////////////////////////////////////////////////////////
//
// Hash Policy
//
// Don't really want buckets to derive from this, but will for now.
template <typename SizeT>
struct prime_policy
{
template <typename Hash, typename T>
static inline SizeT apply_hash(Hash const& hf, T const& x) {
return hf(x);
}
static inline SizeT to_bucket(SizeT bucket_count, SizeT hash) {
return hash % bucket_count;
}
static inline SizeT new_bucket_count(SizeT min) {
return boost::unordered::detail::next_prime(min);
}
static inline SizeT prev_bucket_count(SizeT max) {
return boost::unordered::detail::prev_prime(max);
}
};
template <typename SizeT>
struct mix64_policy
{
template <typename Hash, typename T>
static inline SizeT apply_hash(Hash const& hf, T const& x) {
SizeT key = hf(x);
key = (~key) + (key << 21); // key = (key << 21) - key - 1;
key = key ^ (key >> 24);
key = (key + (key << 3)) + (key << 8); // key * 265
key = key ^ (key >> 14);
key = (key + (key << 2)) + (key << 4); // key * 21
key = key ^ (key >> 28);
key = key + (key << 31);
return key;
}
static inline SizeT to_bucket(SizeT bucket_count, SizeT hash) {
return hash & (bucket_count - 1);
}
static inline SizeT new_bucket_count(SizeT min) {
if (min <= 4) return 4;
--min;
min |= min >> 1;
min |= min >> 2;
min |= min >> 4;
min |= min >> 8;
min |= min >> 16;
min |= min >> 32;
return min + 1;
}
static inline SizeT prev_bucket_count(SizeT max) {
max |= max >> 1;
max |= max >> 2;
max |= max >> 4;
max |= max >> 8;
max |= max >> 16;
max |= max >> 32;
return (max >> 1) + 1;
}
};
template <int digits, int radix>
struct pick_policy_impl {
typedef prime_policy<std::size_t> type;
};
template <>
struct pick_policy_impl<64, 2> {
typedef mix64_policy<std::size_t> type;
};
struct pick_policy :
pick_policy_impl<
std::numeric_limits<std::size_t>::digits,
std::numeric_limits<std::size_t>::radix> {};
///////////////////////////////////////////////////////////////////
//
// Buckets
template <typename A, typename Bucket, typename Node>
struct buckets
template <typename A, typename Bucket, typename Node, typename Policy>
struct buckets : Policy
{
private:
buckets(buckets const&);
@ -193,6 +549,7 @@ namespace boost { namespace unordered { namespace detail {
typedef boost::unordered::detail::allocator_traits<A> traits;
typedef typename traits::value_type value_type;
typedef Policy policy;
typedef Node node;
typedef Bucket bucket;
typedef typename boost::unordered::detail::rebind_wrap<A, node>::type
@ -214,6 +571,16 @@ namespace boost { namespace unordered { namespace detail {
typedef boost::unordered::detail::node_constructor<node_allocator>
node_constructor;
typedef boost::unordered::iterator_detail::
iterator<node_pointer, value_type> iterator;
typedef boost::unordered::iterator_detail::
c_iterator<const_node_pointer, node_pointer, value_type> c_iterator;
typedef boost::unordered::iterator_detail::
l_iterator<node_pointer, value_type, policy> l_iterator;
typedef boost::unordered::iterator_detail::
cl_iterator<const_node_pointer, node_pointer, value_type, policy>
cl_iterator;
// Members
bucket_pointer buckets_;
@ -247,7 +614,7 @@ namespace boost { namespace unordered { namespace detail {
std::size_t max_bucket_count() const
{
// -1 to account for the start bucket.
return boost::unordered::detail::prev_prime(
return policy::prev_bucket_count(
bucket_allocator_traits::max_size(bucket_alloc()) - 1);
}
@ -266,16 +633,17 @@ namespace boost { namespace unordered { namespace detail {
return this->get_bucket(bucket_index)->next_;
}
node_pointer get_start() const
iterator get_start() const
{
return static_cast<node_pointer>(this->get_previous_start()->next_);
return iterator(static_cast<node_pointer>(
this->get_previous_start()->next_));
}
node_pointer get_start(std::size_t bucket_index) const
iterator get_start(std::size_t bucket_index) const
{
previous_pointer prev = this->get_previous_start(bucket_index);
return prev ? static_cast<node_pointer>(prev->next_) :
node_pointer();
return prev ? iterator(static_cast<node_pointer>(prev->next_)) :
iterator();
}
float load_factor() const
@ -288,14 +656,15 @@ namespace boost { namespace unordered { namespace detail {
std::size_t bucket_size(std::size_t index) const
{
if (!this->size_) return 0;
node_pointer ptr = this->get_start(index);
if (!ptr) return 0;
iterator it = this->get_start(index);
if (!it.node_) return 0;
std::size_t count = 0;
while(ptr && ptr->hash_ % this->bucket_count_ == index)
while(it.node_ && policy::to_bucket(
this->bucket_count_, it.node_->hash_) == index)
{
++count;
ptr = static_cast<node_pointer>(ptr->next_);
++it;
}
return count;
@ -391,21 +760,22 @@ namespace boost { namespace unordered { namespace detail {
////////////////////////////////////////////////////////////////////////
// Delete/destruct
inline void delete_node(node_pointer n)
inline void delete_node(c_iterator n)
{
boost::unordered::detail::destroy(n->value_ptr());
node_allocator_traits::destroy(node_alloc(), boost::addressof(*n));
node_allocator_traits::deallocate(node_alloc(), n, 1);
boost::unordered::detail::destroy(n.node_->value_ptr());
node_allocator_traits::destroy(node_alloc(),
boost::addressof(*n.node_));
node_allocator_traits::deallocate(node_alloc(), n.node_, 1);
--size_;
}
std::size_t delete_nodes(node_pointer begin, node_pointer end)
std::size_t delete_nodes(c_iterator begin, c_iterator end)
{
std::size_t count = 0;
while(begin != end) {
node_pointer n = begin;
begin = static_cast<node_pointer>(begin->next_);
c_iterator n = begin;
++begin;
delete_node(n);
++count;
}
@ -433,7 +803,7 @@ namespace boost { namespace unordered { namespace detail {
while(prev->next_) {
node_pointer n = static_cast<node_pointer>(prev->next_);
prev->next_ = n->next_;
delete_node(n);
delete_node(iterator(n));
}
delete_extra_node(prev);
@ -463,7 +833,7 @@ namespace boost { namespace unordered { namespace detail {
while(prev->next_) {
node_pointer n = static_cast<node_pointer>(prev->next_);
prev->next_ = n->next_;
delete_node(n);
delete_node(iterator(n));
}
bucket_pointer end = this->get_bucket(this->bucket_count_);
@ -487,7 +857,7 @@ namespace boost { namespace unordered { namespace detail {
else
{
bucket_pointer next_bucket = this->get_bucket(
next->hash_ % this->bucket_count_);
policy::to_bucket(this->bucket_count_, next->hash_));
if (next_bucket != bucket)
{
@ -513,7 +883,7 @@ namespace boost { namespace unordered { namespace detail {
if (n == end) return;
std::size_t new_bucket_index =
n->hash_ % this->bucket_count_;
policy::to_bucket(this->bucket_count_, n->hash_);
if (bucket_index != new_bucket_index) {
bucket_index = new_bucket_index;
break;
@ -529,7 +899,7 @@ namespace boost { namespace unordered { namespace detail {
if (n == end) break;
std::size_t new_bucket_index =
n->hash_ % this->bucket_count_;
policy::to_bucket(this->bucket_count_, n->hash_);
if (bucket_index != new_bucket_index) {
bucket_index = new_bucket_index;
this->get_bucket(bucket_index)->next_ = previous_pointer();
@ -538,7 +908,8 @@ namespace boost { namespace unordered { namespace detail {
// Finally fix the bucket containing the trailing node.
if (n) {
this->get_bucket(n->hash_ % this->bucket_count_)->next_
this->get_bucket(
policy::to_bucket(this->bucket_count_, n->hash_))->next_
= prev;
}
}

View File

@ -160,9 +160,9 @@ BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS,
//
// Used for piecewise construction.
#if !BOOST_WORKAROUND(__SUNPRO_CC, <= 0x590)
#if !defined(__SUNPRO_CC)
#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \
# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \
template<typename T> \
void construct_from_tuple(T* ptr, namespace_::tuple<>) \
{ \
@ -172,7 +172,7 @@ BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS,
BOOST_PP_REPEAT_FROM_TO(1, n, \
BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_)
#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \
# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \
template<typename T, BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
void construct_from_tuple(T* ptr, \
namespace_::tuple<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> const& x) \
@ -182,32 +182,26 @@ BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS,
); \
}
#define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) \
# define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) \
namespace_::get<n>(x)
BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost)
#if !defined(BOOST_NO_0X_HDR_TUPLE)
BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std)
#endif
#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE
#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL
#undef BOOST_UNORDERED_GET_TUPLE_ARG
#else
template <int N> struct length {};
template<typename T>
void construct_from_tuple_impl(
boost::unordered::detail::length<0>, T* ptr,
boost::tuple<>)
{
new ((void*) ptr) T();
}
# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \
template<typename T> \
void construct_from_tuple_impl( \
boost::unordered::detail::length<0>, T* ptr, \
namespace_::tuple<>) \
{ \
new ((void*) ptr) T(); \
} \
\
BOOST_PP_REPEAT_FROM_TO(1, n, \
BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_)
#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, _) \
# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \
template<typename T, BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
void construct_from_tuple_impl( \
boost::unordered::detail::length<n>, T* ptr, \
@ -218,11 +212,22 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std)
); \
}
#define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, _) \
boost::get<n>(x)
# define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) \
namespace_::get<n>(x)
BOOST_PP_REPEAT_FROM_TO(1, 10, \
BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, _)
#endif
BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost)
#if !defined(__SUNPRO_CC) && !defined(BOOST_NO_0X_HDR_TUPLE)
BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std)
#endif
#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE
#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL
#undef BOOST_UNORDERED_GET_TUPLE_ARG
#if defined(__SUNPRO_CC)
template <typename T, typename Tuple>
void construct_from_tuple(T* ptr, Tuple const& x)
@ -233,9 +238,6 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std)
ptr, x);
}
#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL
#undef BOOST_UNORDERED_GET_TUPLE_ARG
#endif
////////////////////////////////////////////////////////////////////////////

View File

@ -136,6 +136,8 @@ namespace boost { namespace unordered { namespace detail {
typedef boost::unordered::detail::grouped_table_impl<types> table;
typedef boost::unordered::detail::set_extractor<value_type> extractor;
typedef boost::unordered::detail::pick_policy::type policy;
};
template <typename A, typename K, typename M, typename H, typename P>
@ -160,6 +162,8 @@ namespace boost { namespace unordered { namespace detail {
typedef boost::unordered::detail::grouped_table_impl<types> table;
typedef boost::unordered::detail::map_extractor<key_type, value_type>
extractor;
typedef boost::unordered::detail::pick_policy::type policy;
};
template <typename Types>
@ -169,6 +173,7 @@ namespace boost { namespace unordered { namespace detail {
typedef typename table::value_type value_type;
typedef typename table::bucket bucket;
typedef typename table::buckets buckets;
typedef typename table::policy policy;
typedef typename table::node_pointer node_pointer;
typedef typename table::node_allocator node_allocator;
typedef typename table::node_allocator_traits node_allocator_traits;
@ -181,6 +186,7 @@ namespace boost { namespace unordered { namespace detail {
typedef typename table::node_constructor node_constructor;
typedef typename table::extractor extractor;
typedef typename table::iterator iterator;
typedef typename table::c_iterator c_iterator;
// Constructors
@ -214,46 +220,48 @@ namespace boost { namespace unordered { namespace detail {
// Accessors
template <class Key, class Pred>
node_pointer find_node_impl(
iterator find_node_impl(
std::size_t hash,
Key const& k,
Pred const& eq) const
{
std::size_t bucket_index = hash % this->bucket_count_;
node_pointer n = this->get_start(bucket_index);
std::size_t bucket_index =
policy::to_bucket(this->bucket_count_, hash);
iterator n = this->get_start(bucket_index);
for (;;)
{
if (!n) return n;
if (!n.node_) return n;
std::size_t node_hash = n->hash_;
std::size_t node_hash = n.node_->hash_;
if (hash == node_hash)
{
if (eq(k, this->get_key(n->value())))
if (eq(k, this->get_key(*n)))
return n;
}
else
{
if (node_hash % this->bucket_count_ != bucket_index)
return node_pointer();
if (policy::to_bucket(this->bucket_count_, node_hash)
!= bucket_index)
return iterator();
}
n = static_cast<node_pointer>(
static_cast<node_pointer>(n->group_prev_)->next_);
n = iterator(static_cast<node_pointer>(
static_cast<node_pointer>(n.node_->group_prev_)->next_));
}
}
std::size_t count(key_type const& k) const
{
node_pointer n = this->find_node(k);
if (!n) return 0;
iterator n = this->find_node(k);
if (!n.node_) return 0;
std::size_t count = 0;
node_pointer it = n;
node_pointer it = n.node_;
do {
it = static_cast<node_pointer>(it->group_prev_);
++count;
} while(it != n);
} while(it != n.node_);
return count;
}
@ -261,12 +269,12 @@ namespace boost { namespace unordered { namespace detail {
std::pair<iterator, iterator>
equal_range(key_type const& k) const
{
node_pointer n = this->find_node(k);
iterator n = this->find_node(k);
return std::make_pair(
iterator(n), iterator(n ?
n, n.node_ ? iterator(
static_cast<node_pointer>(
static_cast<node_pointer>(n->group_prev_)->next_) :
n));
static_cast<node_pointer>(n.node_->group_prev_)->next_
)) : n);
}
// Equality
@ -276,14 +284,14 @@ namespace boost { namespace unordered { namespace detail {
if(this->size_ != other.size_) return false;
if(!this->size_) return true;
for(node_pointer n1 = this->get_start(); n1;)
for(iterator n1 = this->get_start(); n1.node_;)
{
node_pointer n2 = other.find_matching_node(n1);
if (!n2) return false;
node_pointer end1 = static_cast<node_pointer>(
static_cast<node_pointer>(n1->group_prev_)->next_);
node_pointer end2 = static_cast<node_pointer>(
static_cast<node_pointer>(n2->group_prev_)->next_);
iterator n2 = other.find_matching_node(n1);
if (!n2.node_) return false;
iterator end1(static_cast<node_pointer>(
static_cast<node_pointer>(n1.node_->group_prev_)->next_));
iterator end2(static_cast<node_pointer>(
static_cast<node_pointer>(n2.node_->group_prev_)->next_));
if (!group_equals(n1, end1, n2, end2)) return false;
n1 = end1;
}
@ -293,25 +301,24 @@ namespace boost { namespace unordered { namespace detail {
#if !defined(BOOST_UNORDERED_DEPRECATED_EQUALITY)
static bool group_equals(node_pointer n1, node_pointer end1,
node_pointer n2, node_pointer end2)
static bool group_equals(iterator n1, iterator end1,
iterator n2, iterator end2)
{
for(;;)
{
if (n1->value() != n2->value())
break;
if (*n1 != *n2) break;
n1 = static_cast<node_pointer>(n1->next_);
n2 = static_cast<node_pointer>(n2->next_);
++n1;
++n2;
if (n1 == end1) return n2 == end2;
if (n2 == end2) return false;
}
for(node_pointer n1a = n1, n2a = n2;;)
for(iterator n1a = n1, n2a = n2;;)
{
n1a = static_cast<node_pointer>(n1a->next_);
n2a = static_cast<node_pointer>(n2a->next_);
++n1a;
++n2a;
if (n1a == end1)
{
@ -322,50 +329,50 @@ namespace boost { namespace unordered { namespace detail {
if (n2a == end2) return false;
}
node_pointer start = n1;
for(;n1 != end2; n1 = static_cast<node_pointer>(n1->next_))
iterator start = n1;
for(;n1 != end1; ++n1)
{
value_type const& v = n1->value();
value_type const& v = *n1;
if (find(start, n1, v)) continue;
std::size_t matches = count_equal(n2, end2, v);
if (!matches || matches != 1 + count_equal(
static_cast<node_pointer>(n1->next_), end1, v))
return false;
if (!matches) return false;
iterator next = n1;
++next;
if (matches != 1 + count_equal(next, end1, v)) return false;
}
return true;
}
static bool find(node_pointer n, node_pointer end, value_type const& v)
static bool find(iterator n, iterator end, value_type const& v)
{
for(;n != end; n = static_cast<node_pointer>(n->next_))
if (n->value() == v)
for(;n != end; ++n)
if (*n == v)
return true;
return false;
}
static std::size_t count_equal(node_pointer n, node_pointer end,
static std::size_t count_equal(iterator n, iterator end,
value_type const& v)
{
std::size_t count = 0;
for(;n != end; n = static_cast<node_pointer>(n->next_))
if (n->value() == v) ++count;
for(;n != end; ++n)
if (*n == v) ++count;
return count;
}
#else
static bool group_equals(node_pointer n1, node_pointer end1,
node_pointer n2, node_pointer end2)
static bool group_equals(iterator n1, iterator end1,
iterator n2, iterator end2)
{
for(;;)
{
if(!extractor::compare_mapped(
n1->value(), n2->value()))
if(!extractor::compare_mapped(*n1, *n2))
return false;
n1 = static_cast<node_pointer>(n1->next_);
n2 = static_cast<node_pointer>(n2->next_);
++n1;
++n2;
if (n1 == end1) return n2 == end2;
if (n2 == end2) return false;
@ -387,35 +394,37 @@ namespace boost { namespace unordered { namespace detail {
pos->group_prev_ = static_cast<link_pointer>(n);
}
inline node_pointer add_node(
inline iterator add_node(
node_constructor& a,
std::size_t hash,
node_pointer pos)
iterator pos)
{
node_pointer n = a.release();
n->hash_ = hash;
if(pos) {
this->add_after_node(n, pos);
if (pos.node_) {
this->add_after_node(n, pos.node_);
if (n->next_) {
std::size_t next_bucket =
static_cast<node_pointer>(n->next_)->hash_ %
this->bucket_count_;
if (next_bucket != hash % this->bucket_count_) {
std::size_t next_bucket = policy::to_bucket(
this->bucket_count_,
static_cast<node_pointer>(n->next_)->hash_);
if (next_bucket !=
policy::to_bucket(this->bucket_count_, hash)) {
this->get_bucket(next_bucket)->next_ = n;
}
}
}
else {
bucket_pointer b = this->get_bucket(hash % this->bucket_count_);
bucket_pointer b = this->get_bucket(
policy::to_bucket(this->bucket_count_, hash));
if (!b->next_)
{
previous_pointer start_node = this->get_previous_start();
if (start_node->next_) {
this->get_bucket(
this->get_bucket(policy::to_bucket(this->bucket_count_,
static_cast<node_pointer>(start_node->next_)->hash_
% this->bucket_count_)->next_ = n;
))->next_ = n;
}
b->next_ = start_node;
@ -429,14 +438,14 @@ namespace boost { namespace unordered { namespace detail {
}
}
++this->size_;
return n;
return iterator(n);
}
node_pointer emplace_impl(node_constructor& a)
iterator emplace_impl(node_constructor& a)
{
key_type const& k = this->get_key(a.value());
std::size_t hash = this->hash_function()(k);
node_pointer position = this->find_node(hash, k);
std::size_t hash = this->hash(k);
iterator position = this->find_node(hash, k);
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
@ -447,9 +456,8 @@ namespace boost { namespace unordered { namespace detail {
void emplace_impl_no_rehash(node_constructor& a)
{
key_type const& k = this->get_key(a.value());
std::size_t hash = this->hash_function()(k);
this->add_node(a, hash,
this->find_node(hash, k));
std::size_t hash = this->hash(k);
this->add_node(a, hash, this->find_node(hash, k));
}
#if defined(BOOST_NO_RVALUE_REFERENCES)
@ -523,8 +531,9 @@ namespace boost { namespace unordered { namespace detail {
{
if(!this->size_) return 0;
std::size_t hash = this->hash_function()(k);
std::size_t bucket_index = hash % this->bucket_count_;
std::size_t hash = this->hash(k);
std::size_t bucket_index =
policy::to_bucket(this->bucket_count_, hash);
bucket_pointer bucket = this->get_bucket(bucket_index);
previous_pointer prev = bucket->next_;
@ -535,7 +544,8 @@ namespace boost { namespace unordered { namespace detail {
if (!prev->next_) return 0;
std::size_t node_hash =
static_cast<node_pointer>(prev->next_)->hash_;
if (node_hash % this->bucket_count_ != bucket_index)
if (policy::to_bucket(this->bucket_count_, node_hash)
!= bucket_index)
return 0;
if (node_hash == hash &&
this->key_eq()(k, this->get_key(
@ -551,36 +561,38 @@ namespace boost { namespace unordered { namespace detail {
node_pointer end = static_cast<node_pointer>(end1);
prev->next_ = end1;
this->fix_buckets(bucket, prev, end);
return this->delete_nodes(pos, end);
return this->delete_nodes(c_iterator(pos), c_iterator(end));
}
node_pointer erase(node_pointer r)
iterator erase(c_iterator r)
{
BOOST_ASSERT(r);
node_pointer next = static_cast<node_pointer>(r->next_);
BOOST_ASSERT(r.node_);
iterator next(r.node_);
++next;
bucket_pointer bucket = this->get_bucket(
r->hash_ % this->bucket_count_);
previous_pointer prev = unlink_node(*bucket, r);
policy::to_bucket(this->bucket_count_, r.node_->hash_));
previous_pointer prev = unlink_node(*bucket, r.node_);
this->fix_buckets(bucket, prev, next);
this->fix_buckets(bucket, prev, next.node_);
this->delete_node(r);
return next;
}
node_pointer erase_range(node_pointer r1, node_pointer r2)
iterator erase_range(c_iterator r1, c_iterator r2)
{
if (r1 == r2) return r2;
if (r1 == r2) return iterator(r2.node_);
std::size_t bucket_index = r1->hash_ % this->bucket_count_;
std::size_t bucket_index =
policy::to_bucket(this->bucket_count_, r1.node_->hash_);
previous_pointer prev = unlink_nodes(
*this->get_bucket(bucket_index), r1, r2);
this->fix_buckets_range(bucket_index, prev, r1, r2);
*this->get_bucket(bucket_index), r1.node_, r2.node_);
this->fix_buckets_range(bucket_index, prev, r1.node_, r2.node_);
this->delete_nodes(r1, r2);
return r2;
return iterator(r2.node_);
}
static previous_pointer unlink_node(bucket& b, node_pointer n)
@ -697,17 +709,18 @@ namespace boost { namespace unordered { namespace detail {
node_constructor a(dst.node_alloc());
node_pointer n = src.get_start();
iterator n = src.get_start();
previous_pointer prev = dst.get_previous_start();
while(n) {
std::size_t hash = n->hash_;
node_pointer group_end =
while (n.node_) {
std::size_t hash = n.node_->hash_;
iterator group_end(
static_cast<node_pointer>(
static_cast<node_pointer>(n->group_prev_)->next_);
static_cast<node_pointer>(n.node_->group_prev_)->next_
));
a.construct_node();
a.construct_value2(n->value());
a.construct_value2(*n);
node_pointer first_node = a.release();
node_pointer end = first_node;
@ -715,11 +728,10 @@ namespace boost { namespace unordered { namespace detail {
prev->next_ = static_cast<link_pointer>(first_node);
++dst.size_;
for(n = static_cast<node_pointer>(n->next_); n != group_end;
n = static_cast<node_pointer>(n->next_))
for (++n; n != group_end; ++n)
{
a.construct_node();
a.construct_value2(n->value());
a.construct_value2(*n);
end = a.release();
end->hash_ = hash;
add_after_node(end, first_node);
@ -744,17 +756,18 @@ namespace boost { namespace unordered { namespace detail {
node_constructor a(dst.node_alloc());
node_pointer n = src.get_start();
iterator n = src.get_start();
previous_pointer prev = dst.get_previous_start();
while(n) {
std::size_t hash = n->hash_;
node_pointer group_end =
while (n.node_) {
std::size_t hash = n.node_->hash_;
iterator group_end(
static_cast<node_pointer>(
static_cast<node_pointer>(n->group_prev_)->next_);
static_cast<node_pointer>(n.node_->group_prev_)->next_
));
a.construct_node();
a.construct_value2(boost::move(n->value()));
a.construct_value2(boost::move(*n));
node_pointer first_node = a.release();
node_pointer end = first_node;
@ -762,11 +775,10 @@ namespace boost { namespace unordered { namespace detail {
prev->next_ = static_cast<link_pointer>(first_node);
++dst.size_;
for(n = static_cast<node_pointer>(n->next_); n != group_end;
n = static_cast<node_pointer>(n->next_))
for(++n; n != group_end; ++n)
{
a.construct_node();
a.construct_value2(boost::move(n->value()));
a.construct_value2(boost::move(*n));
end = a.release();
end->hash_ = hash;
add_after_node(end, first_node);
@ -809,7 +821,8 @@ namespace boost { namespace unordered { namespace detail {
static previous_pointer place_in_bucket(buckets& dst,
previous_pointer prev, node_pointer end)
{
bucket_pointer b = dst.get_bucket(end->hash_ % dst.bucket_count_);
bucket_pointer b = dst.get_bucket(policy::to_bucket(
dst.bucket_count_, end->hash_));
if (!b->next_) {
b->next_ = static_cast<node_pointer>(prev);

View File

@ -10,41 +10,11 @@
# pragma once
#endif
#include <boost/config.hpp>
#include <memory>
#include <functional>
#include <boost/functional/hash_fwd.hpp>
namespace boost
{
namespace unordered
{
template <class K,
class T,
class H = boost::hash<K>,
class P = std::equal_to<K>,
class A = std::allocator<std::pair<const K, T> > >
class unordered_map;
template <class K,
class T,
class H = boost::hash<K>,
class P = std::equal_to<K>,
class A = std::allocator<std::pair<const K, T> > >
class unordered_multimap;
template <class T,
class H = boost::hash<T>,
class P = std::equal_to<T>,
class A = std::allocator<T> >
class unordered_set;
template <class T,
class H = boost::hash<T>,
class P = std::equal_to<T>,
class A = std::allocator<T> >
class unordered_multiset;
struct piecewise_construct_t {};
const piecewise_construct_t piecewise_construct = piecewise_construct_t();
}

View File

@ -11,251 +11,8 @@
#include <boost/unordered/detail/util.hpp>
#include <boost/type_traits/aligned_storage.hpp>
#include <boost/type_traits/alignment_of.hpp>
#include <boost/iterator.hpp>
#include <cmath>
namespace boost { namespace unordered { namespace iterator_detail {
////////////////////////////////////////////////////////////////////////////
// Iterators
//
// all no throw
template <typename NodePointer, typename Value> struct iterator;
template <typename ConstNodePointer, typename NodePointer,
typename Value> struct c_iterator;
template <typename NodePointer, typename Value> struct l_iterator;
template <typename ConstNodePointer, typename NodePointer,
typename Value> struct cl_iterator;
// Local Iterators
//
// all no throw
template <typename NodePointer, typename Value>
struct l_iterator
: public boost::iterator<
std::forward_iterator_tag, Value, std::ptrdiff_t,
NodePointer, Value&>
{
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
template <typename ConstNodePointer, typename NodePointer2,
typename Value2>
friend struct boost::unordered::iterator_detail::cl_iterator;
private:
#endif
typedef NodePointer node_pointer;
node_pointer ptr_;
std::size_t bucket_;
std::size_t bucket_count_;
public:
l_iterator() : ptr_() {}
l_iterator(node_pointer x, std::size_t b, std::size_t c)
: ptr_(x), bucket_(b), bucket_count_(c) {}
Value& operator*() const {
return ptr_->value();
}
Value* operator->() const {
return ptr_->value_ptr();
}
l_iterator& operator++() {
ptr_ = static_cast<node_pointer>(ptr_->next_);
if (ptr_ && ptr_->hash_ % bucket_count_ != bucket_)
ptr_ = node_pointer();
return *this;
}
l_iterator operator++(int) {
l_iterator tmp(*this);
++(*this);
return tmp;
}
bool operator==(l_iterator x) const {
return ptr_ == x.ptr_;
}
bool operator!=(l_iterator x) const {
return ptr_ != x.ptr_;
}
};
template <typename ConstNodePointer, typename NodePointer, typename Value>
struct cl_iterator
: public boost::iterator<
std::forward_iterator_tag, Value, std::ptrdiff_t,
ConstNodePointer, Value const&>
{
friend struct boost::unordered::iterator_detail::l_iterator
<NodePointer, Value>;
private:
typedef NodePointer node_pointer;
node_pointer ptr_;
std::size_t bucket_;
std::size_t bucket_count_;
public:
cl_iterator() : ptr_() {}
cl_iterator(node_pointer x, std::size_t b, std::size_t c) :
ptr_(x), bucket_(b), bucket_count_(c) {}
cl_iterator(boost::unordered::iterator_detail::l_iterator<
NodePointer, Value> const& x) :
ptr_(x.ptr_), bucket_(x.bucket_), bucket_count_(x.bucket_count_)
{}
Value const&
operator*() const {
return ptr_->value();
}
Value const* operator->() const {
return ptr_->value_ptr();
}
cl_iterator& operator++() {
ptr_ = static_cast<node_pointer>(ptr_->next_);
if (ptr_ && ptr_->hash_ % bucket_count_ != bucket_)
ptr_ = node_pointer();
return *this;
}
cl_iterator operator++(int) {
cl_iterator tmp(*this);
++(*this);
return tmp;
}
friend bool operator==(cl_iterator const& x, cl_iterator const& y) {
return x.ptr_ == y.ptr_;
}
friend bool operator!=(cl_iterator const& x, cl_iterator const& y) {
return x.ptr_ != y.ptr_;
}
};
template <typename NodePointer, typename Value>
struct iterator
: public boost::iterator<
std::forward_iterator_tag, Value, std::ptrdiff_t,
NodePointer, Value&>
{
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
template <typename ConstNodePointer, typename NodePointer2,
typename Value2>
friend struct boost::unordered::iterator_detail::c_iterator;
private:
#endif
typedef NodePointer node_pointer;
node_pointer node_;
public:
iterator() : node_() {}
explicit iterator(node_pointer const& x) : node_(x) {}
Value& operator*() const {
return node_->value();
}
Value* operator->() const {
return &node_->value();
}
iterator& operator++() {
node_ = static_cast<node_pointer>(node_->next_);
return *this;
}
iterator operator++(int) {
iterator tmp(node_);
node_ = static_cast<node_pointer>(node_->next_);
return tmp;
}
bool operator==(iterator const& x) const {
return node_ == x.node_;
}
bool operator!=(iterator const& x) const {
return node_ != x.node_;
}
};
template <typename ConstNodePointer, typename NodePointer, typename Value>
struct c_iterator
: public boost::iterator<
std::forward_iterator_tag, Value, std::ptrdiff_t,
ConstNodePointer, Value const&>
{
friend struct boost::unordered::iterator_detail::iterator<
NodePointer, Value>;
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
template <typename K, typename T, typename H, typename P, typename A>
friend class boost::unordered::unordered_map;
template <typename K, typename T, typename H, typename P, typename A>
friend class boost::unordered::unordered_multimap;
template <typename T, typename H, typename P, typename A>
friend class boost::unordered::unordered_set;
template <typename T, typename H, typename P, typename A>
friend class boost::unordered::unordered_multiset;
private:
#endif
typedef NodePointer node_pointer;
node_pointer node_;
public:
c_iterator() : node_() {}
explicit c_iterator(node_pointer const& x) : node_(x) {}
c_iterator(boost::unordered::iterator_detail::iterator<
NodePointer, Value> const& x) : node_(x.node_) {}
Value const& operator*() const {
return node_->value();
}
Value const* operator->() const {
return &node_->value();
}
c_iterator& operator++() {
node_ = static_cast<node_pointer>(node_->next_);
return *this;
}
c_iterator operator++(int) {
c_iterator tmp(node_);
node_ = static_cast<node_pointer>(node_->next_);
return tmp;
}
friend bool operator==(c_iterator const& x, c_iterator const& y) {
return x.node_ == y.node_;
}
friend bool operator!=(c_iterator const& x, c_iterator const& y) {
return x.node_ != y.node_;
}
};
}}}
namespace boost { namespace unordered { namespace detail {
////////////////////////////////////////////////////////////////////////////
@ -302,7 +59,8 @@ namespace boost { namespace unordered { namespace detail {
boost::unordered::detail::buckets<
typename Types::allocator,
typename Types::bucket,
typename Types::node>,
typename Types::node,
typename Types::policy>,
boost::unordered::detail::functions<
typename Types::hasher,
typename Types::key_equal>
@ -318,6 +76,7 @@ namespace boost { namespace unordered { namespace detail {
typedef typename Types::value_type value_type;
typedef typename Types::table table_impl;
typedef typename Types::link_pointer link_pointer;
typedef typename Types::policy policy;
typedef boost::unordered::detail::functions<
typename Types::hasher,
@ -326,22 +85,15 @@ namespace boost { namespace unordered { namespace detail {
typedef boost::unordered::detail::buckets<
typename Types::allocator,
typename Types::bucket,
typename Types::node> buckets;
typename Types::node,
typename Types::policy> buckets;
typedef typename buckets::node_allocator node_allocator;
typedef typename buckets::node_allocator_traits node_allocator_traits;
typedef typename buckets::node_pointer node_pointer;
typedef typename buckets::const_node_pointer const_node_pointer;
typedef boost::unordered::iterator_detail::
iterator<node_pointer, value_type> iterator;
typedef boost::unordered::iterator_detail::
c_iterator<const_node_pointer, node_pointer, value_type> c_iterator;
typedef boost::unordered::iterator_detail::
l_iterator<node_pointer, value_type> l_iterator;
typedef boost::unordered::iterator_detail::
cl_iterator<const_node_pointer, node_pointer, value_type>
cl_iterator;
typedef typename table::iterator iterator;
// Members
@ -384,7 +136,7 @@ namespace boost { namespace unordered { namespace detail {
std::size_t min_buckets_for_size(std::size_t size) const
{
BOOST_ASSERT(this->mlf_ != 0);
BOOST_ASSERT(this->mlf_ >= minimum_max_load_factor);
using namespace std;
@ -395,7 +147,7 @@ namespace boost { namespace unordered { namespace detail {
// Or from rehash post-condition:
// count > size / mlf_
return boost::unordered::detail::next_prime(
return policy::new_bucket_count(
boost::unordered::detail::double_to_size(floor(
static_cast<double>(size) /
static_cast<double>(mlf_))) + 1);
@ -408,7 +160,7 @@ namespace boost { namespace unordered { namespace detail {
hasher const& hf,
key_equal const& eq,
node_allocator const& a) :
buckets(a, boost::unordered::detail::next_prime(num_buckets)),
buckets(a, policy::new_bucket_count(num_buckets)),
functions(hf, eq),
mlf_(1.0f),
max_load_(0)
@ -458,9 +210,9 @@ namespace boost { namespace unordered { namespace detail {
// Iterators
node_pointer begin() const {
iterator begin() const {
return !this->buckets_ ?
node_pointer() : this->get_start();
iterator() : this->get_start();
}
// Assignment
@ -586,36 +338,41 @@ namespace boost { namespace unordered { namespace detail {
return extractor::extract(x);
}
std::size_t hash(key_type const& k) const
{
return policy::apply_hash(this->hash_function(), k);
}
// Find Node
template <typename Key, typename Hash, typename Pred>
node_pointer generic_find_node(
iterator generic_find_node(
Key const& k,
Hash const& hash_function,
Pred const& eq) const
{
if (!this->size_) return node_pointer();
if (!this->size_) return iterator();
return static_cast<table_impl const*>(this)->
find_node_impl(hash_function(k), k, eq);
find_node_impl(policy::apply_hash(hash_function, k), k, eq);
}
node_pointer find_node(
iterator find_node(
std::size_t hash,
key_type const& k) const
{
if (!this->size_) return node_pointer();
if (!this->size_) return iterator();
return static_cast<table_impl const*>(this)->
find_node_impl(hash, k, this->key_eq());
}
node_pointer find_node(key_type const& k) const
iterator find_node(key_type const& k) const
{
if (!this->size_) return node_pointer();
if (!this->size_) return iterator();
return static_cast<table_impl const*>(this)->
find_node_impl(this->hash_function()(k), k, this->key_eq());
find_node_impl(this->hash(k), k, this->key_eq());
}
node_pointer find_matching_node(node_pointer n) const
iterator find_matching_node(iterator n) const
{
// TODO: Does this apply to C++11?
//
@ -623,7 +380,7 @@ namespace boost { namespace unordered { namespace detail {
// when different hash functions are used. So I can't use the hash
// value from the node here.
return find_node(get_key(n->value()));
return find_node(get_key(*n));
}
// Reserve and rehash
@ -666,10 +423,10 @@ namespace boost { namespace unordered { namespace detail {
if(!this->size_) {
if(this->buckets_) this->delete_buckets();
this->bucket_count_ = next_prime(min_buckets);
this->bucket_count_ = policy::new_bucket_count(min_buckets);
}
else {
min_buckets = next_prime((std::max)(min_buckets,
min_buckets = policy::new_bucket_count((std::max)(min_buckets,
boost::unordered::detail::double_to_size(floor(
static_cast<double>(this->size_) /
static_cast<double>(mlf_))) + 1));

View File

@ -132,6 +132,8 @@ namespace boost { namespace unordered { namespace detail {
typedef boost::unordered::detail::table_impl<types> table;
typedef boost::unordered::detail::set_extractor<value_type> extractor;
typedef boost::unordered::detail::pick_policy::type policy;
};
template <typename A, typename K, typename M, typename H, typename P>
@ -156,6 +158,8 @@ namespace boost { namespace unordered { namespace detail {
typedef boost::unordered::detail::table_impl<types> table;
typedef boost::unordered::detail::map_extractor<key_type, value_type>
extractor;
typedef boost::unordered::detail::pick_policy::type policy;
};
template <typename Types>
@ -165,6 +169,7 @@ namespace boost { namespace unordered { namespace detail {
typedef typename table::value_type value_type;
typedef typename table::bucket bucket;
typedef typename table::buckets buckets;
typedef typename table::policy policy;
typedef typename table::node_pointer node_pointer;
typedef typename table::node_allocator node_allocator;
typedef typename table::node_allocator_traits node_allocator_traits;
@ -177,6 +182,7 @@ namespace boost { namespace unordered { namespace detail {
typedef typename table::node_constructor node_constructor;
typedef typename table::extractor extractor;
typedef typename table::iterator iterator;
typedef typename table::c_iterator c_iterator;
typedef std::pair<iterator, bool> emplace_return;
@ -212,44 +218,46 @@ namespace boost { namespace unordered { namespace detail {
// Accessors
template <class Key, class Pred>
node_pointer find_node_impl(
iterator find_node_impl(
std::size_t hash,
Key const& k,
Pred const& eq) const
{
std::size_t bucket_index = hash % this->bucket_count_;
node_pointer n = this->get_start(bucket_index);
std::size_t bucket_index =
policy::to_bucket(this->bucket_count_, hash);
iterator n = this->get_start(bucket_index);
for (;;)
{
if (!n) return n;
if (!n.node_) return n;
std::size_t node_hash = n->hash_;
std::size_t node_hash = n.node_->hash_;
if (hash == node_hash)
{
if (eq(k, this->get_key(n->value())))
if (eq(k, this->get_key(*n)))
return n;
}
else
{
if (node_hash % this->bucket_count_ != bucket_index)
return node_pointer();
if (policy::to_bucket(this->bucket_count_, node_hash)
!= bucket_index)
return iterator();
}
n = static_cast<node_pointer>(n->next_);
++n;
}
}
std::size_t count(key_type const& k) const
{
return this->find_node(k) ? 1 : 0;
return this->find_node(k).node_ ? 1 : 0;
}
value_type& at(key_type const& k) const
{
if (this->size_) {
node_pointer it = this->find_node(k);
if (it) return it->value();
iterator it = this->find_node(k);
if (it.node_) return *it;
}
boost::throw_exception(
@ -259,9 +267,10 @@ namespace boost { namespace unordered { namespace detail {
std::pair<iterator, iterator>
equal_range(key_type const& k) const
{
node_pointer n = this->find_node(k);
return std::make_pair(iterator(n),
iterator(n ? static_cast<node_pointer>(n->next_) : n));
iterator n = this->find_node(k);
iterator n2 = n;
if (n2.node_) ++n2;
return std::make_pair(n, n2);
}
// equals
@ -271,17 +280,15 @@ namespace boost { namespace unordered { namespace detail {
if(this->size_ != other.size_) return false;
if(!this->size_) return true;
for(node_pointer n1 = this->get_start(); n1;
n1 = static_cast<node_pointer>(n1->next_))
for(iterator n1 = this->get_start(); n1.node_; ++n1)
{
node_pointer n2 = other.find_matching_node(n1);
iterator n2 = other.find_matching_node(n1);
#if !defined(BOOST_UNORDERED_DEPRECATED_EQUALITY)
if(!n2 || n1->value() != n2->value())
if (!n2.node_ || *n1 != *n2)
return false;
#else
if(!n2 || !extractor::compare_mapped(
n1->value(), n2->value()))
if (!n2.node_ || !extractor::compare_mapped(*n1, *n2))
return false;
#endif
}
@ -291,23 +298,24 @@ namespace boost { namespace unordered { namespace detail {
// Emplace/Insert
inline node_pointer add_node(
inline iterator add_node(
node_constructor& a,
std::size_t hash)
{
node_pointer n = a.release();
n->hash_ = hash;
bucket_pointer b = this->get_bucket(hash % this->bucket_count_);
bucket_pointer b = this->get_bucket(
policy::to_bucket(this->bucket_count_, hash));
if (!b->next_)
{
previous_pointer start_node = this->get_previous_start();
if (start_node->next_) {
this->get_bucket(
static_cast<node_pointer>(start_node->next_)->hash_ %
this->bucket_count_)->next_ = n;
this->get_bucket(policy::to_bucket(this->bucket_count_,
static_cast<node_pointer>(start_node->next_)->hash_)
)->next_ = n;
}
b->next_ = start_node;
@ -321,17 +329,17 @@ namespace boost { namespace unordered { namespace detail {
}
++this->size_;
return n;
return iterator(n);
}
value_type& operator[](key_type const& k)
{
typedef typename value_type::second_type mapped_type;
std::size_t hash = this->hash_function()(k);
node_pointer pos = this->find_node(hash, k);
std::size_t hash = this->hash(k);
iterator pos = this->find_node(hash, k);
if (pos) return pos->value();
if (pos.node_) return *pos;
// Create the node before rehashing in case it throws an
// exception (need strong safety in such a case).
@ -349,7 +357,7 @@ namespace boost { namespace unordered { namespace detail {
#endif
this->reserve_for_insert(this->size_ + 1);
return add_node(a, hash)->value();
return *add_node(a, hash);
}
#if defined(BOOST_NO_RVALUE_REFERENCES)
@ -357,7 +365,7 @@ namespace boost { namespace unordered { namespace detail {
boost::unordered::detail::please_ignore_this_overload> const&)
{
BOOST_ASSERT(false);
return emplace_return(iterator(this->begin()), false);
return emplace_return(this->begin(), false);
}
#endif
@ -389,10 +397,10 @@ namespace boost { namespace unordered { namespace detail {
emplace_return emplace_impl(key_type const& k,
BOOST_UNORDERED_EMPLACE_ARGS)
{
std::size_t hash = this->hash_function()(k);
node_pointer pos = this->find_node(hash, k);
std::size_t hash = this->hash(k);
iterator pos = this->find_node(hash, k);
if (pos) return emplace_return(iterator(pos), false);
if (pos.node_) return emplace_return(pos, false);
// Create the node before rehashing in case it throws an
// exception (need strong safety in such a case).
@ -403,21 +411,21 @@ namespace boost { namespace unordered { namespace detail {
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
this->reserve_for_insert(this->size_ + 1);
return emplace_return(iterator(this->add_node(a, hash)), true);
return emplace_return(this->add_node(a, hash), true);
}
emplace_return emplace_impl_with_node(node_constructor& a)
{
key_type const& k = this->get_key(a.value());
std::size_t hash = this->hash_function()(k);
node_pointer pos = this->find_node(hash, k);
std::size_t hash = this->hash(k);
iterator pos = this->find_node(hash, k);
if (pos) return emplace_return(iterator(pos), false);
if (pos.node_) return emplace_return(pos, false);
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
this->reserve_for_insert(this->size_ + 1);
return emplace_return(iterator(this->add_node(a, hash)), true);
return emplace_return(this->add_node(a, hash), true);
}
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
@ -473,7 +481,7 @@ namespace boost { namespace unordered { namespace detail {
void insert_range_empty(node_constructor& a, key_type const& k,
InputIt i, InputIt j)
{
std::size_t hash = this->hash_function()(k);
std::size_t hash = this->hash(k);
a.construct_node();
a.construct_value2(*i);
this->reserve_for_insert(this->size_ +
@ -486,10 +494,10 @@ namespace boost { namespace unordered { namespace detail {
InputIt i, InputIt j)
{
// No side effects in this initial code
std::size_t hash = this->hash_function()(k);
node_pointer pos = this->find_node(hash, k);
std::size_t hash = this->hash(k);
iterator pos = this->find_node(hash, k);
if (!pos) {
if (!pos.node_) {
a.construct_node();
a.construct_value2(*i);
@ -523,8 +531,9 @@ namespace boost { namespace unordered { namespace detail {
{
if(!this->size_) return 0;
std::size_t hash = this->hash_function()(k);
std::size_t bucket_index = hash % this->bucket_count_;
std::size_t hash = this->hash(k);
std::size_t bucket_index =
policy::to_bucket(this->bucket_count_, hash);
bucket_pointer bucket = this->get_bucket(bucket_index);
previous_pointer prev = bucket->next_;
@ -535,7 +544,8 @@ namespace boost { namespace unordered { namespace detail {
if (!prev->next_) return 0;
std::size_t node_hash =
static_cast<node_pointer>(prev->next_)->hash_;
if (node_hash % this->bucket_count_ != bucket_index)
if (policy::to_bucket(this->bucket_count_, node_hash)
!= bucket_index)
return 0;
if (node_hash == hash &&
this->key_eq()(k, this->get_key(
@ -548,36 +558,38 @@ namespace boost { namespace unordered { namespace detail {
node_pointer end = static_cast<node_pointer>(pos->next_);
prev->next_ = pos->next_;
this->fix_buckets(bucket, prev, end);
return this->delete_nodes(pos, end);
return this->delete_nodes(c_iterator(pos), c_iterator(end));
}
node_pointer erase(node_pointer r)
iterator erase(c_iterator r)
{
BOOST_ASSERT(r);
node_pointer next = static_cast<node_pointer>(r->next_);
BOOST_ASSERT(r.node_);
iterator next(r.node_);
++next;
bucket_pointer bucket = this->get_bucket(
r->hash_ % this->bucket_count_);
previous_pointer prev = unlink_node(*bucket, r);
policy::to_bucket(this->bucket_count_, r.node_->hash_));
previous_pointer prev = unlink_node(*bucket, r.node_);
this->fix_buckets(bucket, prev, next);
this->fix_buckets(bucket, prev, next.node_);
this->delete_node(r);
return next;
}
node_pointer erase_range(node_pointer r1, node_pointer r2)
iterator erase_range(c_iterator r1, c_iterator r2)
{
if (r1 == r2) return r2;
if (r1 == r2) return iterator(r2.node_);
std::size_t bucket_index = r1->hash_ % this->bucket_count_;
std::size_t bucket_index =
policy::to_bucket(this->bucket_count_, r1.node_->hash_);
previous_pointer prev = unlink_nodes(
*this->get_bucket(bucket_index), r1, r2);
this->fix_buckets_range(bucket_index, prev, r1, r2);
*this->get_bucket(bucket_index), r1.node_, r2.node_);
this->fix_buckets_range(bucket_index, prev, r1.node_, r2.node_);
this->delete_nodes(r1, r2);
return r2;
return iterator(r2.node_);
}
static previous_pointer unlink_node(bucket& b, node_pointer n)
@ -610,18 +622,18 @@ namespace boost { namespace unordered { namespace detail {
node_constructor a(dst.node_alloc());
node_pointer n = src.get_start();
iterator n = src.get_start();
previous_pointer prev = dst.get_previous_start();
while(n) {
while(n.node_) {
a.construct_node();
a.construct_value2(n->value());
a.construct_value2(*n);
node_pointer node = a.release();
node->hash_ = n->hash_;
node->hash_ = n.node_->hash_;
prev->next_ = static_cast<link_pointer>(node);
++dst.size_;
n = static_cast<node_pointer>(n->next_);
++n;
prev = place_in_bucket(dst, prev);
}
@ -641,18 +653,18 @@ namespace boost { namespace unordered { namespace detail {
node_constructor a(dst.node_alloc());
node_pointer n = src.get_start();
iterator n = src.get_start();
previous_pointer prev = dst.get_previous_start();
while(n) {
while (n.node_) {
a.construct_node();
a.construct_value2(boost::move(n->value()));
a.construct_value2(boost::move(*n));
node_pointer node = a.release();
node->hash_ = n->hash_;
node->hash_ = n.node_->hash_;
prev->next_ = static_cast<link_pointer>(node);
++dst.size_;
n = static_cast<node_pointer>(n->next_);
++n;
prev = place_in_bucket(dst, prev);
}
@ -689,7 +701,8 @@ namespace boost { namespace unordered { namespace detail {
previous_pointer prev)
{
node_pointer n = static_cast<node_pointer>(prev->next_);
bucket_pointer b = dst.get_bucket(n->hash_ % dst.bucket_count_);
bucket_pointer b = dst.get_bucket(
buckets::to_bucket(dst.bucket_count_, n->hash_));
if (!b->next_) {
b->next_ = prev;

View File

@ -203,12 +203,12 @@ namespace unordered
iterator begin()
{
return iterator(table_.begin());
return table_.begin();
}
const_iterator begin() const
{
return const_iterator(table_.begin());
return table_.begin();
}
iterator end()
@ -223,7 +223,7 @@ namespace unordered
const_iterator cbegin() const
{
return const_iterator(table_.begin());
return table_.begin();
}
const_iterator cend() const
@ -465,7 +465,8 @@ namespace unordered
size_type bucket(const key_type& k) const
{
return table_.hash_function()(k) % table_.bucket_count_;
return table::to_bucket(table_.bucket_count_,
table_.hash(k));
}
local_iterator begin(size_type n)
@ -688,12 +689,12 @@ namespace unordered
iterator begin()
{
return iterator(table_.begin());
return table_.begin();
}
const_iterator begin() const
{
return const_iterator(table_.begin());
return table_.begin();
}
iterator end()
@ -708,7 +709,7 @@ namespace unordered
const_iterator cbegin() const
{
return const_iterator(table_.begin());
return table_.begin();
}
const_iterator cend() const
@ -946,7 +947,8 @@ namespace unordered
size_type bucket(const key_type& k) const
{
return table_.hash_function()(k) % table_.bucket_count_;
return table::to_bucket(table_.bucket_count_,
table_.hash(k));
}
local_iterator begin(size_type n)
@ -1139,7 +1141,7 @@ namespace unordered
typename unordered_map<K,T,H,P,A>::iterator
unordered_map<K,T,H,P,A>::erase(const_iterator position)
{
return iterator(table_.erase(position.node_));
return table_.erase(position);
}
template <class K, class T, class H, class P, class A>
@ -1154,7 +1156,7 @@ namespace unordered
unordered_map<K,T,H,P,A>::erase(
const_iterator first, const_iterator last)
{
return iterator(table_.erase_range(first.node_, last.node_));
return table_.erase_range(first, last);
}
template <class K, class T, class H, class P, class A>
@ -1212,14 +1214,14 @@ namespace unordered
typename unordered_map<K,T,H,P,A>::iterator
unordered_map<K,T,H,P,A>::find(const key_type& k)
{
return iterator(table_.find_node(k));
return table_.find_node(k);
}
template <class K, class T, class H, class P, class A>
typename unordered_map<K,T,H,P,A>::const_iterator
unordered_map<K,T,H,P,A>::find(const key_type& k) const
{
return const_iterator(table_.find_node(k));
return table_.find_node(k);
}
template <class K, class T, class H, class P, class A>
@ -1231,7 +1233,7 @@ namespace unordered
CompatibleHash const& hash,
CompatiblePredicate const& eq)
{
return iterator(table_.generic_find_node(k, hash, eq));
return table_.generic_find_node(k, hash, eq);
}
template <class K, class T, class H, class P, class A>
@ -1243,7 +1245,7 @@ namespace unordered
CompatibleHash const& hash,
CompatiblePredicate const& eq) const
{
return const_iterator(table_.generic_find_node(k, hash, eq));
return table_.generic_find_node(k, hash, eq);
}
template <class K, class T, class H, class P, class A>
@ -1466,7 +1468,7 @@ namespace unordered
typename unordered_multimap<K,T,H,P,A>::iterator
unordered_multimap<K,T,H,P,A>::erase(const_iterator position)
{
return iterator(table_.erase(position.node_));
return table_.erase(position);
}
template <class K, class T, class H, class P, class A>
@ -1481,7 +1483,7 @@ namespace unordered
unordered_multimap<K,T,H,P,A>::erase(
const_iterator first, const_iterator last)
{
return iterator(table_.erase_range(first.node_, last.node_));
return table_.erase_range(first, last);
}
template <class K, class T, class H, class P, class A>
@ -1518,14 +1520,14 @@ namespace unordered
typename unordered_multimap<K,T,H,P,A>::iterator
unordered_multimap<K,T,H,P,A>::find(const key_type& k)
{
return iterator(table_.find_node(k));
return table_.find_node(k);
}
template <class K, class T, class H, class P, class A>
typename unordered_multimap<K,T,H,P,A>::const_iterator
unordered_multimap<K,T,H,P,A>::find(const key_type& k) const
{
return const_iterator(table_.find_node(k));
return table_.find_node(k);
}
template <class K, class T, class H, class P, class A>
@ -1537,7 +1539,7 @@ namespace unordered
CompatibleHash const& hash,
CompatiblePredicate const& eq)
{
return iterator(table_.generic_find_node(k, hash, eq));
return table_.generic_find_node(k, hash, eq);
}
template <class K, class T, class H, class P, class A>
@ -1549,7 +1551,7 @@ namespace unordered
CompatibleHash const& hash,
CompatiblePredicate const& eq) const
{
return const_iterator(table_.generic_find_node(k, hash, eq));
return table_.generic_find_node(k, hash, eq);
}
template <class K, class T, class H, class P, class A>

View File

@ -10,12 +10,23 @@
# pragma once
#endif
#include <boost/config.hpp>
#include <memory>
#include <functional>
#include <boost/functional/hash_fwd.hpp>
#include <boost/unordered/detail/fwd.hpp>
namespace boost
{
namespace unordered
{
template <class K,
class T,
class H = boost::hash<K>,
class P = std::equal_to<K>,
class A = std::allocator<std::pair<const K, T> > >
class unordered_map;
template <class K, class T, class H, class P, class A>
inline bool operator==(unordered_map<K, T, H, P, A> const&,
unordered_map<K, T, H, P, A> const&);
@ -26,6 +37,13 @@ namespace boost
inline void swap(unordered_map<K, T, H, P, A>&,
unordered_map<K, T, H, P, A>&);
template <class K,
class T,
class H = boost::hash<K>,
class P = std::equal_to<K>,
class A = std::allocator<std::pair<const K, T> > >
class unordered_multimap;
template <class K, class T, class H, class P, class A>
inline bool operator==(unordered_multimap<K, T, H, P, A> const&,
unordered_multimap<K, T, H, P, A> const&);

View File

@ -201,12 +201,12 @@ namespace unordered
iterator begin()
{
return iterator(table_.begin());
return table_.begin();
}
const_iterator begin() const
{
return const_iterator(table_.begin());
return table_.begin();
}
iterator end()
@ -221,7 +221,7 @@ namespace unordered
const_iterator cbegin() const
{
return const_iterator(table_.begin());
return table_.begin();
}
const_iterator cend() const
@ -450,7 +450,8 @@ namespace unordered
size_type bucket(const key_type& k) const
{
return table_.hash_function()(k) % table_.bucket_count_;
return table::to_bucket(table_.bucket_count_,
table_.hash(k));
}
local_iterator begin(size_type n)
@ -921,7 +922,8 @@ namespace unordered
size_type bucket(const key_type& k) const
{
return table_.hash_function()(k) % table_.bucket_count_;
return table::to_bucket(table_.bucket_count_,
table_.hash(k));
}
local_iterator begin(size_type n)
@ -1114,7 +1116,7 @@ namespace unordered
typename unordered_set<T,H,P,A>::iterator
unordered_set<T,H,P,A>::erase(const_iterator position)
{
return iterator(table_.erase(position.node_));
return table_.erase(position);
}
template <class T, class H, class P, class A>
@ -1129,7 +1131,7 @@ namespace unordered
unordered_set<T,H,P,A>::erase(
const_iterator first, const_iterator last)
{
return iterator(table_.erase_range(first.node_, last.node_));
return table_.erase_range(first, last);
}
template <class T, class H, class P, class A>
@ -1166,7 +1168,7 @@ namespace unordered
typename unordered_set<T,H,P,A>::const_iterator
unordered_set<T,H,P,A>::find(const key_type& k) const
{
return const_iterator(table_.find_node(k));
return table_.find_node(k);
}
template <class T, class H, class P, class A>
@ -1178,7 +1180,7 @@ namespace unordered
CompatibleHash const& hash,
CompatiblePredicate const& eq) const
{
return const_iterator(table_.generic_find_node(k, hash, eq));
return table_.generic_find_node(k, hash, eq);
}
template <class T, class H, class P, class A>
@ -1392,7 +1394,7 @@ namespace unordered
typename unordered_multiset<T,H,P,A>::iterator
unordered_multiset<T,H,P,A>::erase(const_iterator position)
{
return iterator(table_.erase(position.node_));
return table_.erase(position);
}
template <class T, class H, class P, class A>
@ -1407,7 +1409,7 @@ namespace unordered
unordered_multiset<T,H,P,A>::erase(
const_iterator first, const_iterator last)
{
return iterator(table_.erase_range(first.node_, last.node_));
return table_.erase_range(first, last);
}
template <class T, class H, class P, class A>
@ -1444,7 +1446,7 @@ namespace unordered
typename unordered_multiset<T,H,P,A>::const_iterator
unordered_multiset<T,H,P,A>::find(const key_type& k) const
{
return const_iterator(table_.find_node(k));
return table_.find_node(k);
}
template <class T, class H, class P, class A>
@ -1456,7 +1458,7 @@ namespace unordered
CompatibleHash const& hash,
CompatiblePredicate const& eq) const
{
return const_iterator(table_.generic_find_node(k, hash, eq));
return table_.generic_find_node(k, hash, eq);
}
template <class T, class H, class P, class A>

View File

@ -10,12 +10,22 @@
# pragma once
#endif
#include <boost/config.hpp>
#include <memory>
#include <functional>
#include <boost/functional/hash_fwd.hpp>
#include <boost/unordered/detail/fwd.hpp>
namespace boost
{
namespace unordered
{
template <class T,
class H = boost::hash<T>,
class P = std::equal_to<T>,
class A = std::allocator<T> >
class unordered_set;
template <class T, class H, class P, class A>
inline bool operator==(unordered_set<T, H, P, A> const&,
unordered_set<T, H, P, A> const&);
@ -26,6 +36,12 @@ namespace boost
inline void swap(unordered_set<T, H, P, A> &m1,
unordered_set<T, H, P, A> &m2);
template <class T,
class H = boost::hash<T>,
class P = std::equal_to<T>,
class A = std::allocator<T> >
class unordered_multiset;
template <class T, class H, class P, class A>
inline bool operator==(unordered_multiset<T, H, P, A> const&,
unordered_multiset<T, H, P, A> const&);

View File

@ -3,8 +3,6 @@
// 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)
#include "../helpers/prefix.hpp"
#include "./containers.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/invariants.hpp"

View File

@ -3,8 +3,6 @@
// 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)
#include "../helpers/prefix.hpp"
#include "./containers.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/input_iterator.hpp"

View File

@ -3,8 +3,10 @@
// 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)
#include "../helpers/prefix.hpp"
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>
#include "../helpers/postfix.hpp"
#include "../objects/exception.hpp"
typedef boost::unordered_set<

View File

@ -3,8 +3,6 @@
// 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)
#include "../helpers/prefix.hpp"
#include "./containers.hpp"
#include "../helpers/random_values.hpp"

View File

@ -3,8 +3,6 @@
// 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)
#include "../helpers/prefix.hpp"
#include "./containers.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/invariants.hpp"

View File

@ -3,8 +3,6 @@
// 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)
#include "../helpers/prefix.hpp"
#include "./containers.hpp"
#include <string>
#include "../helpers/random_values.hpp"

View File

@ -3,8 +3,6 @@
// 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)
#include "../helpers/prefix.hpp"
#include "./containers.hpp"
#include <string>
#include "../helpers/random_values.hpp"

View File

@ -3,8 +3,6 @@
// 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)
#include "../helpers/prefix.hpp"
#include "./containers.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/invariants.hpp"

10
test/helpers/postfix.hpp Normal file
View File

@ -0,0 +1,10 @@
// Copyright 2012 Daniel James.
// 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)
// Include this after the boost headers, but before other test headers.
#if defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif

View File

@ -11,8 +11,8 @@ project unordered-test/unordered
<toolset>intel:<warnings>on
# Would be nice to define -Wundef, but I'm getting warnings from
# Boost.Preprocessor on trunk.
<toolset>gcc:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wno-long-long"
<toolset>darwin:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion"
<toolset>gcc:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wno-long-long -Wfloat-equal"
<toolset>darwin:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal"
#<toolset>gcc:<define>_GLIBCXX_DEBUG
#<toolset>darwin:<define>_GLIBCXX_DEBUG
#<toolset>msvc:<warnings-as-errors>on

View File

@ -90,7 +90,7 @@ void test_empty_allocator()
{
typedef empty_allocator<int> allocator;
typedef boost::unordered::detail::allocator_traits<allocator> traits;
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1
BOOST_MPL_ASSERT((boost::is_same<traits::size_type,
std::make_unsigned<std::ptrdiff_t>::type>));
#else
@ -128,8 +128,8 @@ void test_allocator1()
{
typedef allocator1<int> allocator;
typedef boost::unordered::detail::allocator_traits<allocator> traits;
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS
BOOST_MPL_ASSERT((boost::is_same<typename traits::size_type,
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1
BOOST_MPL_ASSERT((boost::is_same<traits::size_type,
std::make_unsigned<std::ptrdiff_t>::type>));
#else
BOOST_MPL_ASSERT((boost::is_same<traits::size_type, std::size_t>));

View File

@ -4,9 +4,9 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include "../helpers/test.hpp"
#include "../objects/test.hpp"
#include "../objects/cxx11_allocator.hpp"
@ -208,9 +208,7 @@ UNORDERED_AUTO_TEST(assign_default_initializer_list) {
#endif
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) && \
!defined(BOOST_NO_INITIALIZER_LISTS)
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
UNORDERED_AUTO_TEST(assign_initializer_list)
{
std::cerr<<"Initializer List Tests\n";

View File

@ -4,8 +4,9 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "../helpers/prefix.hpp"
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include "../helpers/test.hpp"
#include <string>

View File

@ -4,9 +4,10 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include "../helpers/test.hpp"
#include <algorithm>
#include "../objects/test.hpp"

View File

@ -7,8 +7,8 @@
// requirements. Makes sure everything compiles and is defined correctly.
#include "../helpers/prefix.hpp"
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include <iostream>
#include "../helpers/test.hpp"

View File

@ -7,8 +7,8 @@
// requirements. Makes sure everything compiles and is defined correctly.
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
#include "../helpers/postfix.hpp"
#include <iostream>
#include "../helpers/test.hpp"

View File

@ -4,9 +4,10 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include "../helpers/test.hpp"
#include "../objects/test.hpp"
#include "../helpers/random_values.hpp"
@ -442,8 +443,7 @@ UNORDERED_AUTO_TEST(test_default_initializer_list) {
#endif
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) && \
!defined(BOOST_NO_INITIALIZER_LISTS)
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
UNORDERED_AUTO_TEST(test_initializer_list) {
std::cerr<<"Initializer List Tests\n";

View File

@ -4,9 +4,10 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include "../helpers/test.hpp"
#include "../objects/test.hpp"
#include "../objects/cxx11_allocator.hpp"

View File

@ -6,9 +6,10 @@
#define BOOST_UNORDERED_DEPRECATED_EQUALITY
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include <boost/preprocessor/seq.hpp>
#include <list>
#include "../helpers/test.hpp"

View File

@ -4,9 +4,10 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include <boost/preprocessor/seq.hpp>
#include <list>
#include "../helpers/test.hpp"
@ -149,6 +150,14 @@ namespace equality_tests
((1)(2))((1001)(1)), !=, ((1001)(2))((1)(1)))
}
UNORDERED_AUTO_TEST(equality_multiple_group_test)
{
UNORDERED_EQUALITY_MULTISET_TEST(
(1)(1)(1)(1001)(2001)(2001)(2)(1002)(3)(1003)(2003), ==,
(3)(1003)(2003)(1002)(2)(2001)(2001)(1)(1001)(1)(1)
);
}
// Test that equality still works when the two containers have
// different hash functions but the same equality predicate.
@ -167,7 +176,6 @@ namespace equality_tests
set1.insert(20); set2.insert(10);
BOOST_TEST(set1 == set2);
}
}
RUN_TESTS()

View File

@ -4,9 +4,10 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include "../helpers/test.hpp"
#include <algorithm>
#include <map>

View File

@ -7,8 +7,9 @@
// hairy with several tricky edge cases - so explicitly test each one.
#include "../helpers/prefix.hpp"
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include "../helpers/test.hpp"
#include "../helpers/list.hpp"
#include <set>

View File

@ -4,9 +4,10 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include "../helpers/test.hpp"
#include <boost/next_prior.hpp>
#include "../objects/test.hpp"

View File

@ -4,9 +4,10 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include "../helpers/test.hpp"
#include "../objects/test.hpp"
#include "../helpers/random_values.hpp"

View File

@ -4,8 +4,8 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "../helpers/prefix.hpp"
#include <boost/unordered/unordered_map_fwd.hpp>
#include "../helpers/postfix.hpp"
template <typename T>
void call_swap(boost::unordered_map<T,T>& x,

View File

@ -4,8 +4,8 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "../helpers/prefix.hpp"
#include <boost/unordered/unordered_set_fwd.hpp>
#include "../helpers/postfix.hpp"
struct true_type { char x[100]; };
struct false_type { char x; };

View File

@ -4,10 +4,11 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "../helpers/prefix.hpp"
#include <utility>
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>
#include "../helpers/postfix.hpp"
#include <utility>
namespace x
{

View File

@ -4,9 +4,10 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include "../helpers/test.hpp"
#include <iostream>

View File

@ -4,9 +4,10 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include "../helpers/test.hpp"
#include <boost/next_prior.hpp>
#include "../objects/test.hpp"
@ -465,8 +466,7 @@ UNORDERED_TEST(map_insert_range_test2,
((default_generator)(generate_collisions))
)
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) && \
!defined(BOOST_NO_INITIALIZER_LISTS)
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
UNORDERED_AUTO_TEST(insert_initializer_list_set)
{

View File

@ -4,9 +4,9 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
void foo(boost::unordered_set<int>&,
boost::unordered_map<int, int>&,

View File

@ -4,9 +4,9 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
void foo(boost::unordered_set<int>& x1,
boost::unordered_map<int, int>& x2,

View File

@ -4,9 +4,10 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include "../helpers/test.hpp"
#include <boost/limits.hpp>
#include "../helpers/random_values.hpp"

View File

@ -52,7 +52,7 @@ void test_simple_allocator()
BOOST_MPL_ASSERT((boost::is_same<typename traits::difference_type, std::ptrdiff_t>));
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1
BOOST_MPL_ASSERT((boost::is_same<typename traits::size_type,
std::make_unsigned<std::ptrdiff_t>::type>));
#else

View File

@ -4,9 +4,10 @@
// file LICENSE_1_0.txt or move at http://www.boost.org/LICENSE_1_0.txt)
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include "../helpers/test.hpp"
#include "../objects/test.hpp"
#include "../objects/cxx11_allocator.hpp"

View File

@ -4,9 +4,10 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include "../helpers/test.hpp"
#include "../helpers/random_values.hpp"
#include "../helpers/tracker.hpp"

View File

@ -6,9 +6,10 @@
// This test checks the runtime requirements of containers.
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include "../helpers/test.hpp"
#include <cstdlib>
#include <algorithm>

View File

@ -4,12 +4,13 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include <boost/config.hpp>
#include <algorithm>
#include <iterator>
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include "../helpers/test.hpp"
#include "../objects/test.hpp"
#include "../objects/cxx11_allocator.hpp"

View File

@ -1,12 +1,14 @@
#include <iostream>
// Copyright 2006-2009 Daniel James.
// 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)
#include "../helpers/prefix.hpp"
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include "../helpers/postfix.hpp"
#include <iostream>
#include "../helpers/test.hpp"
#if defined(BOOST_UNORDERED_VARIADIC_MOVE)