Since all the compilers support out of line template members use them

and lots of other things.

[SVN r56329]
This commit is contained in:
Daniel James 2009-09-20 21:55:15 +00:00
parent 491fa330f6
commit 78b078f41d
16 changed files with 2462 additions and 2061 deletions

View File

@ -99,7 +99,8 @@ namespace boost { namespace unordered_detail {
}
private:
allocator_array_constructor(allocator_array_constructor const&);
allocator_array_constructor& operator=(allocator_array_constructor const&);
allocator_array_constructor& operator=(
allocator_array_constructor const&);
};
}}

View File

@ -14,23 +14,123 @@
namespace boost { namespace unordered_detail {
////////////////////////////////////////////////////////////////////////////
// Explicitly call a destructor
#if defined(BOOST_MSVC)
# define BOOST_UNORDERED_DESTRUCT(x, type) (x)->~type();
#else
# define BOOST_UNORDERED_DESTRUCT(x, type) boost::unordered_detail::destroy(x)
template <class T>
void destroy(T* x) {
x->~T();
// Buckets
// TODO: Are these needed?
template <class A, class G>
inline BOOST_DEDUCED_TYPENAME hash_buckets<A, G>::bucket_ptr
hash_buckets<A, G>::get_bucket(std::size_t n) const
{
return buckets_ + static_cast<std::ptrdiff_t>(n);
}
#endif
// Constructors
template <class A, class G>
hash_buckets<A, G>::hash_buckets(node_allocator const& a, std::size_t bucket_count)
: buckets_(), allocators_(a,a)
inline BOOST_DEDUCED_TYPENAME hash_buckets<A, G>::bucket_ptr
hash_buckets<A, G>::bucket_ptr_from_hash(std::size_t hashed) const
{
return get_bucket(hashed % bucket_count_);
}
template <class A, class G>
inline std::size_t hash_buckets<A, G>::bucket_size(std::size_t index) const
{
if(!buckets_) return 0;
bucket_ptr ptr = get_bucket(index)->next_;
std::size_t count = 0;
while(ptr) {
++count;
ptr = ptr->next_;
}
return count;
}
template <class A, class G>
inline BOOST_DEDUCED_TYPENAME hash_buckets<A, G>::node_ptr
hash_buckets<A, G>::bucket_begin(std::size_t n) const
{
return buckets_ ? get_bucket(n)->next_ : node_ptr();
}
////////////////////////////////////////////////////////////////////////////
// Delete
template <class A, class G>
inline void hash_buckets<A, G>::delete_node(node_ptr b)
{
node* raw_ptr = static_cast<node*>(&*b);
boost::unordered_detail::destroy(&raw_ptr->value());
real_node_ptr n(node_alloc().address(*raw_ptr));
node_alloc().destroy(n);
node_alloc().deallocate(n, 1);
}
template <class A, class G>
inline void hash_buckets<A, G>::clear_bucket(bucket_ptr b)
{
node_ptr node_it = b->next_;
b->next_ = node_ptr();
while(node_it) {
node_ptr node_to_delete = node_it;
node_it = node_it->next_;
delete_node(node_to_delete);
}
}
template <class A, class G>
inline void hash_buckets<A, G>::delete_buckets()
{
bucket_ptr end = this->get_bucket(this->bucket_count_);
for(bucket_ptr begin = this->buckets_; begin != end; ++begin) {
clear_bucket(begin);
}
// Destroy the buckets (including the sentinel bucket).
++end;
for(bucket_ptr begin = this->buckets_; begin != end; ++begin) {
bucket_alloc().destroy(begin);
}
bucket_alloc().deallocate(this->buckets_, this->bucket_count_ + 1);
this->buckets_ = bucket_ptr();
}
template <class A, class G>
inline std::size_t hash_buckets<A, G>::delete_nodes(
node_ptr begin, node_ptr end)
{
std::size_t count = 0;
while(begin != end) {
node_ptr node = begin;
begin = begin->next_;
delete_node(node);
++count;
}
return count;
}
////////////////////////////////////////////////////////////////////////////
// Constructors and Destructors
template <class A, class G>
inline hash_buckets<A, G>::hash_buckets(
node_allocator const& a, std::size_t bucket_count)
: buckets_(),
bucket_count_(bucket_count),
allocators_(a,a)
{
}
template <class A, class G>
inline hash_buckets<A, G>::~hash_buckets()
{
if(this->buckets_) { this->delete_buckets(); }
}
template <class A, class G>
inline void hash_buckets<A, G>::create_buckets()
{
// The array constructor will clean up in the event of an
// exception.
@ -38,52 +138,27 @@ namespace boost { namespace unordered_detail {
constructor(bucket_alloc());
// Creates an extra bucket to act as a sentinel.
constructor.construct(bucket(), bucket_count + 1);
constructor.construct(bucket(), this->bucket_count_ + 1);
// Set up the sentinel (node_ptr cast)
bucket_ptr sentinel = constructor.get() + static_cast<ptrdiff_t>(bucket_count);
bucket_ptr sentinel = constructor.get() +
static_cast<ptrdiff_t>(this->bucket_count_);
sentinel->next_ = sentinel;
// Only release the buckets once everything is successfully
// done.
this->buckets_ = constructor.release();
this->bucket_count_ = bucket_count;
}
template <class A, class G>
hash_buckets<A, G>::hash_buckets(hash_buckets& x, move_tag)
: buckets_(), allocators_(x.allocators_)
{
this->buckets_ = x.buckets_;
this->bucket_count_ = x.bucket_count_;
x.buckets_ = bucket_ptr();
x.bucket_count_ = 0;
}
template <class A, class G>
hash_buckets<A, G>::hash_buckets(hash_buckets& x, value_allocator const& a, move_tag) :
buckets_(), allocators_(a,a)
{
if(this->node_alloc() == x.node_alloc()) {
this->buckets_ = x.buckets_;
this->bucket_count_ = x.bucket_count_;
x.buckets_ = bucket_ptr();
x.bucket_count_ = 0;
}
}
template <class A, class G>
hash_buckets<A, G>::~hash_buckets()
{
if(this->buckets_) { delete_buckets(); }
}
////////////////////////////////////////////////////////////////////////////
// Constructors and Destructors
// no throw
template <class A, class G>
inline void hash_buckets<A, G>::move(hash_buckets& other)
{
BOOST_ASSERT(node_alloc() == other.node_alloc());
delete_buckets();
if(this->buckets_) { this->delete_buckets(); }
this->buckets_ = other.buckets_;
this->bucket_count_ = other.bucket_count_;
other.buckets_ = bucket_ptr();
@ -97,166 +172,6 @@ namespace boost { namespace unordered_detail {
std::swap(buckets_, other.buckets_);
std::swap(bucket_count_, other.bucket_count_);
}
// Buckets
template <class A, class G>
inline std::size_t hash_buckets<A, G>::bucket_count() const
{
return bucket_count_;
}
template <class A, class G>
inline std::size_t hash_buckets<A, G>::bucket_from_hash(std::size_t hashed) const
{
return hashed % bucket_count_;
}
template <class A, class G>
inline BOOST_DEDUCED_TYPENAME hash_buckets<A, G>::bucket_ptr
hash_buckets<A, G>::bucket_ptr_from_hash(std::size_t hashed) const
{
return buckets_ + static_cast<std::ptrdiff_t>(
bucket_from_hash(hashed));
}
template <class A, class G>
inline BOOST_DEDUCED_TYPENAME hash_buckets<A, G>::bucket_ptr
hash_buckets<A, G>::buckets_begin() const
{
return buckets_;
}
template <class A, class G>
inline BOOST_DEDUCED_TYPENAME hash_buckets<A, G>::bucket_ptr
hash_buckets<A, G>::buckets_end() const
{
return buckets_ + static_cast<std::ptrdiff_t>(bucket_count_);
}
template <class A, class G>
inline std::size_t hash_buckets<A, G>::bucket_size(std::size_t index) const
{
bucket_ptr ptr = (buckets_ + static_cast<std::ptrdiff_t>(index))->next_;
std::size_t count = 0;
while(ptr) {
++count;
ptr = next_node(ptr);
}
return count;
}
template <class A, class G>
inline BOOST_DEDUCED_TYPENAME hash_buckets<A, G>::bucket_ptr
hash_buckets<A, G>::get_bucket(std::size_t n) const
{
return buckets_ + static_cast<std::ptrdiff_t>(n);
}
template <class A, class G>
inline BOOST_DEDUCED_TYPENAME hash_buckets<A, G>::node_ptr
hash_buckets<A, G>::bucket_begin(std::size_t n) const
{
return (buckets_ + static_cast<std::ptrdiff_t>(n))->next_;
}
template <class A, class G>
inline BOOST_DEDUCED_TYPENAME hash_buckets<A, G>::node_ptr
hash_buckets<A, G>::bucket_end(std::size_t) const
{
return node_ptr();
}
// Construct/destruct
template <class A, class G>
inline void hash_buckets<A, G>::destruct_node(node_ptr b)
{
node* raw_ptr = static_cast<node*>(&*b);
BOOST_UNORDERED_DESTRUCT(&raw_ptr->value(), value_type);
real_node_ptr n(node_alloc().address(*raw_ptr));
node_alloc().destroy(n);
node_alloc().deallocate(n, 1);
}
// Delete and clear buckets
template <class A, class G>
inline void hash_buckets<A, G>::delete_group(node_ptr first_node)
{
delete_nodes(first_node, node::next_group(first_node));
}
template <class A, class G>
inline void hash_buckets<A, G>::delete_nodes(node_ptr begin, node_ptr end)
{
while(begin != end) {
node_ptr node = begin;
begin = next_node(begin);
destruct_node(node);
}
}
template <class A, class G>
inline void hash_buckets<A, G>::delete_to_bucket_end(node_ptr begin)
{
while(BOOST_UNORDERED_BORLAND_BOOL(begin)) {
node_ptr node = begin;
begin = next_node(begin);
destruct_node(node);
}
}
template <class A, class G>
inline void hash_buckets<A, G>::clear_bucket(bucket_ptr b)
{
node_ptr node_it = b->next_;
b->next_ = node_ptr();
while(node_it) {
node_ptr node_to_destruct = node_it;
node_it = next_node(node_it);
destruct_node(node_to_destruct);
}
}
template <class A, class G>
inline void hash_buckets<A, G>::delete_buckets()
{
for(bucket_ptr begin = this->buckets_begin(), end = this->buckets_end(); begin != end; ++begin) {
clear_bucket(begin);
}
// Destroy the buckets (including the sentinel bucket).
bucket_ptr end = this->buckets_end();
++end;
for(bucket_ptr begin = this->buckets_begin(); begin != end; ++begin) {
bucket_alloc().destroy(begin);
}
bucket_alloc().deallocate(this->buckets_begin(), this->bucket_count() + 1);
this->buckets_ = bucket_ptr();
}
////////////////////////////////////////////////////////////////////////////
// hash_iterator_base implementation
template <class BucketPtr>
inline void hash_iterator_base<BucketPtr>::increment(node_ptr node) {
while(!node) {
++bucket_;
node = bucket_->next_;
}
node_ = node;
}
template <class BucketPtr>
inline void hash_iterator_base<BucketPtr>::increment()
{
increment(next_node(node_));
}
}}
#endif

View File

@ -0,0 +1,271 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-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)
#ifndef BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED
#define BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED
#include <boost/unordered/detail/table.hpp>
#include <boost/unordered/detail/extract_key.hpp>
namespace boost { namespace unordered_detail {
////////////////////////////////////////////////////////////////////////////
// Equality
template <class H, class P, class A, class K>
bool hash_equivalent_table<H, P, A, K>
::equals(hash_equivalent_table<H, P, A, K> const& other) const
{
if(this->size_ != other.size_) return false;
if(!this->size_) return true;
bucket_ptr end = this->get_bucket(this->bucket_count_);
for(bucket_ptr i = this->cached_begin_bucket_; i != end; ++i)
{
node_ptr it1 = i->next_;
while(BOOST_UNORDERED_BORLAND_BOOL(it1))
{
node_ptr it2 = other.find_iterator(get_key_from_ptr(it1));
if(!BOOST_UNORDERED_BORLAND_BOOL(it2)) return false;
node_ptr end1 = node::next_group(it1);
node_ptr end2 = node::next_group(it2);
do {
if(!extractor::compare_mapped(
node::get_value(it1), node::get_value(it2)))
return false;
it1 = it1->next_;
it2 = it2->next_;
} while(it1 != end1 && it2 != end2);
if(it1 != end1 || it2 != end2) return false;
}
}
return true;
}
////////////////////////////////////////////////////////////////////////////
// A convenience method for adding nodes.
template <class H, class P, class A, class K>
inline BOOST_DEDUCED_TYPENAME hash_equivalent_table<H, P, A, K>::node_ptr
hash_equivalent_table<H, P, A, K>
::add_node(node_constructor& a, bucket_ptr bucket, node_ptr pos)
{
node_ptr n = a.release();
if(BOOST_UNORDERED_BORLAND_BOOL(pos)) {
node::add_after_node(n, pos);
}
else {
node::add_to_bucket(n, *bucket);
if(bucket < this->cached_begin_bucket_)
this->cached_begin_bucket_ = bucket;
}
++this->size_;
return n;
}
////////////////////////////////////////////////////////////////////////////
// Insert methods
template <class H, class P, class A, class K>
inline BOOST_DEDUCED_TYPENAME
hash_equivalent_table<H, P, A, K>::iterator_base
hash_equivalent_table<H, P, A, K>::emplace_impl(node_constructor& a)
{
key_type const& k = get_key(a.value());
std::size_t hash_value = this->hash_function()(k);
if(!this->size_) {
return this->emplace_empty_impl_with_node(a, 1);
}
else {
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
node_ptr position = find_iterator(bucket, k);
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
if(this->reserve_for_insert(this->size_ + 1))
bucket = this->bucket_ptr_from_hash(hash_value);
return iterator_base(bucket, add_node(a, bucket, position));
}
}
template <class H, class P, class A, class K>
inline BOOST_DEDUCED_TYPENAME
hash_equivalent_table<H, P, A, K>::iterator_base
hash_equivalent_table<H, P, A, K>
::emplace_hint_impl(iterator_base const& it, node_constructor& a)
{
// equal can throw, but with no effects
if (!it.node_ || !equal(get_key(a.value()), *it)) {
// Use the standard emplace if the iterator doesn't point
// to a matching key.
return emplace_impl(a);
}
else {
// Find the first node in the group - so that the node
// will be added at the end of the group.
node_ptr start = node::first_in_group(it.node_);
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
bucket_ptr bucket = this->reserve_for_insert(this->size_ + 1) ?
get_bucket(this->bucket_index(get_key(a.value()))) :
it.bucket_;
// Nothing after this point can throw
return iterator_base(bucket, add_node(a, bucket, start));
}
}
template <class H, class P, class A, class K>
inline void hash_equivalent_table<H, P, A, K>
::emplace_impl_no_rehash(node_constructor& a)
{
key_type const& k = get_key(a.value());
bucket_ptr bucket = this->get_bucket(this->bucket_index(k));
add_node(a, bucket, find_iterator(bucket, k));
}
#if defined(BOOST_UNORDERED_STD_FORWARD)
// Emplace (equivalent key containers)
// (I'm using an overloaded emplace for both 'insert' and 'emplace')
// if hash function throws, basic exception safety
// strong otherwise
template <class H, class P, class A, class K>
template <class... Args>
BOOST_DEDUCED_TYPENAME hash_equivalent_table<H, P, A, K>::iterator_base
hash_equivalent_table<H, P, A, K>
::emplace(Args&&... args)
{
// Create the node before rehashing in case it throws an
// exception (need strong safety in such a case).
node_constructor a(*this);
a.construct(std::forward<Args>(args)...);
return emplace_impl(a);
}
// Emplace (equivalent key containers)
// (I'm using an overloaded emplace for both 'insert' and 'emplace')
// if hash function throws, basic exception safety
// strong otherwise
template <class H, class P, class A, class K>
template <class... Args>
BOOST_DEDUCED_TYPENAME hash_equivalent_table<H, P, A, K>::iterator_base
hash_equivalent_table<H, P, A, K>
::emplace_hint(iterator_base const& it, Args&&... args)
{
// Create the node before rehashing in case it throws an
// exception (need strong safety in such a case).
node_constructor a(*this);
a.construct(std::forward<Args>(args)...);
return emplace_hint_impl(it, a);
}
#else
#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \
template <class H, class P, class A, class K> \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
BOOST_DEDUCED_TYPENAME hash_equivalent_table<H, P, A, K>::iterator_base \
hash_equivalent_table<H, P, A, K> \
::emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
{ \
node_constructor a(*this); \
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \
return emplace_impl(a); \
} \
\
template <class H, class P, class A, class K> \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
BOOST_DEDUCED_TYPENAME hash_equivalent_table<H, P, A, K>::iterator_base \
hash_equivalent_table<H, P, A, K> \
::emplace_hint(iterator_base const& it, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
{ \
node_constructor a(*this); \
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \
return emplace_hint_impl(it, a); \
}
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_INSERT_IMPL, _)
#undef BOOST_UNORDERED_INSERT_IMPL
#endif
////////////////////////////////////////////////////////////////////////////
// Insert range methods
// if hash function throws, or inserting > 1 element, basic exception safety
// strong otherwise
template <class H, class P, class A, class K>
template <class I>
inline void hash_equivalent_table<H, P, A, K>
::insert_for_range(I i, I j, forward_traversal_tag)
{
if(i == j) return;
std::size_t distance = unordered_detail::distance(i, j);
if(distance == 1) {
emplace(*i);
}
else {
node_constructor a(*this);
// Only require basic exception safety here
if(this->size_) {
this->reserve_for_insert(this->size_ + distance);
}
else {
a.construct(*i++);
this->emplace_empty_impl_with_node(a, distance);
}
for (; i != j; ++i) {
a.construct(*i);
emplace_impl_no_rehash(a);
}
}
}
// if hash function throws, or inserting > 1 element, basic exception safety
// strong otherwise
template <class H, class P, class A, class K>
template <class I>
inline void hash_equivalent_table<H, P, A, K>
::insert_for_range(I i, I j, boost::incrementable_traversal_tag)
{
node_constructor a(*this);
for (; i != j; ++i) {
a.construct(*i);
emplace_impl(a);
}
}
// if hash function throws, or inserting > 1 element, basic exception safety
// strong otherwise
// TODO: Should I special case an empty container?
template <class H, class P, class A, class K>
template <class I>
void hash_equivalent_table<H, P, A, K>::insert_range(I i, I j)
{
BOOST_DEDUCED_TYPENAME boost::iterator_traversal<I>::type
iterator_traversal_tag;
insert_for_range(i, j, iterator_traversal_tag);
}
}}
#endif

View File

@ -66,6 +66,11 @@ namespace unordered_detail {
return no_key();
}
#endif
static bool compare_mapped(value_type const&, value_type const&)
{
return true;
}
};
};
@ -75,7 +80,9 @@ namespace unordered_detail {
struct apply
{
typedef ValueType value_type;
typedef BOOST_DEDUCED_TYPENAME remove_const<BOOST_DEDUCED_TYPENAME ValueType::first_type>::type key_type;
typedef BOOST_DEDUCED_TYPENAME
remove_const<BOOST_DEDUCED_TYPENAME ValueType::first_type>::type
key_type;
static key_type const& extract(value_type const& v)
{
@ -94,19 +101,22 @@ namespace unordered_detail {
}
template <class Second>
static key_type const& extract(std::pair<key_type const, Second> const& v)
static key_type const& extract(
std::pair<key_type const, Second> const& v)
{
return v.first;
}
/*
template <class Second>
static key_type const& extract(std::pair<key_type&, Second> const& v)
static key_type const& extract(
std::pair<key_type&, Second> const& v)
{
return v.first;
}
template <class Second>
static key_type const& extract(std::pair<key_type const&, Second> const& v)
static key_type const& extract(
std::pair<key_type const&, Second> const& v)
{
return v.first;
}
@ -114,7 +124,8 @@ namespace unordered_detail {
#if defined(BOOST_UNORDERED_STD_FORWARD)
template <class Arg1, class... Args>
static key_type const& extract(key_type const& k, Arg1 const&, Args const&...)
static key_type const& extract(key_type const& k,
Arg1 const&, Args const&...)
{
return k;
}
@ -149,6 +160,10 @@ namespace unordered_detail {
}
#endif
static bool compare_mapped(value_type const& x, value_type const& y)
{
return x.second == y.second;
}
};
};
}}

View File

@ -18,6 +18,7 @@
#include <boost/type_traits/aligned_storage.hpp>
#include <boost/type_traits/alignment_of.hpp>
#include <boost/unordered/detail/allocator_helpers.hpp>
#include <algorithm>
// This header defines most of the classes used to implement the unordered
// containers. It doesn't include the insert methods as they require a lot
@ -31,8 +32,6 @@
// G = Grouped/Ungrouped
// K = Key Extractor
#include <boost/config.hpp>
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
# if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)
// STLport doesn't have std::forward.
@ -45,12 +44,51 @@
#define BOOST_UNORDERED_EMPLACE_LIMIT 10
#endif
#if !defined(BOOST_UNORDERED_STD_FORWARD)
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#define BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
BOOST_PP_ENUM_PARAMS_Z(z, n, class Arg)
#define BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, Arg, const& arg)
#define BOOST_UNORDERED_CALL_PARAMS(z, n) \
BOOST_PP_ENUM_PARAMS_Z(z, n, arg)
#endif
namespace boost { namespace unordered_detail {
static const float minimum_max_load_factor = 1e-3f;
static const std::size_t default_initial_bucket_count = 11;
static const std::size_t default_bucket_count = 11;
struct move_tag {};
template <class Alloc, class Grouped>
class hash_node_constructor;
struct set_extractor;
struct map_extractor;
struct no_key;
// Explicitly call a destructor
#if defined(BOOST_MSVC)
#pragma warning(push)
#if BOOST_MSVC >= 1400
#pragma warning(disable:4100) // unreferenced formal parameter
#endif
#endif
template <class T>
inline void destroy(T* x) {
x->~T();
}
#if defined(BOOST_MSVC)
#pragma warning(pop)
#endif
// hash_bucket
template <class A>
@ -70,8 +108,11 @@ namespace boost { namespace unordered_detail {
hash_bucket() : next_() {}
// Only copy construct when allocating.
hash_bucket(hash_bucket const& x) : next_()
{ BOOST_ASSERT(!x.next_); }
hash_bucket(hash_bucket const& x)
: next_()
{
BOOST_ASSERT(!x.next_);
}
};
template <class A>
@ -84,12 +125,10 @@ namespace boost { namespace unordered_detail {
static inline node_ptr& next_group(node_ptr ptr);
static inline std::size_t group_count(node_ptr ptr);
static inline void add_to_bucket(node_ptr n, bucket& b);
static inline void add_group_to_bucket(node_ptr n, bucket& b);
static inline void add_after_node(node_ptr n, node_ptr position);
static void unlink_node(bucket& b, node_ptr node);
static void unlink_nodes(bucket& b, node_ptr begin, node_ptr end);
static void unlink_nodes(bucket& b, node_ptr end);
static inline void unlink_group(node_ptr* b);
};
template <class A>
@ -102,21 +141,20 @@ namespace boost { namespace unordered_detail {
node_ptr group_prev_;
grouped_node_base() : bucket(), group_prev_() {}
static inline node_ptr& group_prev(node_ptr ptr);
static inline node_ptr& next_group(node_ptr ptr);
static inline node_ptr first_in_group(node_ptr n);
static inline std::size_t group_count(node_ptr ptr);
static inline void add_to_bucket(node_ptr n, bucket& b);
static inline void add_group_to_bucket(node_ptr n, bucket& b);
static inline void add_after_node(node_ptr n, node_ptr position);
static void unlink_node(bucket& b, node_ptr node);
static void unlink_nodes(bucket& b, node_ptr begin, node_ptr end);
static void unlink_nodes(bucket& b, node_ptr end);
static inline void unlink_group(node_ptr* b);
private:
static inline node_ptr split_group(node_ptr split);
static inline grouped_node_base& get(node_ptr ptr)
{ return static_cast<grouped_node_base&>(*ptr); }
static inline grouped_node_base& get(node_ptr ptr) {
return static_cast<grouped_node_base&>(*ptr);
}
};
struct ungrouped
@ -143,44 +181,73 @@ namespace boost { namespace unordered_detail {
sizeof(value_type),
::boost::alignment_of<value_type>::value>::type data_;
void* address() { return this; }
value_type& value() { return *(ValueType*) this; }
void* address() {
return this;
}
value_type& value() {
return *(ValueType*) this;
}
};
// Node
template <class NodeBase, class ValueType>
class hash_node : public NodeBase, public value_base<ValueType>
template <class A, class G>
class hash_node :
public G::BOOST_NESTED_TEMPLATE base<A>::type,
public value_base<BOOST_DEDUCED_TYPENAME A::value_type>
{
public:
typedef ValueType value_type;
typedef BOOST_DEDUCED_TYPENAME NodeBase::node_ptr node_ptr;
typedef BOOST_DEDUCED_TYPENAME A::value_type value_type;
typedef BOOST_DEDUCED_TYPENAME hash_bucket<A>::node_ptr node_ptr;
static value_type& get_value(node_ptr p) { return static_cast<hash_node&>(*p).value(); }
static value_type& get_value(node_ptr p) {
return static_cast<hash_node&>(*p).value();
}
};
// Iterator Base
template <class BucketPtr>
template <class A, class G>
class hash_iterator_base
{
public:
typedef BucketPtr bucket_ptr;
typedef BucketPtr node_ptr;
typedef A value_allocator;
typedef hash_bucket<A> bucket;
typedef hash_node<A, G> node;
typedef BOOST_DEDUCED_TYPENAME node::value_type value_type;
typedef BOOST_DEDUCED_TYPENAME node::bucket_ptr bucket_ptr;
typedef BOOST_DEDUCED_TYPENAME node::node_ptr node_ptr;
bucket_ptr bucket_;
node_ptr node_;
hash_iterator_base() : bucket_(), node_() {}
explicit hash_iterator_base(bucket_ptr b) : bucket_(b), node_(b->next_) {}
hash_iterator_base(bucket_ptr b, node_ptr n) : bucket_(b), node_(n) {}
explicit hash_iterator_base(bucket_ptr b)
: bucket_(b),
node_(b ? b->next_ : node_ptr()) {}
hash_iterator_base(bucket_ptr b, node_ptr n)
: bucket_(b),
node_(n) {}
bool operator==(hash_iterator_base const& x) const { return node_ == x.node_; }
bool operator!=(hash_iterator_base const& x) const { return node_ != x.node_; }
bool is_end() const { return node_ == bucket_; }
node_ptr get() const { return node_; }
void increment(node_ptr node);
void increment();
bool operator==(hash_iterator_base const& x) const {
return node_ == x.node_; }
bool operator!=(hash_iterator_base const& x) const {
return node_ != x.node_; }
value_type& operator*() const {
return node::get_value(node_);
}
void increment_bucket(node_ptr node) {
while(!node) {
++bucket_;
node = bucket_->next_;
}
node_ = bucket_ == node ? node_ptr() : node;
}
void increment() {
increment_bucket(node_->next_);
}
};
// hash_buckets
@ -188,9 +255,10 @@ namespace boost { namespace unordered_detail {
// This is responsible for allocating and deallocating buckets and nodes.
//
// Notes:
// 1. For the sake exception safety the allocators themselves don't allocate anything.
// 2. It's the callers responsibility to allocate the buckets before calling any of the
// methods (other than getters and setters).
// 1. For the sake exception safety the allocators themselves don't allocate
// anything.
// 2. It's the callers responsibility to allocate the buckets before calling
// any of the methods (other than getters and setters).
template <class A, class G>
class hash_buckets
@ -201,22 +269,19 @@ namespace boost { namespace unordered_detail {
// Types
typedef A value_allocator;
typedef BOOST_DEDUCED_TYPENAME A::value_type value_type;
typedef hash_bucket<A> bucket;
typedef BOOST_DEDUCED_TYPENAME G::BOOST_NESTED_TEMPLATE base<A>::type
node_base;
typedef hash_node<node_base, value_type> node;
typedef hash_iterator_base<A, G> iterator_base;
typedef BOOST_DEDUCED_TYPENAME A::value_type value_type;
typedef BOOST_DEDUCED_TYPENAME iterator_base::node node;
typedef BOOST_DEDUCED_TYPENAME node::bucket_allocator bucket_allocator;
typedef BOOST_DEDUCED_TYPENAME node::bucket_ptr bucket_ptr;
typedef BOOST_DEDUCED_TYPENAME node::node_ptr node_ptr;
typedef BOOST_DEDUCED_TYPENAME rebind_wrap<value_allocator, node>::type node_allocator;
typedef BOOST_DEDUCED_TYPENAME rebind_wrap<value_allocator, node>::type
node_allocator;
typedef BOOST_DEDUCED_TYPENAME node_allocator::pointer real_node_ptr;
typedef hash_iterator_base<bucket_ptr> iterator_base;
// Members
bucket_ptr buckets_;
@ -225,124 +290,194 @@ namespace boost { namespace unordered_detail {
// Data access
bucket_allocator const& bucket_alloc() const { return allocators_.first(); }
node_allocator const& node_alloc() const { return allocators_.second(); }
bucket_allocator& bucket_alloc() { return allocators_.first(); }
node_allocator& node_alloc() { return allocators_.second(); }
bucket_allocator const& bucket_alloc() const {
return allocators_.first(); }
node_allocator const& node_alloc() const {
return allocators_.second(); }
bucket_allocator& bucket_alloc() {
return allocators_.first(); }
node_allocator& node_alloc() {
return allocators_.second(); }
std::size_t max_bucket_count() const {
// -1 to account for the sentinel.
return prev_prime(this->bucket_alloc().max_size() - 1);
}
// Constructors
//
// The copy constructor doesn't copy the buckets.
hash_buckets(node_allocator const& a, std::size_t n);
hash_buckets(hash_buckets& x, move_tag m);
hash_buckets(hash_buckets& x, value_allocator const& a, move_tag m);
void create_buckets();
~hash_buckets();
// no throw
void swap(hash_buckets& other);
void move(hash_buckets& other);
// Buckets
// For the remaining functions, buckets_ must not be null.
std::size_t bucket_count() const;
std::size_t bucket_from_hash(std::size_t hashed) const;
bucket_ptr bucket_ptr_from_hash(std::size_t hashed) const;
bucket_ptr buckets_begin() const;
bucket_ptr buckets_end() const;
std::size_t bucket_size(std::size_t index) const;
bucket_ptr get_bucket(std::size_t n) const;
bucket_ptr bucket_ptr_from_hash(std::size_t hashed) const;
std::size_t bucket_size(std::size_t index) const;
node_ptr bucket_begin(std::size_t n) const;
node_ptr bucket_end(std::size_t) const;
// Alloc/Dealloc
void destruct_node(node_ptr);
void delete_node(node_ptr);
//
void delete_buckets();
void clear_bucket(bucket_ptr);
void delete_group(node_ptr first_node);
void delete_nodes(node_ptr begin, node_ptr end);
void delete_to_bucket_end(node_ptr begin);
std::size_t delete_nodes(node_ptr begin, node_ptr end);
std::size_t delete_to_bucket_end(node_ptr begin);
};
template <class H, class P> class set_hash_functions;
template <class H, class P>
class hash_buffered_functions
{
friend class set_hash_functions<H, P>;
hash_buffered_functions& operator=(hash_buffered_functions const&);
typedef boost::compressed_pair<H, P> function_pair;
typedef BOOST_DEDUCED_TYPENAME boost::aligned_storage<
sizeof(function_pair),
::boost::alignment_of<function_pair>::value>::type aligned_function;
bool current_; // The currently active functions.
aligned_function funcs_[2];
function_pair const& current() const {
return *static_cast<function_pair const*>(
static_cast<void const*>(&funcs_[current_]));
}
void construct(bool which, H const& hf, P const& eq)
{
new((void*) &funcs_[which]) function_pair(hf, eq);
}
void construct(bool which, function_pair const& f)
{
new((void*) &funcs_[which]) function_pair(f);
}
void destroy(bool which)
{
boost::unordered_detail::destroy((function_pair*)(&funcs_[which]));
}
public:
hash_buffered_functions(H const& hf, P const& eq)
: current_(false)
{
construct(current_, hf, eq);
}
hash_buffered_functions(hash_buffered_functions const& bf)
: current_(false)
{
construct(current_, bf.current());
}
~hash_buffered_functions() {
destroy(current_);
}
H const& hash_function() const {
return current().first();
}
P const& key_eq() const {
return current().second();
}
};
template <class H, class P>
class set_hash_functions
{
set_hash_functions(set_hash_functions const&);
set_hash_functions& operator=(set_hash_functions const&);
typedef hash_buffered_functions<H, P> buffered_functions;
buffered_functions& buffered_functions_;
bool tmp_functions_;
public:
set_hash_functions(buffered_functions& f, H const& h, P const& p)
: buffered_functions_(f),
tmp_functions_(!f.current_)
{
f.construct(tmp_functions_, h, p);
}
set_hash_functions(buffered_functions& f,
buffered_functions const& other)
: buffered_functions_(f),
tmp_functions_(!f.current_)
{
f.construct(tmp_functions_, other.current());
}
~set_hash_functions()
{
buffered_functions_.destroy(tmp_functions_);
}
void commit()
{
buffered_functions_.current_ = tmp_functions_;
tmp_functions_ = !tmp_functions_;
}
};
template <class H, class P, class A, class G, class K>
class hash_table :
public hash_buckets<A, G>
public hash_buckets<A, G>,
public hash_buffered_functions<H, P>
{
hash_table(hash_table const&);
public:
typedef H hasher;
typedef P key_equal;
typedef A value_allocator;
typedef G grouped;
typedef K key_extractor;
typedef hash_buffered_functions<H, P> base;
typedef hash_buckets<A, G> buckets;
typedef BOOST_DEDUCED_TYPENAME value_allocator::value_type value_type;
typedef BOOST_DEDUCED_TYPENAME key_extractor::BOOST_NESTED_TEMPLATE apply<value_type>
extractor;
typedef BOOST_DEDUCED_TYPENAME key_extractor::BOOST_NESTED_TEMPLATE
apply<value_type> extractor;
typedef BOOST_DEDUCED_TYPENAME extractor::key_type key_type;
typedef BOOST_DEDUCED_TYPENAME buckets::node node;
typedef BOOST_DEDUCED_TYPENAME buckets::bucket bucket;
typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr;
typedef BOOST_DEDUCED_TYPENAME buckets::bucket_ptr bucket_ptr;
typedef BOOST_DEDUCED_TYPENAME buckets::iterator_base iterator_base;
// Types for storing functions
typedef boost::compressed_pair<hasher, key_equal> functions;
typedef bool functions_ptr;
typedef BOOST_DEDUCED_TYPENAME boost::aligned_storage<
sizeof(functions),
::boost::alignment_of<functions>::value>::type aligned_function;
typedef BOOST_DEDUCED_TYPENAME buckets::node_allocator node_allocator;
typedef hash_node_constructor<A, G> node_constructor;
typedef std::pair<iterator_base, iterator_base> iterator_pair;
// Members
bool func_; // The currently active functions.
aligned_function funcs_[2];
bucket_ptr cached_begin_bucket_;
std::size_t size_;
float mlf_;
// Cached data - invalid if !this->buckets_
bucket_ptr cached_begin_bucket_;
std::size_t max_load_;
// Buffered Functions
functions* get_functions(bool which) {
return static_cast<functions*>(static_cast<void*>(&this->funcs_[which]));
}
functions const* get_functions(bool which) const {
return static_cast<functions const*>(static_cast<void const*>(&this->funcs_[which]));
}
functions const& current() const {
return *this->get_functions(this->func_);
}
hasher const& hash_function() const {
return this->current().first();
}
key_equal const& key_eq() const {
return this->current().second();
}
functions_ptr buffer_functions(hash_table const& x) {
functions_ptr ptr = !func_;
*this->get_functions(ptr) = x.current();
return ptr;
}
void set_functions(functions_ptr ptr) {
BOOST_ASSERT(ptr != func_);
func_ = ptr;
}
// Helper methods
key_type const& get_key(value_type const& v) const {
return extractor::extract(v);
}
key_type const& get_key_from_ptr(node_ptr n) const {
return extractor::extract(node::get_value(n));
}
bool equal(key_type const& k, value_type const& v) const;
node_ptr find_iterator(bucket_ptr bucket, key_type const& k) const;
node_ptr find_iterator(key_type const& k) const;
@ -354,31 +489,40 @@ namespace boost { namespace unordered_detail {
std::size_t bucket_index(key_type const& k) const;
void max_load_factor(float z);
std::size_t min_buckets_for_size(std::size_t n) const;
void calculate_max_load();
std::size_t calculate_max_load();
// Constructors
hash_table(std::size_t n, hasher const& hf, key_equal const& eq, value_allocator const& a);
hash_table(hash_table const& x);
hash_table(hash_table const& x, value_allocator const& a);
hash_table(std::size_t n, hasher const& hf, key_equal const& eq,
node_allocator const& a);
hash_table(hash_table const& x, node_allocator const& a);
hash_table(hash_table& x, move_tag m);
hash_table(hash_table& x, value_allocator const& a, move_tag m);
~hash_table();
hash_table(hash_table& x, node_allocator const& a, move_tag m);
~hash_table() {}
hash_table& operator=(hash_table const&);
// Iterators
iterator_base begin() const { return iterator_base(this->cached_begin_bucket_); }
iterator_base end() const { return iterator_base(this->buckets_end()); }
iterator_base begin() const {
return this->size_ ?
iterator_base(this->cached_begin_bucket_) :
iterator_base();
}
iterator_base end() const {
return iterator_base();
}
// Swap & Move
void swap(hash_table& x);
void fast_swap(hash_table& other);
void slow_swap(hash_table& other);
void partial_swap(hash_table& other);
void move(hash_table& x);
// Reserve and rehash
bool reserve(std::size_t n);
void create_for_insert(std::size_t n);
bool reserve_for_insert(std::size_t n);
void rehash(std::size_t n);
void rehash_impl(std::size_t n);
@ -393,7 +537,7 @@ namespace boost { namespace unordered_detail {
std::size_t count(key_type const& k) const;
iterator_base find(key_type const& k) const;
value_type& at(key_type const& k) const;
std::pair<iterator_base, iterator_base> equal_range(key_type const& k) const;
iterator_pair equal_range(key_type const& k) const;
// Erase
//
@ -407,7 +551,7 @@ namespace boost { namespace unordered_detail {
// recompute_begin_bucket
void recompute_begin_bucket();
void init_buckets();
// After an erase cached_begin_bucket_ might be left pointing to
// an empty bucket, so this is called to update it
@ -424,6 +568,203 @@ namespace boost { namespace unordered_detail {
// no throw
float load_factor() const;
iterator_base emplace_empty_impl_with_node(
node_constructor&, std::size_t);
};
template <class H, class P, class A, class K>
class hash_unique_table :
public hash_table<H, P, A, boost::unordered_detail::ungrouped, K>
{
public:
typedef H hasher;
typedef P key_equal;
typedef A value_allocator;
typedef K key_extractor;
typedef hash_table<H, P, A, ungrouped, K> table;
typedef hash_node_constructor<A, ungrouped> node_constructor;
typedef BOOST_DEDUCED_TYPENAME table::key_type key_type;
typedef BOOST_DEDUCED_TYPENAME table::value_type value_type;
typedef BOOST_DEDUCED_TYPENAME table::node node;
typedef BOOST_DEDUCED_TYPENAME table::node_ptr node_ptr;
typedef BOOST_DEDUCED_TYPENAME table::bucket_ptr bucket_ptr;
typedef BOOST_DEDUCED_TYPENAME table::iterator_base iterator_base;
typedef BOOST_DEDUCED_TYPENAME table::extractor extractor;
typedef std::pair<iterator_base, bool> emplace_return;
// Constructors
hash_unique_table(std::size_t n, hasher const& hf, key_equal const& eq,
value_allocator const& a)
: table(n, hf, eq, a) {}
hash_unique_table(hash_unique_table const& x)
: table(x, x.node_alloc()) {}
hash_unique_table(hash_unique_table const& x, value_allocator const& a)
: table(x, a) {}
hash_unique_table(hash_unique_table& x, move_tag m)
: table(x, m) {}
hash_unique_table(hash_unique_table& x, value_allocator const& a,
move_tag m)
: table(x, a, m) {}
~hash_unique_table() {}
// Insert methods
emplace_return emplace_impl_with_node(node_constructor& a);
value_type& operator[](key_type const& k);
// equals
bool equals(hash_unique_table const&) const;
node_ptr add_node(node_constructor& a, bucket_ptr bucket);
#if defined(BOOST_UNORDERED_STD_FORWARD)
template<class... Args>
emplace_return emplace(Args&&... args);
template<class... Args>
iterator_base emplace_hint(iterator_base const&, Args&&... args);
template<class... Args>
emplace_return emplace_impl(key_type const& k, Args&&... args);
template<class... Args>
emplace_return emplace_impl(no_key, Args&&... args);
template<class... Args>
emplace_return emplace_empty_impl(Args&&... args);
#else
template <class Arg0>
emplace_return emplace(Arg0 const& arg0);
template <class Arg0>
iterator_base emplace_hint(iterator_base const&, Arg0 const& arg0);
#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
emplace_return emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
iterator_base emplace_hint(iterator_base const& it, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \
BOOST_UNORDERED_INSERT_IMPL2(z, n, _)
#define BOOST_UNORDERED_INSERT_IMPL2(z, n, _) \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
emplace_return emplace_impl(key_type const& k, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
emplace_return emplace_impl(no_key, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
emplace_return emplace_empty_impl( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n));
BOOST_UNORDERED_INSERT_IMPL2(1, 1, _)
BOOST_PP_REPEAT_FROM_TO(2, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_INSERT_IMPL, _)
#undef BOOST_UNORDERED_INSERT_IMPL
#undef BOOST_UNORDERED_INSERT_IMPL2
#endif
// if hash function throws, or inserting > 1 element, basic exception
// safety strong otherwise
template <class InputIt>
void insert_range(InputIt i, InputIt j);
template <class InputIt>
void insert_range_impl(key_type const&, InputIt i, InputIt j);
template <class InputIt>
void insert_range_impl(no_key, InputIt i, InputIt j);
};
template <class H, class P, class A, class K>
class hash_equivalent_table :
public hash_table<H, P, A, boost::unordered_detail::grouped, K>
{
public:
typedef H hasher;
typedef P key_equal;
typedef A value_allocator;
typedef K key_extractor;
typedef hash_table<H, P, A, boost::unordered_detail::grouped, K> table;
typedef hash_node_constructor<A, boost::unordered_detail::grouped>
node_constructor;
typedef hash_iterator_base<A, grouped> iterator_base;
typedef BOOST_DEDUCED_TYPENAME table::key_type key_type;
typedef BOOST_DEDUCED_TYPENAME table::value_type value_type;
typedef BOOST_DEDUCED_TYPENAME table::node node;
typedef BOOST_DEDUCED_TYPENAME table::node_ptr node_ptr;
typedef BOOST_DEDUCED_TYPENAME table::bucket_ptr bucket_ptr;
typedef BOOST_DEDUCED_TYPENAME table::extractor extractor;
// Constructors
hash_equivalent_table(std::size_t n,
hasher const& hf, key_equal const& eq, value_allocator const& a)
: table(n, hf, eq, a) {}
hash_equivalent_table(hash_equivalent_table const& x)
: table(x, x.node_alloc()) {}
hash_equivalent_table(hash_equivalent_table const& x,
value_allocator const& a)
: table(x, a) {}
hash_equivalent_table(hash_equivalent_table& x, move_tag m)
: table(x, m) {}
hash_equivalent_table(hash_equivalent_table& x,
value_allocator const& a, move_tag m)
: table(x, a, m) {}
~hash_equivalent_table() {}
// Insert methods
iterator_base emplace_impl(node_constructor& a);
iterator_base emplace_hint_impl(iterator_base const& it,
node_constructor& a);
void emplace_impl_no_rehash(node_constructor& a);
// equals
bool equals(hash_equivalent_table const&) const;
inline node_ptr add_node(node_constructor& a,
bucket_ptr bucket, node_ptr pos);
#if defined(BOOST_UNORDERED_STD_FORWARD)
template <class... Args>
iterator_base emplace(Args&&... args);
template <class... Args>
iterator_base emplace_hint(iterator_base const& it, Args&&... args);
#else
#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
iterator_base emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \
\
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
iterator_base emplace_hint(iterator_base const& it, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n));
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_INSERT_IMPL, _)
#undef BOOST_UNORDERED_INSERT_IMPL
#endif
template <class I>
void insert_for_range(I i, I j, forward_traversal_tag);
template <class I>
void insert_for_range(I i, I j, boost::incrementable_traversal_tag);
template <class I>
void insert_range(I i, I j);
};
// Iterator Access
@ -432,7 +773,9 @@ namespace boost { namespace unordered_detail {
{
public:
template <class Iterator>
static BOOST_DEDUCED_TYPENAME Iterator::base const& get(Iterator const& it) {
static BOOST_DEDUCED_TYPENAME Iterator::base const&
get(Iterator const& it)
{
return it.base_;
}
};
@ -462,25 +805,39 @@ namespace boost { namespace unordered_detail {
private:
typedef hash_buckets<A, G> buckets;
typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr ptr;
typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr;
typedef BOOST_DEDUCED_TYPENAME buckets::node node;
typedef hash_const_local_iterator<A, G> const_local_iterator;
friend class hash_const_local_iterator<A, G>;
ptr ptr_;
node_ptr ptr_;
public:
hash_local_iterator() : ptr_() {}
explicit hash_local_iterator(ptr x) : ptr_(x) {}
BOOST_DEDUCED_TYPENAME A::reference operator*() const
{ return node::get_value(ptr_); }
value_type* operator->() const { return &node::get_value(ptr_); }
hash_local_iterator& operator++() { ptr_ = next_node(ptr_); return *this; }
hash_local_iterator operator++(int) { hash_local_iterator tmp(ptr_); ptr_ = next_node(ptr_); return tmp; }
bool operator==(hash_local_iterator x) const { return ptr_ == x.ptr_; }
bool operator==(const_local_iterator x) const { return ptr_ == x.ptr_; }
bool operator!=(hash_local_iterator x) const { return ptr_ != x.ptr_; }
bool operator!=(const_local_iterator x) const { return ptr_ != x.ptr_; }
explicit hash_local_iterator(node_ptr x) : ptr_(x) {}
BOOST_DEDUCED_TYPENAME A::reference operator*() const {
return node::get_value(ptr_);
}
value_type* operator->() const {
return &node::get_value(ptr_);
}
hash_local_iterator& operator++() {
ptr_ = ptr_->next_; return *this;
}
hash_local_iterator operator++(int) {
hash_local_iterator tmp(ptr_); ptr_ = ptr_->next_; return tmp; }
bool operator==(hash_local_iterator x) const {
return ptr_ == x.ptr_;
}
bool operator==(const_local_iterator x) const {
return ptr_ == x.ptr_;
}
bool operator!=(hash_local_iterator x) const {
return ptr_ != x.ptr_;
}
bool operator!=(const_local_iterator x) const {
return ptr_ != x.ptr_;
}
};
template <class A, class G>
@ -508,14 +865,30 @@ namespace boost { namespace unordered_detail {
explicit hash_const_local_iterator(ptr x) : ptr_(x) {}
hash_const_local_iterator(local_iterator x) : ptr_(x.ptr_) {}
BOOST_DEDUCED_TYPENAME A::const_reference
operator*() const { return node::get_value(ptr_); }
value_type const* operator->() const { return &node::get_value(ptr_); }
hash_const_local_iterator& operator++() { ptr_ = next_node(ptr_); return *this; }
hash_const_local_iterator operator++(int) { hash_const_local_iterator tmp(ptr_); ptr_ = next_node(ptr_); return tmp; }
bool operator==(local_iterator x) const { return ptr_ == x.ptr_; }
bool operator==(hash_const_local_iterator x) const { return ptr_ == x.ptr_; }
bool operator!=(local_iterator x) const { return ptr_ != x.ptr_; }
bool operator!=(hash_const_local_iterator x) const { return ptr_ != x.ptr_; }
operator*() const {
return node::get_value(ptr_);
}
value_type const* operator->() const {
return &node::get_value(ptr_);
}
hash_const_local_iterator& operator++() {
ptr_ = ptr_->next_; return *this;
}
hash_const_local_iterator operator++(int) {
hash_const_local_iterator tmp(ptr_); ptr_ = ptr_->next_; return tmp;
}
bool operator==(local_iterator x) const {
return ptr_ == x.ptr_;
}
bool operator==(hash_const_local_iterator x) const {
return ptr_ == x.ptr_;
}
bool operator!=(local_iterator x) const {
return ptr_ != x.ptr_;
}
bool operator!=(hash_const_local_iterator x) const {
return ptr_ != x.ptr_;
}
};
// iterators
@ -547,15 +920,30 @@ namespace boost { namespace unordered_detail {
hash_iterator() : base_() {}
explicit hash_iterator(base const& x) : base_(x) {}
BOOST_DEDUCED_TYPENAME A::reference
operator*() const { return node::get_value(base_.get()); }
value_type* operator->() const { return &node::get_value(base_.get()); }
hash_iterator& operator++() { base_.increment(); return *this; }
hash_iterator operator++(int) { hash_iterator tmp(base_); base_.increment(); return tmp; }
bool operator==(hash_iterator const& x) const { return base_ == x.base_; }
bool operator==(const_iterator const& x) const { return base_ == x.base_; }
bool operator!=(hash_iterator const& x) const { return base_ != x.base_; }
bool operator!=(const_iterator const& x) const { return base_ != x.base_; }
BOOST_DEDUCED_TYPENAME A::reference operator*() const {
return *base_;
}
value_type* operator->() const {
return &*base_;
}
hash_iterator& operator++() {
base_.increment(); return *this;
}
hash_iterator operator++(int) {
hash_iterator tmp(base_); base_.increment(); return tmp;
}
bool operator==(hash_iterator const& x) const {
return base_ == x.base_;
}
bool operator==(const_iterator const& x) const {
return base_ == x.base_;
}
bool operator!=(hash_iterator const& x) const {
return base_ != x.base_;
}
bool operator!=(const_iterator const& x) const {
return base_ != x.base_;
}
};
template <class A, class G>
@ -584,15 +972,30 @@ namespace boost { namespace unordered_detail {
hash_const_iterator() : base_() {}
explicit hash_const_iterator(base const& x) : base_(x) {}
hash_const_iterator(iterator const& x) : base_(x.base_) {}
BOOST_DEDUCED_TYPENAME A::const_reference
operator*() const { return node::get_value(base_.get()); }
value_type const* operator->() const { return &node::get_value(base_.get()); }
hash_const_iterator& operator++() { base_.increment(); return *this; }
hash_const_iterator operator++(int) { hash_const_iterator tmp(base_); base_.increment(); return tmp; }
bool operator==(iterator const& x) const { return base_ == x.base_; }
bool operator==(hash_const_iterator const& x) const { return base_ == x.base_; }
bool operator!=(iterator const& x) const { return base_ != x.base_; }
bool operator!=(hash_const_iterator const& x) const { return base_ != x.base_; }
BOOST_DEDUCED_TYPENAME A::const_reference operator*() const {
return *base_;
}
value_type const* operator->() const {
return &*base_;
}
hash_const_iterator& operator++() {
base_.increment(); return *this;
}
hash_const_iterator operator++(int) {
hash_const_iterator tmp(base_); base_.increment(); return tmp;
}
bool operator==(iterator const& x) const {
return base_ == x.base_;
}
bool operator==(hash_const_iterator const& x) const {
return base_ == x.base_;
}
bool operator!=(iterator const& x) const {
return base_ != x.base_;
}
bool operator!=(hash_const_iterator const& x) const {
return base_ != x.base_;
}
};
}}

View File

@ -1,678 +0,0 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-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)
#ifndef BOOST_UNORDERED_DETAIL_INSERT_HPP_INCLUDED
#define BOOST_UNORDERED_DETAIL_INSERT_HPP_INCLUDED
#include <boost/unordered/detail/table.hpp>
#include <boost/unordered/detail/extract_key.hpp>
namespace boost { namespace unordered_detail {
////////////////////////////////////////////////////////////////////////////
// A couple of convenience methods for adding nodes.
// H = Has Func
// P = Predicate
// A = Value Allocator
// K = Key Extractor
template <class H, class P, class A, class K>
class hash_unique_table :
public hash_table<H, P, A, boost::unordered_detail::ungrouped, K>
{
public:
typedef H hasher;
typedef P key_equal;
typedef A value_allocator;
typedef K key_extractor;
typedef hash_table<H, P, A, boost::unordered_detail::ungrouped, K> table;
typedef hash_node_constructor<A, boost::unordered_detail::ungrouped> node_constructor;
typedef BOOST_DEDUCED_TYPENAME table::key_type key_type;
typedef BOOST_DEDUCED_TYPENAME table::value_type value_type;
typedef BOOST_DEDUCED_TYPENAME table::node node;
typedef BOOST_DEDUCED_TYPENAME table::node_ptr node_ptr;
typedef BOOST_DEDUCED_TYPENAME table::bucket_ptr bucket_ptr;
typedef BOOST_DEDUCED_TYPENAME table::iterator_base iterator_base;
typedef BOOST_DEDUCED_TYPENAME table::extractor extractor;
// Constructors
hash_unique_table(std::size_t n, hasher const& hf, key_equal const& eq, value_allocator const& a)
: table(n, hf, eq, a) {}
hash_unique_table(hash_unique_table const& x)
: table(x) {}
hash_unique_table(hash_unique_table const& x, value_allocator const& a)
: table(x, a) {}
hash_unique_table(hash_unique_table& x, move_tag m)
: table(x, m) {}
hash_unique_table(hash_unique_table& x, value_allocator const& a, move_tag m)
: table(x, a, m) {}
~hash_unique_table() {}
// Insert methods
std::pair<iterator_base, bool> emplace_impl_with_node(node_constructor& a);
value_type& operator[](key_type const& k);
// equals
bool equals(hash_unique_table const&) const;
static bool group_equals(node_ptr it1, node_ptr it2, set_extractor*);
static bool group_equals(node_ptr it1, node_ptr it2, map_extractor*);
inline node_ptr add_node(node_constructor& a, bucket_ptr bucket)
{
node_ptr n = a.release();
node::add_to_bucket(n, *bucket);
++this->size_;
if(bucket < this->cached_begin_bucket_) this->cached_begin_bucket_ = bucket;
return n;
}
#if defined(BOOST_UNORDERED_STD_FORWARD)
// Emplace (unique keys)
// (I'm using an overloaded emplace for both 'insert' and 'emplace')
// if hash function throws, basic exception safety
// strong otherwise
template<class... Args>
std::pair<iterator_base, bool> emplace(Args&&... args)
{
return emplace_impl(
extractor::extract(std::forward<Args>(args)...),
std::forward<Args>(args)...);
}
// Insert (unique keys)
// (I'm using an overloaded emplace for both 'insert' and 'emplace')
// I'm just ignoring hints here for now.
// if hash function throws, basic exception safety
// strong otherwise
template<class... Args>
iterator_base emplace_hint(iterator_base const&, Args&&... args)
{
return emplace_impl(
extractor::extract(std::forward<Args>(args)...),
std::forward<Args>(args)...).first;
}
template<class... Args>
std::pair<iterator_base, bool> emplace_impl(key_type const& k, Args&&... args)
{
// No side effects in this initial code
std::size_t hash_value = this->hash_function()(k);
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
node_ptr pos = find_iterator(bucket, k);
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
// Found an existing key, return it (no throw).
return std::pair<iterator_base, bool>(
iterator_base(bucket, pos), false);
} else {
// Doesn't already exist, add to bucket.
// Side effects only in this block.
// Create the node before rehashing in case it throws an
// exception (need strong safety in such a case).
node_constructor a(*this);
a.construct(std::forward<Args>(args)...);
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
if(reserve_for_insert(this->size_ + 1))
bucket = this->bucket_ptr_from_hash(hash_value);
// Nothing after this point can throw.
return std::pair<iterator_base, bool>(iterator_base(bucket,
add_node(a, bucket)), true);
}
}
template<class... Args>
std::pair<iterator_base, bool> emplace_impl(no_key, Args&&... args)
{
// Construct the node regardless - in order to get the key.
// It will be discarded if it isn't used
node_constructor a(*this);
a.construct(std::forward<Args>(args)...);
return emplace_impl_with_node(a);
}
#else
template <class Arg0>
std::pair<iterator_base, bool> emplace(Arg0 const& arg0)
{
return emplace_impl(extractor::extract(arg0), arg0);
}
template <class Arg0>
iterator_base emplace_hint(iterator_base const&, Arg0 const& arg0)
{
return emplace_impl(extractor::extract(arg0), arg0).first;
}
#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
std::pair<iterator_base, bool> emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return emplace_impl(extractor::extract(arg0, arg1), \
BOOST_UNORDERED_CALL_PARAMS(z, n)); \
} \
\
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
iterator_base emplace_hint(iterator_base const& it, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return emplace_impl(extractor::extract(arg0, arg1), \
BOOST_UNORDERED_CALL_PARAMS(z, n)).first; \
} \
BOOST_UNORDERED_INSERT_IMPL2(z, n, _)
#define BOOST_UNORDERED_INSERT_IMPL2(z, n, _) \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
std::pair<iterator_base, bool> emplace_impl(key_type const& k, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
std::size_t hash_value = this->hash_function()(k); \
bucket_ptr bucket \
= this->bucket_ptr_from_hash(hash_value); \
node_ptr pos = find_iterator(bucket, k); \
\
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { \
return std::pair<iterator_base, bool>( \
iterator_base(bucket, pos), false); \
} else { \
node_constructor a(*this); \
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \
\
if(reserve_for_insert(this->size_ + 1)) \
bucket = this->bucket_ptr_from_hash(hash_value); \
\
return std::pair<iterator_base, bool>(iterator_base(bucket, \
add_node(a, bucket)), true); \
} \
} \
\
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
std::pair<iterator_base, bool> emplace_impl(no_key, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
{ \
node_constructor a(*this); \
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \
return emplace_impl_with_node(a); \
}
BOOST_UNORDERED_INSERT_IMPL2(1, 1, _)
BOOST_PP_REPEAT_FROM_TO(2, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_INSERT_IMPL, _)
#undef BOOST_UNORDERED_INSERT_IMPL
#endif
// if hash function throws, or inserting > 1 element, basic exception safety
// strong otherwise
template <class InputIterator>
void insert_range(InputIterator i, InputIterator j)
{
if(i != j)
return insert_range_impl(extractor::extract(*i), i, j);
}
template <class InputIterator>
void insert_range_impl(key_type const&, InputIterator i, InputIterator j)
{
node_constructor a(*this);
for (; i != j; ++i) {
// No side effects in this initial code
std::size_t hash_value = this->hash_function()(extractor::extract(*i));
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
node_ptr pos = find_iterator(bucket, extractor::extract(*i));
if (!BOOST_UNORDERED_BORLAND_BOOL(pos)) {
// Doesn't already exist, add to bucket.
// Side effects only in this block.
// Create the node before rehashing in case it throws an
// exception (need strong safety in such a case).
a.construct(*i);
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
if(this->size_ + 1 >= this->max_load_) {
reserve_for_insert(this->size_ + insert_size(i, j));
bucket = this->bucket_ptr_from_hash(hash_value);
}
// Nothing after this point can throw.
add_node(a, bucket);
}
}
}
template <class InputIterator>
void insert_range_impl(no_key, InputIterator i, InputIterator j)
{
node_constructor a(*this);
for (; i != j; ++i) {
// No side effects in this initial code
a.construct(*i);
emplace_impl_with_node(a);
}
}
};
template <class H, class P, class A, class K>
class hash_equivalent_table :
public hash_table<H, P, A, boost::unordered_detail::grouped, K>
{
public:
typedef H hasher;
typedef P key_equal;
typedef A value_allocator;
typedef K key_extractor;
typedef hash_table<H, P, A, boost::unordered_detail::grouped, K> table;
typedef hash_node_constructor<A, boost::unordered_detail::grouped> node_constructor;
typedef BOOST_DEDUCED_TYPENAME table::key_type key_type;
typedef BOOST_DEDUCED_TYPENAME table::value_type value_type;
typedef BOOST_DEDUCED_TYPENAME table::node node;
typedef BOOST_DEDUCED_TYPENAME table::node_ptr node_ptr;
typedef BOOST_DEDUCED_TYPENAME table::bucket_ptr bucket_ptr;
typedef BOOST_DEDUCED_TYPENAME table::iterator_base iterator_base;
typedef BOOST_DEDUCED_TYPENAME table::extractor extractor;
// Constructors
hash_equivalent_table(std::size_t n, hasher const& hf, key_equal const& eq, value_allocator const& a)
: table(n, hf, eq, a) {}
hash_equivalent_table(hash_equivalent_table const& x)
: table(x) {}
hash_equivalent_table(hash_equivalent_table const& x, value_allocator const& a)
: table(x, a) {}
hash_equivalent_table(hash_equivalent_table& x, move_tag m)
: table(x, m) {}
hash_equivalent_table(hash_equivalent_table& x, value_allocator const& a, move_tag m)
: table(x, a, m) {}
~hash_equivalent_table() {}
// Insert methods
iterator_base emplace_impl(node_constructor& a);
iterator_base emplace_hint_impl(iterator_base const& it, node_constructor& a);
void emplace_impl_no_rehash(node_constructor& a);
// equals
bool equals(hash_equivalent_table const&) const;
static bool group_equals(node_ptr it1, node_ptr it2, set_extractor*);
static bool group_equals(node_ptr it1, node_ptr it2, map_extractor*);
inline node_ptr add_node(node_constructor& a, bucket_ptr bucket, node_ptr pos)
{
node_ptr n = a.release();
if(BOOST_UNORDERED_BORLAND_BOOL(pos)) {
node::add_after_node(n, pos);
}
else {
node::add_to_bucket(n, *bucket);
if(bucket < this->cached_begin_bucket_) this->cached_begin_bucket_ = bucket;
}
++this->size_;
return n;
}
public:
// Insert functions
//
// basic exception safety, if hash function throws
// strong otherwise.
#if defined(BOOST_UNORDERED_STD_FORWARD)
// Emplace (equivalent key containers)
// (I'm using an overloaded emplace for both 'insert' and 'emplace')
// if hash function throws, basic exception safety
// strong otherwise
template <class... Args>
iterator_base emplace(Args&&... args)
{
// Create the node before rehashing in case it throws an
// exception (need strong safety in such a case).
node_constructor a(*this);
a.construct(std::forward<Args>(args)...);
return emplace_impl(a);
}
// Emplace (equivalent key containers)
// (I'm using an overloaded emplace for both 'insert' and 'emplace')
// if hash function throws, basic exception safety
// strong otherwise
template <class... Args>
iterator_base emplace_hint(iterator_base const& it, Args&&... args)
{
// Create the node before rehashing in case it throws an
// exception (need strong safety in such a case).
node_constructor a(*this);
a.construct(std::forward<Args>(args)...);
return emplace_hint_impl(it, a);
}
#else
#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
iterator_base emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
node_constructor a(*this); \
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \
return emplace_impl(a); \
} \
\
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
iterator_base emplace_hint(iterator_base const& it, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
node_constructor a(*this); \
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \
return emplace_hint_impl(it, a); \
}
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_INSERT_IMPL, _)
#undef BOOST_UNORDERED_INSERT_IMPL
#endif
// Insert from iterator range (equivalent key containers)
private:
// if hash function throws, or inserting > 1 element, basic exception safety
// strong otherwise
template <class I>
void insert_for_range(I i, I j, forward_traversal_tag)
{
std::size_t distance = unordered_detail::distance(i, j);
if(distance == 1) {
emplace(*i);
}
else {
// Only require basic exception safety here
reserve_for_insert(this->size_ + distance);
node_constructor a(*this);
for (; i != j; ++i) {
a.construct(*i);
emplace_impl_no_rehash(a);
}
}
}
// if hash function throws, or inserting > 1 element, basic exception safety
// strong otherwise
template <class I>
void insert_for_range(I i, I j,
boost::incrementable_traversal_tag)
{
node_constructor a(*this);
for (; i != j; ++i) {
a.construct(*i);
emplace_impl(a);
}
}
public:
// if hash function throws, or inserting > 1 element, basic exception safety
// strong otherwise
template <class I>
void insert_range(I i, I j)
{
BOOST_DEDUCED_TYPENAME boost::iterator_traversal<I>::type
iterator_traversal_tag;
insert_for_range(i, j, iterator_traversal_tag);
}
};
////////////////////////////////////////////////////////////////////////////
// Unique insert methods
template <class H, class P, class A, class K>
std::pair<
BOOST_DEDUCED_TYPENAME hash_unique_table<H, P, A, K>::iterator_base,
bool>
hash_unique_table<H, P, A, K>
::emplace_impl_with_node(node_constructor& a)
{
// No side effects in this initial code
key_type const& k = extractor::extract(a.get()->value());
std::size_t hash_value = this->hash_function()(k);
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
node_ptr pos = find_iterator(bucket, k);
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
// Found an existing key, return it (no throw).
return std::pair<iterator_base, bool>(
iterator_base(bucket, pos), false);
} else {
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
if(reserve_for_insert(this->size_ + 1))
bucket = this->bucket_ptr_from_hash(hash_value);
// Nothing after this point can throw.
return std::pair<iterator_base, bool>(iterator_base(bucket,
add_node(a, bucket)), true);
}
}
// if hash function throws, basic exception safety
// strong otherwise
template <class H, class P, class A, class K>
BOOST_DEDUCED_TYPENAME hash_unique_table<H, P, A, K>::value_type&
hash_unique_table<H, P, A, K>
::operator[](key_type const& k)
{
typedef BOOST_DEDUCED_TYPENAME value_type::second_type mapped_type;
std::size_t hash_value = this->hash_function()(k);
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
node_ptr pos = find_iterator(bucket, k);
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
return node::get_value(pos);
}
else {
// Side effects only in this block.
// Create the node before rehashing in case it throws an
// exception (need strong safety in such a case).
node_constructor a(*this);
a.construct_pair(k, (mapped_type*) 0);
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
if(reserve_for_insert(this->size_ + 1))
bucket = this->bucket_ptr_from_hash(hash_value);
// Nothing after this point can throw.
return node::get_value(add_node(a, bucket));
}
}
////////////////////////////////////////////////////////////////////////////
// Insert methods
template <class H, class P, class A, class K>
BOOST_DEDUCED_TYPENAME hash_equivalent_table<H, P, A, K>::iterator_base
hash_equivalent_table<H, P, A, K>
::emplace_impl(node_constructor& a)
{
key_type const& k = extractor::extract(a.get()->value());
std::size_t hash_value = this->hash_function()(k);
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
node_ptr position = find_iterator(bucket, k);
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
if(reserve_for_insert(this->size_ + 1))
bucket = this->bucket_ptr_from_hash(hash_value);
// I'm relying on node_ptr not being invalidated by
// the rehash here.
return iterator_base(bucket, add_node(a, bucket, position));
}
template <class H, class P, class A, class K>
BOOST_DEDUCED_TYPENAME hash_equivalent_table<H, P, A, K>::iterator_base
hash_equivalent_table<H, P, A, K>
::emplace_hint_impl(iterator_base const& it, node_constructor& a)
{
// equal can throw, but with no effects
if (it.is_end() ||
!equal(extractor::extract(a.get()->value()), node::get_value(it.get()))) {
// Use the standard emplace if the iterator doesn't point
// to a matching key.
return emplace_impl(a);
}
else {
// Find the first node in the group - so that the node
// will be added at the end of the group.
node_ptr start(it.node_);
while(node::next_group(start) == start)
start = node::group_prev(start);
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
bucket_ptr bucket = reserve_for_insert(this->size_ + 1) ?
get_bucket(this->bucket_index(
extractor::extract(a.get()->value()))) : it.bucket_;
// Nothing after this point can throw
return iterator_base(bucket, add_node(a, bucket, start));
}
}
template <class H, class P, class A, class K>
void hash_equivalent_table<H, P, A, K>
::emplace_impl_no_rehash(node_constructor& a)
{
key_type const& k = extractor::extract(a.get()->value());
bucket_ptr bucket = this->get_bucket(this->bucket_index(k));
add_node(a, bucket, find_iterator(bucket, k));
}
////////////////////////////////////////////////////////////////////////////
// Equalilty check
template <class H, class P, class A, class K>
inline bool hash_equivalent_table<H, P, A, K>
::group_equals(node_ptr it1, node_ptr it2, set_extractor*)
{
return node::group_count(it1) == node::group_count(it2);
}
template <class H, class P, class A, class K>
inline bool hash_equivalent_table<H, P, A, K>
::group_equals(node_ptr it1, node_ptr it2, map_extractor*)
{
node_ptr end1 = node::next_group(it1);
node_ptr end2 = node::next_group(it2);
do {
if(node::get_value(it1).second != node::get_value(it2).second) return false;
it1 = next_node(it1);
it2 = next_node(it2);
} while(it1 != end1 && it2 != end2);
return it1 == end1 && it2 == end2;
}
template <class H, class P, class A, class K>
bool hash_equivalent_table<H, P, A, K>
::equals(hash_equivalent_table<H, P, A, K> const& other) const
{
if(this->size_ != other.size_) return false;
for(bucket_ptr i = this->cached_begin_bucket_, j = this->buckets_end(); i != j; ++i)
{
for(node_ptr it(i->next_); BOOST_UNORDERED_BORLAND_BOOL(it); it = node::next_group(it))
{
node_ptr other_pos = other.find_iterator(extractor::extract(node::get_value(it)));
if(!BOOST_UNORDERED_BORLAND_BOOL(other_pos) ||
!group_equals(it, other_pos, (K*)0))
return false;
}
}
return true;
}
template <class H, class P, class A, class K>
inline bool hash_unique_table<H, P, A, K>
::group_equals(node_ptr, node_ptr, set_extractor*)
{
return true;
}
template <class H, class P, class A, class K>
inline bool hash_unique_table<H, P, A, K>
::group_equals(node_ptr it1, node_ptr it2, map_extractor*)
{
return node::get_value(it1).second == node::get_value(it2).second;
}
template <class H, class P, class A, class K>
bool hash_unique_table<H, P, A, K>
::equals(hash_unique_table<H, P, A, K> const& other) const
{
if(this->size_ != other.size_) return false;
for(bucket_ptr i = this->cached_begin_bucket_, j = this->buckets_end(); i != j; ++i)
{
for(node_ptr it(i->next_); BOOST_UNORDERED_BORLAND_BOOL(it); it = node::next_group(it))
{
node_ptr other_pos = other.find_iterator(extractor::extract(node::get_value(it)));
if(!BOOST_UNORDERED_BORLAND_BOOL(other_pos) ||
!group_equals(it, other_pos, (K*)0))
return false;
}
}
return true;
}
}}
#endif

View File

@ -109,6 +109,8 @@ struct move_from
{
explicit move_from(T& x) : source(x) { }
T& source;
private:
move_from& operator=(move_from const&);
};
/*************************************************************************************************/

View File

@ -24,23 +24,6 @@
namespace boost { namespace unordered_detail {
template <class BucketPtr>
inline BucketPtr& next_node(BucketPtr ptr)
{
return ptr->next_;
}
template <class BucketPtr>
inline std::size_t node_count(BucketPtr ptr, BucketPtr end)
{
std::size_t count = 0;
while(ptr != end) {
++count;
ptr = next_node(ptr);
}
return count;
}
////////////////////////////////////////////////////////////////////////////
// ungrouped node implementation
@ -48,7 +31,7 @@ namespace boost { namespace unordered_detail {
inline BOOST_DEDUCED_TYPENAME ungrouped_node_base<A>::node_ptr&
ungrouped_node_base<A>::next_group(node_ptr ptr)
{
return next_node(ptr);
return ptr->next_;
}
template <class A>
@ -60,35 +43,24 @@ namespace boost { namespace unordered_detail {
template <class A>
inline void ungrouped_node_base<A>::add_to_bucket(node_ptr n, bucket& b)
{
next_node(n) = b.next_;
n->next_ = b.next_;
b.next_ = n;
}
template <class A>
inline void ungrouped_node_base<A>::add_group_to_bucket(node_ptr n, bucket& b)
inline void ungrouped_node_base<A>::add_after_node(node_ptr n,
node_ptr position)
{
next_node(n) = b.next_;
b.next_ = n;
}
template <class A>
inline void ungrouped_node_base<A>::add_after_node(node_ptr n, node_ptr position)
{
next_node(n) = next_node(position);
next_node(position) = position;
n->next_ = position->next_;
position->next_ = position;
}
template <class A>
inline void ungrouped_node_base<A>::unlink_node(bucket& b, node_ptr node)
{
unlink_nodes(b, node, next_node(node));
}
template <class A>
inline void ungrouped_node_base<A>::unlink_nodes(bucket& b, node_ptr begin, node_ptr end)
inline void ungrouped_node_base<A>::unlink_nodes(bucket& b,
node_ptr begin, node_ptr end)
{
node_ptr* pos = &b.next_;
while(*pos != begin) pos = &next_node(*pos);
while(*pos != begin) pos = &(*pos)->next_;
*pos = end;
}
@ -99,26 +71,30 @@ namespace boost { namespace unordered_detail {
}
template <class A>
inline void ungrouped_node_base<A>::unlink_group(node_ptr* b)
inline void ungrouped_node_base<A>::unlink_node(bucket& b, node_ptr node)
{
*b = next_node(*b);
unlink_nodes(b, node, node->next_);
}
////////////////////////////////////////////////////////////////////////////
// grouped node implementation
template <class A>
inline BOOST_DEDUCED_TYPENAME grouped_node_base<A>::node_ptr&
grouped_node_base<A>::group_prev(node_ptr ptr)
{
return get(ptr).group_prev_;
}
// If ptr is the first element in a group, return pointer to next group.
// Otherwise returns a pointer to ptr.
template <class A>
inline BOOST_DEDUCED_TYPENAME grouped_node_base<A>::node_ptr&
grouped_node_base<A>::next_group(node_ptr ptr)
{
return next_node(group_prev(ptr));
return get(ptr).group_prev_->next_;
}
template <class A>
inline BOOST_DEDUCED_TYPENAME grouped_node_base<A>::node_ptr
grouped_node_base<A>::first_in_group(node_ptr ptr)
{
while(next_group(ptr) == ptr)
ptr = get(ptr).group_prev_;
return ptr;
}
template <class A>
@ -128,7 +104,7 @@ namespace boost { namespace unordered_detail {
std::size_t size = 0;
do {
++size;
ptr = group_prev(ptr);
ptr = get(ptr).group_prev_;
} while(ptr != start);
return size;
}
@ -136,25 +112,18 @@ namespace boost { namespace unordered_detail {
template <class A>
inline void grouped_node_base<A>::add_to_bucket(node_ptr n, bucket& b)
{
next_node(n) = b.next_;
group_prev(n) = n;
n->next_ = b.next_;
get(n).group_prev_ = n;
b.next_ = n;
}
template <class A>
inline void grouped_node_base<A>::add_group_to_bucket(node_ptr n, bucket& b)
inline void grouped_node_base<A>::add_after_node(node_ptr n, node_ptr pos)
{
next_group(n) = b.next_;
b.next_ = n;
}
template <class A>
inline void grouped_node_base<A>::add_after_node(node_ptr n, node_ptr position)
{
next_node(n) = next_group(position);
group_prev(n) = group_prev(position);
next_group(position) = n;
group_prev(position) = n;
n->next_ = next_group(pos);
get(n).group_prev_ = get(pos).group_prev_;
next_group(pos) = n;
get(pos).group_prev_ = n;
}
// Break a ciruclar list into two, with split as the beginning
@ -164,29 +133,21 @@ namespace boost { namespace unordered_detail {
inline BOOST_DEDUCED_TYPENAME grouped_node_base<A>::node_ptr
grouped_node_base<A>::split_group(node_ptr split)
{
// If split is at the beginning of the group then there's
// nothing to split.
if(next_node(group_prev(split)) != split)
return split;
node_ptr first = first_in_group(split);
if(first == split) return split;
// Find the start of the group.
node_ptr start = split;
do {
start = group_prev(start);
} while(next_node(group_prev(start)) == start);
node_ptr last = get(first).group_prev_;
get(first).group_prev_ = get(split).group_prev_;
get(split).group_prev_ = last;
node_ptr last = group_prev(start);
group_prev(start) = group_prev(split);
group_prev(split) = last;
return start;
return first;
}
template <class A>
void grouped_node_base<A>::unlink_node(bucket& b, node_ptr node)
{
node_ptr next = next_node(node);
node_ptr* pos = &next_node(group_prev(node));
node_ptr next = node->next_;
node_ptr* pos = &next_group(node);
if(*pos != node) {
// The node is at the beginning of a group.
@ -196,31 +157,37 @@ namespace boost { namespace unordered_detail {
while(*pos != node) pos = &next_group(*pos);
// Remove from group
if(BOOST_UNORDERED_BORLAND_BOOL(next) && group_prev(next) == node)
group_prev(next) = group_prev(node);
if(BOOST_UNORDERED_BORLAND_BOOL(next) &&
get(next).group_prev_ == node)
{
get(next).group_prev_ = get(node).group_prev_;
}
}
else if(BOOST_UNORDERED_BORLAND_BOOL(next) && group_prev(next) == node) {
else if(BOOST_UNORDERED_BORLAND_BOOL(next) &&
get(next).group_prev_ == node)
{
// The deleted node is not at the end of the group, so
// change the link from the next node.
group_prev(next) = group_prev(node);
get(next).group_prev_ = get(node).group_prev_;
}
else {
// The deleted node is at the end of the group, so the
// first node in the group is pointing to it.
// Find that to change its pointer.
node_ptr x = group_prev(node);
while(group_prev(x) != node) {
x = group_prev(x);
node_ptr x = get(node).group_prev_;
while(get(x).group_prev_ != node) {
x = get(x).group_prev_;
}
group_prev(x) = group_prev(node);
get(x).group_prev_ = get(node).group_prev_;
}
*pos = next;
}
template <class A>
void grouped_node_base<A>::unlink_nodes(bucket& b, node_ptr begin, node_ptr end)
void grouped_node_base<A>::unlink_nodes(bucket& b,
node_ptr begin, node_ptr end)
{
node_ptr* pos = &next_node(group_prev(begin));
node_ptr* pos = &next_group(begin);
if(*pos != begin) {
// The node is at the beginning of a group.
@ -238,10 +205,10 @@ namespace boost { namespace unordered_detail {
node_ptr group2 = split_group(end);
if(begin == group2) {
node_ptr end1 = group_prev(group1);
node_ptr end2 = group_prev(group2);
group_prev(group1) = end2;
group_prev(group2) = end1;
node_ptr end1 = get(group1).group_prev_;
node_ptr end2 = get(group2).group_prev_;
get(group1).group_prev_ = end2;
get(group2).group_prev_ = end1;
}
}
}
@ -254,12 +221,6 @@ namespace boost { namespace unordered_detail {
split_group(end);
b.next_ = end;
}
template <class A>
inline void grouped_node_base<A>::unlink_group(node_ptr* b)
{
*b = next_group(*b);
}
}}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,431 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-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)
#ifndef BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED
#define BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED
#include <boost/unordered/detail/table.hpp>
#include <boost/unordered/detail/extract_key.hpp>
namespace boost { namespace unordered_detail {
////////////////////////////////////////////////////////////////////////////
// Equality
template <class H, class P, class A, class K>
bool hash_unique_table<H, P, A, K>
::equals(hash_unique_table<H, P, A, K> const& other) const
{
if(this->size_ != other.size_) return false;
if(!this->size_) return true;
bucket_ptr end = this->get_bucket(this->bucket_count_);
for(bucket_ptr i = this->cached_begin_bucket_; i != end; ++i)
{
node_ptr it1 = i->next_;
while(BOOST_UNORDERED_BORLAND_BOOL(it1))
{
node_ptr it2 = other.find_iterator(get_key_from_ptr(it1));
if(!BOOST_UNORDERED_BORLAND_BOOL(it2)) return false;
if(!extractor::compare_mapped(
node::get_value(it1), node::get_value(it2)))
return false;
it1 = it1->next_;
}
}
return true;
}
////////////////////////////////////////////////////////////////////////////
// A convenience method for adding nodes.
template <class H, class P, class A, class K>
inline BOOST_DEDUCED_TYPENAME hash_unique_table<H, P, A, K>::node_ptr
hash_unique_table<H, P, A, K>::add_node(node_constructor& a,
bucket_ptr bucket)
{
node_ptr n = a.release();
node::add_to_bucket(n, *bucket);
++this->size_;
if(bucket < this->cached_begin_bucket_)
this->cached_begin_bucket_ = bucket;
return n;
}
////////////////////////////////////////////////////////////////////////////
// Insert methods
// if hash function throws, basic exception safety
// strong otherwise
template <class H, class P, class A, class K>
BOOST_DEDUCED_TYPENAME hash_unique_table<H, P, A, K>::value_type&
hash_unique_table<H, P, A, K>::operator[](key_type const& k)
{
typedef BOOST_DEDUCED_TYPENAME value_type::second_type mapped_type;
std::size_t hash_value = this->hash_function()(k);
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
if(!this->buckets_) {
node_constructor a(*this);
a.construct_pair(k, (mapped_type*) 0);
return *this->emplace_empty_impl_with_node(a, 1);
}
node_ptr pos = find_iterator(bucket, k);
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
return node::get_value(pos);
}
else {
// Side effects only in this block.
// Create the node before rehashing in case it throws an
// exception (need strong safety in such a case).
node_constructor a(*this);
a.construct_pair(k, (mapped_type*) 0);
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
if(this->reserve_for_insert(this->size_ + 1))
bucket = this->bucket_ptr_from_hash(hash_value);
// Nothing after this point can throw.
return node::get_value(add_node(a, bucket));
}
}
template <class H, class P, class A, class K>
inline BOOST_DEDUCED_TYPENAME hash_unique_table<H, P, A, K>::emplace_return
hash_unique_table<H, P, A, K>
::emplace_impl_with_node(node_constructor& a)
{
// No side effects in this initial code
key_type const& k = get_key(a.value());
std::size_t hash_value = this->hash_function()(k);
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
node_ptr pos = find_iterator(bucket, k);
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
// Found an existing key, return it (no throw).
return emplace_return(iterator_base(bucket, pos), false);
} else {
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
if(this->reserve_for_insert(this->size_ + 1))
bucket = this->bucket_ptr_from_hash(hash_value);
// Nothing after this point can throw.
return emplace_return(
iterator_base(bucket, add_node(a, bucket)),
true);
}
}
#if defined(BOOST_UNORDERED_STD_FORWARD)
template <class H, class P, class A, class K>
template<class... Args>
inline BOOST_DEDUCED_TYPENAME hash_unique_table<H, P, A, K>::emplace_return
hash_unique_table<H, P, A, K>::emplace_impl(key_type const& k,
Args&&... args)
{
// No side effects in this initial code
std::size_t hash_value = this->hash_function()(k);
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
node_ptr pos = find_iterator(bucket, k);
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
// Found an existing key, return it (no throw).
return emplace_return(iterator_base(bucket, pos), false);
} else {
// Doesn't already exist, add to bucket.
// Side effects only in this block.
// Create the node before rehashing in case it throws an
// exception (need strong safety in such a case).
node_constructor a(*this);
a.construct(std::forward<Args>(args)...);
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
if(this->reserve_for_insert(this->size_ + 1))
bucket = this->bucket_ptr_from_hash(hash_value);
// Nothing after this point can throw.
return emplace_return(
iterator_base(bucket, add_node(a, bucket)),
true);
}
}
template <class H, class P, class A, class K>
template<class... Args>
inline BOOST_DEDUCED_TYPENAME hash_unique_table<H, P, A, K>::emplace_return
hash_unique_table<H, P, A, K>::emplace_impl(no_key, Args&&... args)
{
// Construct the node regardless - in order to get the key.
// It will be discarded if it isn't used
node_constructor a(*this);
a.construct(std::forward<Args>(args)...);
return emplace_impl_with_node(a);
}
template <class H, class P, class A, class K>
template<class... Args>
inline BOOST_DEDUCED_TYPENAME hash_unique_table<H, P, A, K>::emplace_return
hash_unique_table<H, P, A, K>::emplace_empty_impl(Args&&... args)
{
node_constructor a(*this);
a.construct(std::forward<Args>(args)...);
return emplace_return(this->emplace_empty_impl_with_node(a, 1), true);
}
#else
#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \
template <class H, class P, class A, class K> \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
inline BOOST_DEDUCED_TYPENAME \
hash_unique_table<H, P, A, K>::emplace_return \
hash_unique_table<H, P, A, K>::emplace_impl( \
key_type const& k, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
{ \
std::size_t hash_value = this->hash_function()(k); \
bucket_ptr bucket \
= this->bucket_ptr_from_hash(hash_value); \
node_ptr pos = find_iterator(bucket, k); \
\
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { \
return emplace_return(iterator_base(bucket, pos), false); \
} else { \
node_constructor a(*this); \
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \
\
if(this->reserve_for_insert(this->size_ + 1)) \
bucket = this->bucket_ptr_from_hash(hash_value); \
\
return emplace_return(iterator_base(bucket, \
add_node(a, bucket)), true); \
} \
} \
\
template <class H, class P, class A, class K> \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
inline BOOST_DEDUCED_TYPENAME \
hash_unique_table<H, P, A, K>::emplace_return \
hash_unique_table<H, P, A, K>:: \
emplace_impl(no_key, BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
{ \
node_constructor a(*this); \
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \
return emplace_impl_with_node(a); \
} \
\
template <class H, class P, class A, class K> \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
inline BOOST_DEDUCED_TYPENAME \
hash_unique_table<H, P, A, K>::emplace_return \
hash_unique_table<H, P, A, K>:: \
emplace_empty_impl(BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
{ \
node_constructor a(*this); \
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \
return emplace_return(this->emplace_empty_impl_with_node(a, 1), true); \
}
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_INSERT_IMPL, _)
#undef BOOST_UNORDERED_INSERT_IMPL
#endif
#if defined(BOOST_UNORDERED_STD_FORWARD)
// Emplace (unique keys)
// (I'm using an overloaded emplace for both 'insert' and 'emplace')
// if hash function throws, basic exception safety
// strong otherwise
template <class H, class P, class A, class K>
template<class... Args>
BOOST_DEDUCED_TYPENAME hash_unique_table<H, P, A, K>::emplace_return
hash_unique_table<H, P, A, K>::emplace(Args&&... args)
{
return this->size_ ?
emplace_impl(
extractor::extract(std::forward<Args>(args)...),
std::forward<Args>(args)...) :
emplace_empty_impl(std::forward<Args>(args)...);
}
// Insert (unique keys)
// (I'm using an overloaded emplace for both 'insert' and 'emplace')
// I'm just ignoring hints here for now.
// if hash function throws, basic exception safety
// strong otherwise
template <class H, class P, class A, class K>
template<class... Args>
BOOST_DEDUCED_TYPENAME hash_unique_table<H, P, A, K>::iterator_base
hash_unique_table<H, P, A, K>::emplace_hint(iterator_base const&,
Args&&... args)
{
return this->size_ ?
emplace_impl(
extractor::extract(std::forward<Args>(args)...),
std::forward<Args>(args)...).first :
emplace_empty_impl(std::forward<Args>(args)...).first;
}
#else
template <class H, class P, class A, class K>
template <class Arg0>
BOOST_DEDUCED_TYPENAME hash_unique_table<H, P, A, K>::emplace_return
hash_unique_table<H, P, A, K>::emplace(Arg0 const& arg0)
{
return this->size_ ?
emplace_impl(extractor::extract(arg0), arg0) :
emplace_empty_impl(arg0);
}
template <class H, class P, class A, class K>
template <class Arg0>
BOOST_DEDUCED_TYPENAME hash_unique_table<H, P, A, K>::iterator_base
hash_unique_table<H, P, A, K>::emplace_hint(iterator_base const&,
Arg0 const& arg0)
{
return this->size_ ?
emplace_impl(extractor::extract(arg0), arg0).first :
emplace_empty_impl(arg0).first;
}
#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \
template <class H, class P, class A, class K> \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
BOOST_DEDUCED_TYPENAME hash_unique_table<H, P, A, K>::emplace_return \
hash_unique_table<H, P, A, K>::emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
{ \
return this->size_ ? \
emplace_impl(extractor::extract(arg0, arg1), \
BOOST_UNORDERED_CALL_PARAMS(z, n)) : \
emplace_empty_impl( \
BOOST_UNORDERED_CALL_PARAMS(z, n)); \
} \
\
template <class H, class P, class A, class K> \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
BOOST_DEDUCED_TYPENAME hash_unique_table<H, P, A, K>::iterator_base \
hash_unique_table<H, P, A, K>:: \
emplace_hint(iterator_base const& it, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
{ \
return this->size_ ? \
emplace_impl(extractor::extract(arg0, arg1), \
BOOST_UNORDERED_CALL_PARAMS(z, n)) : \
emplace_empty_impl( \
BOOST_UNORDERED_CALL_PARAMS(z, n)); \
} \
BOOST_PP_REPEAT_FROM_TO(2, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_INSERT_IMPL, _)
#undef BOOST_UNORDERED_INSERT_IMPL
#endif
////////////////////////////////////////////////////////////////////////////
// Insert range methods
template <class H, class P, class A, class K>
template <class InputIt>
inline void hash_unique_table<H, P, A, K>::insert_range_impl(
key_type const&, InputIt i, InputIt j)
{
node_constructor a(*this);
if(!this->size_) {
a.construct(*i);
this->emplace_empty_impl_with_node(a, 1);
++i;
if(i == j) return;
}
do {
// No side effects in this initial code
// Note: can't use get_key as '*i' might not be value_type.
// TODO: Check if std::pair has an appropriate constructor. If not
// that might not be true.
// TODO: Test this line better.
key_type const& k = extractor::extract(*i);
std::size_t hash_value = this->hash_function()(k);
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
node_ptr pos = find_iterator(bucket, k);
if (!BOOST_UNORDERED_BORLAND_BOOL(pos)) {
// Doesn't already exist, add to bucket.
// Side effects only in this block.
// Create the node before rehashing in case it throws an
// exception (need strong safety in such a case).
a.construct(*i);
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
if(this->size_ + 1 >= this->max_load_) {
this->reserve_for_insert(this->size_ + insert_size(i, j));
bucket = this->bucket_ptr_from_hash(hash_value);
}
// Nothing after this point can throw.
add_node(a, bucket);
}
} while(++i != j);
}
template <class H, class P, class A, class K>
template <class InputIt>
inline void hash_unique_table<H, P, A, K>::insert_range_impl(
no_key, InputIt i, InputIt j)
{
node_constructor a(*this);
if(!this->size_) {
a.construct(*i);
this->emplace_empty_impl_with_node(a, 1);
++i;
if(i == j) return;
}
do {
// No side effects in this initial code
a.construct(*i);
emplace_impl_with_node(a);
} while(++i != j);
}
// if hash function throws, or inserting > 1 element, basic exception safety
// strong otherwise
template <class H, class P, class A, class K>
template <class InputIt>
void hash_unique_table<H, P, A, K>::insert_range(InputIt i, InputIt j)
{
if(i != j)
return insert_range_impl(extractor::extract(*i), i, j);
}
}}
#endif

View File

@ -14,22 +14,7 @@
#include <boost/iterator/iterator_categories.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/unordered/detail/buckets.hpp>
#if !defined(BOOST_UNORDERED_STD_FORWARD)
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#define BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
BOOST_PP_ENUM_PARAMS_Z(z, n, class Arg)
#define BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, Arg, const& arg)
#define BOOST_UNORDERED_CALL_PARAMS(z, n) \
BOOST_PP_ENUM_PARAMS_Z(z, n, arg)
#endif
#include <boost/unordered/detail/fwd.hpp>
namespace boost { namespace unordered_detail {
@ -38,7 +23,8 @@ namespace boost { namespace unordered_detail {
inline std::size_t double_to_size_t(double f)
{
return f >= static_cast<double>((std::numeric_limits<std::size_t>::max)()) ?
return f >= static_cast<double>(
(std::numeric_limits<std::size_t>::max)()) ?
(std::numeric_limits<std::size_t>::max)() :
static_cast<std::size_t>(f);
}
@ -143,7 +129,7 @@ namespace boost { namespace unordered_detail {
template <class I>
inline std::size_t initial_size(I i, I j,
std::size_t n = boost::unordered_detail::default_initial_bucket_count)
std::size_t n = boost::unordered_detail::default_bucket_count)
{
return (std::max)(static_cast<std::size_t>(insert_size(i, j)) + 1, n);
}
@ -172,29 +158,29 @@ namespace boost { namespace unordered_detail {
#else
#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, n, _) \
template < \
class T, \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
inline void construct_impl( \
T*, void* address, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
new(address) T( \
BOOST_UNORDERED_CALL_PARAMS(z, n)); \
} \
\
template <class First, class Second, class Key, \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
inline void construct_impl( \
std::pair<First, Second>*, void* address, \
Key const& k, BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
{ \
new(address) std::pair<First, Second>(k, \
Second(BOOST_UNORDERED_CALL_PARAMS(z, n))); \
#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, n, _) \
template < \
class T, \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
inline void construct_impl( \
T*, void* address, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
new(address) T( \
BOOST_UNORDERED_CALL_PARAMS(z, n)); \
} \
\
template <class First, class Second, class Key, \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
inline void construct_impl( \
std::pair<First, Second>*, void* address, \
Key const& k, BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
{ \
new(address) std::pair<First, Second>(k, \
Second(BOOST_UNORDERED_CALL_PARAMS(z, n))); \
}
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
@ -244,20 +230,20 @@ namespace boost { namespace unordered_detail {
}
#else
#define BOOST_UNORDERED_CONSTRUCT(z, n, _) \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
void construct( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
construct_preamble(); \
construct_impl( \
(value_type*) 0, node_->address(), \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
); \
value_constructed_ = true; \
#define BOOST_UNORDERED_CONSTRUCT(z, n, _) \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
void construct( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
construct_preamble(); \
construct_impl( \
(value_type*) 0, node_->address(), \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
); \
value_constructed_ = true; \
}
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
@ -274,10 +260,10 @@ namespace boost { namespace unordered_detail {
value_constructed_ = true;
}
real_node_ptr get() const
value_type& value() const
{
BOOST_ASSERT(node_);
return node_;
return node_->value();
}
// no throw
@ -297,11 +283,11 @@ namespace boost { namespace unordered_detail {
// hash_node_constructor
template <class Alloc, class Grouped>
hash_node_constructor<Alloc, Grouped>::~hash_node_constructor()
inline hash_node_constructor<Alloc, Grouped>::~hash_node_constructor()
{
if (node_) {
if (value_constructed_) {
BOOST_UNORDERED_DESTRUCT(&node_->value(), value_type);
boost::unordered_detail::destroy(&node_->value());
}
if (node_constructed_)
@ -312,7 +298,7 @@ namespace boost { namespace unordered_detail {
}
template <class Alloc, class Grouped>
void hash_node_constructor<Alloc, Grouped>::construct_preamble()
inline void hash_node_constructor<Alloc, Grouped>::construct_preamble()
{
if(!node_) {
node_constructed_ = false;
@ -324,7 +310,7 @@ namespace boost { namespace unordered_detail {
}
else {
BOOST_ASSERT(node_constructed_ && value_constructed_);
BOOST_UNORDERED_DESTRUCT(&node_->value(), value_type);
boost::unordered_detail::destroy(&node_->value());
value_constructed_ = false;
}
}

View File

@ -16,7 +16,8 @@
#include <boost/unordered/unordered_map_fwd.hpp>
#include <boost/functional/hash.hpp>
#include <boost/unordered/detail/allocator_helpers.hpp>
#include <boost/unordered/detail/insert.hpp>
#include <boost/unordered/detail/equivalent.hpp>
#include <boost/unordered/detail/unique.hpp>
#if !defined(BOOST_HAS_RVALUE_REFS)
#include <boost/unordered/detail/move.hpp>
@ -53,32 +54,41 @@ namespace boost
#endif
typedef BOOST_DEDUCED_TYPENAME
boost::unordered_detail::rebind_wrap<allocator_type, value_type>::type
boost::unordered_detail::rebind_wrap<
allocator_type, value_type>::type
value_allocator;
typedef boost::unordered_detail::hash_unique_table<Hash, Pred, value_allocator,
boost::unordered_detail::map_extractor> table;
typedef boost::unordered_detail::hash_unique_table<Hash, Pred,
value_allocator, boost::unordered_detail::map_extractor> table;
typedef BOOST_DEDUCED_TYPENAME table::iterator_base iterator_base;
public:
typedef BOOST_DEDUCED_TYPENAME value_allocator::pointer pointer;
typedef BOOST_DEDUCED_TYPENAME value_allocator::const_pointer const_pointer;
typedef BOOST_DEDUCED_TYPENAME value_allocator::reference reference;
typedef BOOST_DEDUCED_TYPENAME value_allocator::const_reference const_reference;
typedef BOOST_DEDUCED_TYPENAME
value_allocator::pointer pointer;
typedef BOOST_DEDUCED_TYPENAME
value_allocator::const_pointer const_pointer;
typedef BOOST_DEDUCED_TYPENAME
value_allocator::reference reference;
typedef BOOST_DEDUCED_TYPENAME
value_allocator::const_reference const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef boost::unordered_detail::hash_const_local_iterator<
value_allocator, boost::unordered_detail::ungrouped> const_local_iterator;
value_allocator, boost::unordered_detail::ungrouped>
const_local_iterator;
typedef boost::unordered_detail::hash_local_iterator<
value_allocator, boost::unordered_detail::ungrouped> local_iterator;
value_allocator, boost::unordered_detail::ungrouped>
local_iterator;
typedef boost::unordered_detail::hash_const_iterator<
value_allocator, boost::unordered_detail::ungrouped> const_iterator;
value_allocator, boost::unordered_detail::ungrouped>
const_iterator;
typedef boost::unordered_detail::hash_iterator<
value_allocator, boost::unordered_detail::ungrouped> iterator;
value_allocator, boost::unordered_detail::ungrouped>
iterator;
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
private:
@ -97,49 +107,51 @@ namespace boost
// construct/destroy/copy
explicit unordered_map(
size_type n = boost::unordered_detail::default_initial_bucket_count,
size_type n = boost::unordered_detail::default_bucket_count,
const hasher &hf = hasher(),
const key_equal &eql = key_equal(),
const allocator_type &a = allocator_type())
: table_(n, hf, eql, a)
: table_(n, hf, eql, a)
{
}
explicit unordered_map(allocator_type const& a)
: table_(boost::unordered_detail::default_initial_bucket_count,
: table_(boost::unordered_detail::default_bucket_count,
hasher(), key_equal(), a)
{
}
unordered_map(unordered_map const& other, allocator_type const& a)
: table_(other.table_, a)
: table_(other.table_, a)
{
}
template <class InputIterator>
unordered_map(InputIterator f, InputIterator l)
: table_(boost::unordered_detail::initial_size(f, l), hasher(), key_equal(), allocator_type())
template <class InputIt>
unordered_map(InputIt f, InputIt l)
: table_(boost::unordered_detail::initial_size(f, l),
hasher(), key_equal(), allocator_type())
{
table_.insert_range(f, l);
}
template <class InputIterator>
unordered_map(InputIterator f, InputIterator l,
template <class InputIt>
unordered_map(InputIt f, InputIt l,
size_type n,
const hasher &hf = hasher(),
const key_equal &eql = key_equal())
: table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, allocator_type())
: table_(boost::unordered_detail::initial_size(f, l, n),
hf, eql, allocator_type())
{
table_.insert_range(f, l);
}
template <class InputIterator>
unordered_map(InputIterator f, InputIterator l,
template <class InputIt>
unordered_map(InputIt f, InputIt l,
size_type n,
const hasher &hf,
const key_equal &eql,
const allocator_type &a)
: table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, a)
: table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, a)
{
table_.insert_range(f, l);
}
@ -148,12 +160,12 @@ namespace boost
#if defined(BOOST_HAS_RVALUE_REFS)
unordered_map(unordered_map&& other)
: table_(other.table_, boost::unordered_detail::move_tag())
: table_(other.table_, boost::unordered_detail::move_tag())
{
}
unordered_map(unordered_map&& other, allocator_type const& a)
: table_(other.table_, a, boost::unordered_detail::move_tag())
: table_(other.table_, a, boost::unordered_detail::move_tag())
{
}
@ -163,8 +175,10 @@ namespace boost
return *this;
}
#else
unordered_map(boost::unordered_detail::move_from<unordered_map<Key, T, Hash, Pred, Alloc> > other)
: table_(other.source.table_, boost::unordered_detail::move_tag())
unordered_map(boost::unordered_detail::move_from<
unordered_map<Key, T, Hash, Pred, Alloc>
> other)
: table_(other.source.table_, boost::unordered_detail::move_tag())
{
}
@ -179,11 +193,13 @@ namespace boost
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
unordered_map(std::initializer_list<value_type> list,
size_type n = boost::unordered_detail::default_initial_bucket_count,
size_type n = boost::unordered_detail::default_bucket_count,
const hasher &hf = hasher(),
const key_equal &eql = key_equal(),
const allocator_type &a = allocator_type())
: table_(boost::unordered_detail::initial_size(list.begin(), list.end(), n), hf, eql, allocator_type())
: table_(boost::unordered_detail::initial_size(
list.begin(), list.end(), n),
hf, eql, allocator_type())
{
table_.insert_range(list.begin(), list.end());
}
@ -263,7 +279,8 @@ namespace boost
template <class... Args>
iterator emplace_hint(const_iterator hint, Args&&... args)
{
return iterator(table_.emplace_hint(get(hint), std::forward<Args>(args)...));
return iterator(
table_.emplace_hint(get(hint), std::forward<Args>(args)...));
}
#else
@ -273,35 +290,36 @@ namespace boost
table_.emplace(v));
}
iterator emplace_hint(const_iterator hint, value_type const& v = value_type())
iterator emplace_hint(const_iterator hint,
value_type const& v = value_type())
{
return iterator(table_.emplace_hint(get(hint), v));
}
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
std::pair<iterator, bool> emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return boost::unordered_detail::pair_cast<iterator, bool>( \
table_.emplace( \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
)); \
} \
\
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
iterator emplace_hint(const_iterator hint, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return iterator(table_.emplace_hint(get(hint), \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
)); \
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
std::pair<iterator, bool> emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return boost::unordered_detail::pair_cast<iterator, bool>( \
table_.emplace( \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
)); \
} \
\
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
iterator emplace_hint(const_iterator hint, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return iterator(table_.emplace_hint(get(hint), \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
)); \
}
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
@ -322,8 +340,8 @@ namespace boost
return iterator(table_.emplace_hint(get(hint), obj));
}
template <class InputIterator>
void insert(InputIterator first, InputIterator last)
template <class InputIt>
void insert(InputIt first, InputIt last)
{
table_.insert_range(first, last);
}
@ -400,14 +418,16 @@ namespace boost
std::pair<iterator, iterator>
equal_range(const key_type& k)
{
return boost::unordered_detail::pair_cast<iterator, iterator>(
return boost::unordered_detail::pair_cast<
iterator, iterator>(
table_.equal_range(k));
}
std::pair<const_iterator, const_iterator>
equal_range(const key_type& k) const
{
return boost::unordered_detail::pair_cast<const_iterator, const_iterator>(
return boost::unordered_detail::pair_cast<
const_iterator, const_iterator>(
table_.equal_range(k));
}
@ -415,7 +435,7 @@ namespace boost
size_type bucket_count() const
{
return table_.bucket_count();
return table_.bucket_count_;
}
size_type max_bucket_count() const
@ -443,14 +463,14 @@ namespace boost
return const_local_iterator(table_.bucket_begin(n));
}
local_iterator end(size_type n)
local_iterator end(size_type)
{
return local_iterator(table_.bucket_end(n));
return local_iterator();
}
const_local_iterator end(size_type n) const
const_local_iterator end(size_type) const
{
return const_local_iterator(table_.bucket_end(n));
return const_local_iterator();
}
const_local_iterator cbegin(size_type n) const
@ -458,9 +478,9 @@ namespace boost
return const_local_iterator(table_.bucket_begin(n));
}
const_local_iterator cend(size_type n) const
const_local_iterator cend(size_type) const
{
return const_local_iterator(table_.bucket_end(n));
return const_local_iterator();
}
// hash policy
@ -486,8 +506,10 @@ namespace boost
}
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
friend bool operator==<Key, T, Hash, Pred, Alloc>(unordered_map const&, unordered_map const&);
friend bool operator!=<Key, T, Hash, Pred, Alloc>(unordered_map const&, unordered_map const&);
friend bool operator==<Key, T, Hash, Pred, Alloc>(
unordered_map const&, unordered_map const&);
friend bool operator!=<Key, T, Hash, Pred, Alloc>(
unordered_map const&, unordered_map const&);
#endif
}; // class template unordered_map
@ -528,31 +550,40 @@ namespace boost
private:
#endif
typedef BOOST_DEDUCED_TYPENAME
boost::unordered_detail::rebind_wrap<allocator_type, value_type>::type
boost::unordered_detail::rebind_wrap<
allocator_type, value_type>::type
value_allocator;
typedef boost::unordered_detail::hash_equivalent_table<Hash, Pred, value_allocator,
boost::unordered_detail::map_extractor> table;
typedef boost::unordered_detail::hash_equivalent_table<Hash, Pred,
value_allocator, boost::unordered_detail::map_extractor> table;
typedef BOOST_DEDUCED_TYPENAME table::iterator_base iterator_base;
public:
typedef BOOST_DEDUCED_TYPENAME value_allocator::pointer pointer;
typedef BOOST_DEDUCED_TYPENAME value_allocator::const_pointer const_pointer;
typedef BOOST_DEDUCED_TYPENAME value_allocator::reference reference;
typedef BOOST_DEDUCED_TYPENAME value_allocator::const_reference const_reference;
typedef BOOST_DEDUCED_TYPENAME
value_allocator::pointer pointer;
typedef BOOST_DEDUCED_TYPENAME
value_allocator::const_pointer const_pointer;
typedef BOOST_DEDUCED_TYPENAME
value_allocator::reference reference;
typedef BOOST_DEDUCED_TYPENAME
value_allocator::const_reference const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef boost::unordered_detail::hash_const_local_iterator<
value_allocator, boost::unordered_detail::grouped> const_local_iterator;
value_allocator, boost::unordered_detail::grouped>
const_local_iterator;
typedef boost::unordered_detail::hash_local_iterator<
value_allocator, boost::unordered_detail::grouped> local_iterator;
value_allocator, boost::unordered_detail::grouped>
local_iterator;
typedef boost::unordered_detail::hash_const_iterator<
value_allocator, boost::unordered_detail::grouped> const_iterator;
value_allocator, boost::unordered_detail::grouped>
const_iterator;
typedef boost::unordered_detail::hash_iterator<
value_allocator, boost::unordered_detail::grouped> iterator;
value_allocator, boost::unordered_detail::grouped>
iterator;
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
private:
@ -571,7 +602,7 @@ namespace boost
// construct/destroy/copy
explicit unordered_multimap(
size_type n = boost::unordered_detail::default_initial_bucket_count,
size_type n = boost::unordered_detail::default_bucket_count,
const hasher &hf = hasher(),
const key_equal &eql = key_equal(),
const allocator_type &a = allocator_type())
@ -580,35 +611,38 @@ namespace boost
}
explicit unordered_multimap(allocator_type const& a)
: table_(boost::unordered_detail::default_initial_bucket_count,
: table_(boost::unordered_detail::default_bucket_count,
hasher(), key_equal(), a)
{
}
unordered_multimap(unordered_multimap const& other, allocator_type const& a)
: table_(other.table_, a)
unordered_multimap(unordered_multimap const& other,
allocator_type const& a)
: table_(other.table_, a)
{
}
template <class InputIterator>
unordered_multimap(InputIterator f, InputIterator l)
: table_(boost::unordered_detail::initial_size(f, l), hasher(), key_equal(), allocator_type())
template <class InputIt>
unordered_multimap(InputIt f, InputIt l)
: table_(boost::unordered_detail::initial_size(f, l),
hasher(), key_equal(), allocator_type())
{
table_.insert_range(f, l);
}
template <class InputIterator>
unordered_multimap(InputIterator f, InputIterator l,
template <class InputIt>
unordered_multimap(InputIt f, InputIt l,
size_type n,
const hasher &hf = hasher(),
const key_equal &eql = key_equal())
: table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, allocator_type())
: table_(boost::unordered_detail::initial_size(f, l, n),
hf, eql, allocator_type())
{
table_.insert_range(f, l);
}
template <class InputIterator>
unordered_multimap(InputIterator f, InputIterator l,
template <class InputIt>
unordered_multimap(InputIt f, InputIt l,
size_type n,
const hasher &hf,
const key_equal &eql,
@ -622,12 +656,12 @@ namespace boost
#if defined(BOOST_HAS_RVALUE_REFS)
unordered_multimap(unordered_multimap&& other)
: table_(other.table_, boost::unordered_detail::move_tag())
: table_(other.table_, boost::unordered_detail::move_tag())
{
}
unordered_multimap(unordered_multimap&& other, allocator_type const& a)
: table_(other.table_, a, boost::unordered_detail::move_tag())
: table_(other.table_, a, boost::unordered_detail::move_tag())
{
}
@ -637,8 +671,10 @@ namespace boost
return *this;
}
#else
unordered_multimap(boost::unordered_detail::move_from<unordered_multimap<Key, T, Hash, Pred, Alloc> > other)
: table_(other.source.table_, boost::unordered_detail::move_tag())
unordered_multimap(boost::unordered_detail::move_from<
unordered_multimap<Key, T, Hash, Pred, Alloc>
> other)
: table_(other.source.table_, boost::unordered_detail::move_tag())
{
}
@ -653,11 +689,13 @@ namespace boost
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
unordered_multimap(std::initializer_list<value_type> list,
size_type n = boost::unordered_detail::default_initial_bucket_count,
size_type n = boost::unordered_detail::default_bucket_count,
const hasher &hf = hasher(),
const key_equal &eql = key_equal(),
const allocator_type &a = allocator_type())
: table_(boost::unordered_detail::initial_size(list.begin(), list.end(), n), hf, eql, allocator_type())
: table_(boost::unordered_detail::initial_size(
list.begin(), list.end(), n),
hf, eql, allocator_type())
{
table_.insert_range(list.begin(), list.end());
}
@ -736,7 +774,8 @@ namespace boost
template <class... Args>
iterator emplace_hint(const_iterator hint, Args&&... args)
{
return iterator(table_.emplace_hint(get(hint), std::forward<Args>(args)...));
return iterator(table_.emplace_hint(get(hint),
std::forward<Args>(args)...));
}
#else
@ -745,36 +784,37 @@ namespace boost
return iterator(table_.emplace(v));
}
iterator emplace_hint(const_iterator hint, value_type const& v = value_type())
iterator emplace_hint(const_iterator hint,
value_type const& v = value_type())
{
return iterator(table_.emplace_hint(get(hint), v));
}
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
iterator emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return iterator( \
table_.emplace( \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
)); \
} \
\
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
iterator emplace_hint(const_iterator hint, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return iterator(table_.emplace_hint(get(hint), \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
)); \
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
iterator emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return iterator( \
table_.emplace( \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
)); \
} \
\
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
iterator emplace_hint(const_iterator hint, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return iterator(table_.emplace_hint(get(hint), \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
)); \
}
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
@ -794,8 +834,8 @@ namespace boost
return iterator(table_.emplace_hint(get(hint), obj));
}
template <class InputIterator>
void insert(InputIterator first, InputIterator last)
template <class InputIt>
void insert(InputIt first, InputIt last)
{
table_.insert_range(first, last);
}
@ -857,14 +897,16 @@ namespace boost
std::pair<iterator, iterator>
equal_range(const key_type& k)
{
return boost::unordered_detail::pair_cast<iterator, iterator>(
return boost::unordered_detail::pair_cast<
iterator, iterator>(
table_.equal_range(k));
}
std::pair<const_iterator, const_iterator>
equal_range(const key_type& k) const
{
return boost::unordered_detail::pair_cast<const_iterator, const_iterator>(
return boost::unordered_detail::pair_cast<
const_iterator, const_iterator>(
table_.equal_range(k));
}
@ -872,7 +914,7 @@ namespace boost
size_type bucket_count() const
{
return table_.bucket_count();
return table_.bucket_count_;
}
size_type max_bucket_count() const
@ -900,14 +942,14 @@ namespace boost
return const_local_iterator(table_.bucket_begin(n));
}
local_iterator end(size_type n)
local_iterator end(size_type)
{
return local_iterator(table_.bucket_end(n));
return local_iterator();
}
const_local_iterator end(size_type n) const
const_local_iterator end(size_type) const
{
return const_local_iterator(table_.bucket_end(n));
return const_local_iterator();
}
const_local_iterator cbegin(size_type n) const
@ -915,9 +957,9 @@ namespace boost
return const_local_iterator(table_.bucket_begin(n));
}
const_local_iterator cend(size_type n) const
const_local_iterator cend(size_type) const
{
return const_local_iterator(table_.bucket_end(n));
return const_local_iterator();
}
// hash policy
@ -943,8 +985,10 @@ namespace boost
}
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
friend bool operator==<Key, T, Hash, Pred, Alloc>(unordered_multimap const&, unordered_multimap const&);
friend bool operator!=<Key, T, Hash, Pred, Alloc>(unordered_multimap const&, unordered_multimap const&);
friend bool operator==<Key, T, Hash, Pred, Alloc>(
unordered_multimap const&, unordered_multimap const&);
friend bool operator!=<Key, T, Hash, Pred, Alloc>(
unordered_multimap const&, unordered_multimap const&);
#endif
}; // class template unordered_multimap

View File

@ -16,7 +16,8 @@
#include <boost/unordered/unordered_set_fwd.hpp>
#include <boost/functional/hash.hpp>
#include <boost/unordered/detail/allocator_helpers.hpp>
#include <boost/unordered/detail/insert.hpp>
#include <boost/unordered/detail/equivalent.hpp>
#include <boost/unordered/detail/unique.hpp>
#if !defined(BOOST_HAS_RVALUE_REFS)
#include <boost/unordered/detail/move.hpp>
@ -53,27 +54,34 @@ namespace boost
#endif
typedef BOOST_DEDUCED_TYPENAME
boost::unordered_detail::rebind_wrap<allocator_type, value_type>::type
boost::unordered_detail::rebind_wrap<
allocator_type, value_type>::type
value_allocator;
typedef boost::unordered_detail::hash_unique_table<Hash, Pred, value_allocator,
boost::unordered_detail::set_extractor> table;
typedef boost::unordered_detail::hash_unique_table<Hash, Pred,
value_allocator, boost::unordered_detail::set_extractor> table;
typedef BOOST_DEDUCED_TYPENAME table::iterator_base iterator_base;
public:
typedef BOOST_DEDUCED_TYPENAME value_allocator::pointer pointer;
typedef BOOST_DEDUCED_TYPENAME value_allocator::const_pointer const_pointer;
typedef BOOST_DEDUCED_TYPENAME value_allocator::reference reference;
typedef BOOST_DEDUCED_TYPENAME value_allocator::const_reference const_reference;
typedef BOOST_DEDUCED_TYPENAME
value_allocator::pointer pointer;
typedef BOOST_DEDUCED_TYPENAME
value_allocator::const_pointer const_pointer;
typedef BOOST_DEDUCED_TYPENAME
value_allocator::reference reference;
typedef BOOST_DEDUCED_TYPENAME
value_allocator::const_reference const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef boost::unordered_detail::hash_const_local_iterator<
value_allocator, boost::unordered_detail::ungrouped> const_local_iterator;
value_allocator, boost::unordered_detail::ungrouped>
const_local_iterator;
typedef boost::unordered_detail::hash_const_iterator<
value_allocator, boost::unordered_detail::ungrouped> const_iterator;
value_allocator, boost::unordered_detail::ungrouped>
const_iterator;
typedef const_local_iterator local_iterator;
typedef const_iterator iterator;
@ -94,47 +102,49 @@ namespace boost
// construct/destroy/copy
explicit unordered_set(
size_type n = boost::unordered_detail::default_initial_bucket_count,
size_type n = boost::unordered_detail::default_bucket_count,
const hasher &hf = hasher(),
const key_equal &eql = key_equal(),
const allocator_type &a = allocator_type())
: table_(n, hf, eql, a)
: table_(n, hf, eql, a)
{
}
explicit unordered_set(allocator_type const& a)
: table_(boost::unordered_detail::default_initial_bucket_count,
: table_(boost::unordered_detail::default_bucket_count,
hasher(), key_equal(), a)
{
}
unordered_set(unordered_set const& other, allocator_type const& a)
: table_(other.table_, a)
: table_(other.table_, a)
{
}
template <class InputIterator>
unordered_set(InputIterator f, InputIterator l)
: table_(boost::unordered_detail::initial_size(f, l), hasher(), key_equal(), allocator_type())
template <class InputIt>
unordered_set(InputIt f, InputIt l)
: table_(boost::unordered_detail::initial_size(f, l),
hasher(), key_equal(), allocator_type())
{
table_.insert_range(f, l);
}
template <class InputIterator>
unordered_set(InputIterator f, InputIterator l, size_type n,
template <class InputIt>
unordered_set(InputIt f, InputIt l, size_type n,
const hasher &hf = hasher(),
const key_equal &eql = key_equal())
: table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, allocator_type())
: table_(boost::unordered_detail::initial_size(f, l, n),
hf, eql, allocator_type())
{
table_.insert_range(f, l);
}
template <class InputIterator>
unordered_set(InputIterator f, InputIterator l, size_type n,
template <class InputIt>
unordered_set(InputIt f, InputIt l, size_type n,
const hasher &hf,
const key_equal &eql,
const allocator_type &a)
: table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, a)
: table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, a)
{
table_.insert_range(f, l);
}
@ -143,12 +153,12 @@ namespace boost
#if defined(BOOST_HAS_RVALUE_REFS)
unordered_set(unordered_set&& other)
: table_(other.table_, boost::unordered_detail::move_tag())
: table_(other.table_, boost::unordered_detail::move_tag())
{
}
unordered_set(unordered_set&& other, allocator_type const& a)
: table_(other.table_, a, boost::unordered_detail::move_tag())
: table_(other.table_, a, boost::unordered_detail::move_tag())
{
}
@ -158,8 +168,10 @@ namespace boost
return *this;
}
#else
unordered_set(boost::unordered_detail::move_from<unordered_set<Value, Hash, Pred, Alloc> > other)
: table_(other.source.table_, boost::unordered_detail::move_tag())
unordered_set(boost::unordered_detail::move_from<
unordered_set<Value, Hash, Pred, Alloc>
> other)
: table_(other.source.table_, boost::unordered_detail::move_tag())
{
}
@ -174,11 +186,13 @@ namespace boost
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
unordered_set(std::initializer_list<value_type> list,
size_type n = boost::unordered_detail::default_initial_bucket_count,
size_type n = boost::unordered_detail::default_bucket_count,
const hasher &hf = hasher(),
const key_equal &eql = key_equal(),
const allocator_type &a = allocator_type())
: table_(boost::unordered_detail::initial_size(list.begin(), list.end(), n), hf, eql, allocator_type())
: table_(boost::unordered_detail::initial_size(
list.begin(), list.end(), n),
hf, eql, allocator_type())
{
table_.insert_range(list.begin(), list.end());
}
@ -269,35 +283,36 @@ namespace boost
table_.emplace(v));
}
iterator emplace_hint(const_iterator hint, value_type const& v = value_type())
iterator emplace_hint(const_iterator hint,
value_type const& v = value_type())
{
return iterator(table_.emplace_hint(get(hint), v));
}
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
std::pair<iterator, bool> emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return boost::unordered_detail::pair_cast<iterator, bool>( \
table_.emplace( \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
)); \
} \
\
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
iterator emplace_hint(const_iterator hint, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return iterator(table_.emplace_hint(get(hint), \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
)); \
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
std::pair<iterator, bool> emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return boost::unordered_detail::pair_cast<iterator, bool>( \
table_.emplace( \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
)); \
} \
\
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
iterator emplace_hint(const_iterator hint, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return iterator(table_.emplace_hint(get(hint), \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
)); \
}
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
@ -318,8 +333,8 @@ namespace boost
return iterator(table_.emplace_hint(get(hint), obj));
}
template <class InputIterator>
void insert(InputIterator first, InputIterator last)
template <class InputIt>
void insert(InputIt first, InputIt last)
{
table_.insert_range(first, last);
}
@ -376,7 +391,8 @@ namespace boost
std::pair<const_iterator, const_iterator>
equal_range(const key_type& k) const
{
return boost::unordered_detail::pair_cast<const_iterator, const_iterator>(
return boost::unordered_detail::pair_cast<
const_iterator, const_iterator>(
table_.equal_range(k));
}
@ -384,7 +400,7 @@ namespace boost
size_type bucket_count() const
{
return table_.bucket_count();
return table_.bucket_count_;
}
size_type max_bucket_count() const
@ -412,14 +428,14 @@ namespace boost
return const_local_iterator(table_.bucket_begin(n));
}
local_iterator end(size_type n)
local_iterator end(size_type)
{
return local_iterator(table_.bucket_end(n));
return local_iterator();
}
const_local_iterator end(size_type n) const
const_local_iterator end(size_type) const
{
return const_local_iterator(table_.bucket_end(n));
return const_local_iterator();
}
const_local_iterator cbegin(size_type n) const
@ -427,9 +443,9 @@ namespace boost
return const_local_iterator(table_.bucket_begin(n));
}
const_local_iterator cend(size_type n) const
const_local_iterator cend(size_type) const
{
return const_local_iterator(table_.bucket_end(n));
return const_local_iterator();
}
// hash policy
@ -455,8 +471,10 @@ namespace boost
}
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
friend bool operator==<Value, Hash, Pred, Alloc>(unordered_set const&, unordered_set const&);
friend bool operator!=<Value, Hash, Pred, Alloc>(unordered_set const&, unordered_set const&);
friend bool operator==<Value, Hash, Pred, Alloc>(
unordered_set const&, unordered_set const&);
friend bool operator!=<Value, Hash, Pred, Alloc>(
unordered_set const&, unordered_set const&);
#endif
}; // class template unordered_set
@ -496,27 +514,34 @@ namespace boost
private:
#endif
typedef BOOST_DEDUCED_TYPENAME
boost::unordered_detail::rebind_wrap<allocator_type, value_type>::type
boost::unordered_detail::rebind_wrap<
allocator_type, value_type>::type
value_allocator;
typedef boost::unordered_detail::hash_equivalent_table<Hash, Pred, value_allocator,
boost::unordered_detail::set_extractor> table;
typedef boost::unordered_detail::hash_equivalent_table<Hash, Pred,
value_allocator, boost::unordered_detail::set_extractor> table;
typedef BOOST_DEDUCED_TYPENAME table::iterator_base iterator_base;
public:
typedef BOOST_DEDUCED_TYPENAME value_allocator::pointer pointer;
typedef BOOST_DEDUCED_TYPENAME value_allocator::const_pointer const_pointer;
typedef BOOST_DEDUCED_TYPENAME value_allocator::reference reference;
typedef BOOST_DEDUCED_TYPENAME value_allocator::const_reference const_reference;
typedef BOOST_DEDUCED_TYPENAME
value_allocator::pointer pointer;
typedef BOOST_DEDUCED_TYPENAME
value_allocator::const_pointer const_pointer;
typedef BOOST_DEDUCED_TYPENAME
value_allocator::reference reference;
typedef BOOST_DEDUCED_TYPENAME
value_allocator::const_reference const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef boost::unordered_detail::hash_const_local_iterator<
value_allocator, boost::unordered_detail::grouped> const_local_iterator;
value_allocator, boost::unordered_detail::grouped>
const_local_iterator;
typedef boost::unordered_detail::hash_const_iterator<
value_allocator, boost::unordered_detail::grouped> const_iterator;
value_allocator, boost::unordered_detail::grouped>
const_iterator;
typedef const_local_iterator local_iterator;
typedef const_iterator iterator;
@ -537,7 +562,7 @@ namespace boost
// construct/destroy/copy
explicit unordered_multiset(
size_type n = boost::unordered_detail::default_initial_bucket_count,
size_type n = boost::unordered_detail::default_bucket_count,
const hasher &hf = hasher(),
const key_equal &eql = key_equal(),
const allocator_type &a = allocator_type())
@ -546,34 +571,37 @@ namespace boost
}
explicit unordered_multiset(allocator_type const& a)
: table_(boost::unordered_detail::default_initial_bucket_count,
: table_(boost::unordered_detail::default_bucket_count,
hasher(), key_equal(), a)
{
}
unordered_multiset(unordered_multiset const& other, allocator_type const& a)
: table_(other.table_, a)
unordered_multiset(unordered_multiset const& other,
allocator_type const& a)
: table_(other.table_, a)
{
}
template <class InputIterator>
unordered_multiset(InputIterator f, InputIterator l)
: table_(boost::unordered_detail::initial_size(f, l), hasher(), key_equal(), allocator_type())
template <class InputIt>
unordered_multiset(InputIt f, InputIt l)
: table_(boost::unordered_detail::initial_size(f, l),
hasher(), key_equal(), allocator_type())
{
table_.insert_range(f, l);
}
template <class InputIterator>
unordered_multiset(InputIterator f, InputIterator l, size_type n,
template <class InputIt>
unordered_multiset(InputIt f, InputIt l, size_type n,
const hasher &hf = hasher(),
const key_equal &eql = key_equal())
: table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, allocator_type())
: table_(boost::unordered_detail::initial_size(f, l, n),
hf, eql, allocator_type())
{
table_.insert_range(f, l);
}
template <class InputIterator>
unordered_multiset(InputIterator f, InputIterator l, size_type n,
template <class InputIt>
unordered_multiset(InputIt f, InputIt l, size_type n,
const hasher &hf,
const key_equal &eql,
const allocator_type &a)
@ -586,12 +614,12 @@ namespace boost
#if defined(BOOST_HAS_RVALUE_REFS)
unordered_multiset(unordered_multiset&& other)
: table_(other.table_, boost::unordered_detail::move_tag())
: table_(other.table_, boost::unordered_detail::move_tag())
{
}
unordered_multiset(unordered_multiset&& other, allocator_type const& a)
: table_(other.table_, a, boost::unordered_detail::move_tag())
: table_(other.table_, a, boost::unordered_detail::move_tag())
{
}
@ -601,8 +629,10 @@ namespace boost
return *this;
}
#else
unordered_multiset(boost::unordered_detail::move_from<unordered_multiset<Value, Hash, Pred, Alloc> > other)
: table_(other.source.table_, boost::unordered_detail::move_tag())
unordered_multiset(boost::unordered_detail::move_from<
unordered_multiset<Value, Hash, Pred, Alloc>
> other)
: table_(other.source.table_, boost::unordered_detail::move_tag())
{
}
@ -617,11 +647,13 @@ namespace boost
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
unordered_multiset(std::initializer_list<value_type> list,
size_type n = boost::unordered_detail::default_initial_bucket_count,
size_type n = boost::unordered_detail::default_bucket_count,
const hasher &hf = hasher(),
const key_equal &eql = key_equal(),
const allocator_type &a = allocator_type())
: table_(boost::unordered_detail::initial_size(list.begin(), list.end(), n), hf, eql, allocator_type())
: table_(boost::unordered_detail::initial_size(
list.begin(), list.end(), n),
hf, eql, allocator_type())
{
table_.insert_range(list.begin(), list.end());
}
@ -700,7 +732,8 @@ namespace boost
template <class... Args>
iterator emplace_hint(const_iterator hint, Args&&... args)
{
return iterator(table_.emplace_hint(get(hint), std::forward<Args>(args)...));
return iterator(table_.emplace_hint(get(hint),
std::forward<Args>(args)...));
}
#else
@ -709,33 +742,34 @@ namespace boost
return iterator(table_.emplace(v));
}
iterator emplace_hint(const_iterator hint, value_type const& v = value_type())
iterator emplace_hint(const_iterator hint,
value_type const& v = value_type())
{
return iterator(table_.emplace_hint(get(hint), v));
}
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
iterator emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return iterator( \
table_.emplace(BOOST_UNORDERED_CALL_PARAMS(z, n))); \
} \
\
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
iterator emplace_hint(const_iterator hint, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return iterator(table_.emplace_hint(get(hint), \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
)); \
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
iterator emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return iterator( \
table_.emplace(BOOST_UNORDERED_CALL_PARAMS(z, n))); \
} \
\
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
iterator emplace_hint(const_iterator hint, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return iterator(table_.emplace_hint(get(hint), \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
)); \
}
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
@ -755,8 +789,8 @@ namespace boost
return iterator(table_.emplace_hint(get(hint), obj));
}
template <class InputIterator>
void insert(InputIterator first, InputIterator last)
template <class InputIt>
void insert(InputIt first, InputIt last)
{
table_.insert_range(first, last);
}
@ -813,7 +847,8 @@ namespace boost
std::pair<const_iterator, const_iterator>
equal_range(const key_type& k) const
{
return boost::unordered_detail::pair_cast<const_iterator, const_iterator>(
return boost::unordered_detail::pair_cast<
const_iterator, const_iterator>(
table_.equal_range(k));
}
@ -821,7 +856,7 @@ namespace boost
size_type bucket_count() const
{
return table_.bucket_count();
return table_.bucket_count_;
}
size_type max_bucket_count() const
@ -849,14 +884,14 @@ namespace boost
return const_local_iterator(table_.bucket_begin(n));
}
local_iterator end(size_type n)
local_iterator end(size_type)
{
return local_iterator(table_.bucket_end(n));
return local_iterator();
}
const_local_iterator end(size_type n) const
const_local_iterator end(size_type) const
{
return const_local_iterator(table_.bucket_end(n));
return const_local_iterator();
}
const_local_iterator cbegin(size_type n) const
@ -864,9 +899,9 @@ namespace boost
return const_local_iterator(table_.bucket_begin(n));
}
const_local_iterator cend(size_type n) const
const_local_iterator cend(size_type) const
{
return const_local_iterator(table_.bucket_end(n));
return const_local_iterator();
}
// hash policy
@ -892,8 +927,10 @@ namespace boost
}
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
friend bool operator==<Value, Hash, Pred, Alloc>(unordered_multiset const&, unordered_multiset const&);
friend bool operator!=<Value, Hash, Pred, Alloc>(unordered_multiset const&, unordered_multiset const&);
friend bool operator==<Value, Hash, Pred, Alloc>(
unordered_multiset const&, unordered_multiset const&);
friend bool operator!=<Value, Hash, Pred, Alloc>(
unordered_multiset const&, unordered_multiset const&);
#endif
}; // class template unordered_multiset

View File

@ -21,14 +21,17 @@ namespace test
namespace test_detail
{
template <typename T> struct list_node;
template <typename T> class list_node;
template <typename T> class list_data;
template <typename T> class list_iterator;
template <typename T> class list_const_iterator;
template <typename T>
struct list_node
class list_node
{
list_node(list_node const&);
list_node& operator=(list_node const&);
public:
T value_;
list_node* next_;
@ -243,8 +246,8 @@ namespace test
node** merge_adjacent_ranges(node** first, node** second,
node** third, Less less)
{
while(true) {
while(true) {
for(;;) {
for(;;) {
if(first == second) return third;
if(less((*second)->value_, (*first)->value_)) break;
first = &(*first)->next_;
@ -256,7 +259,7 @@ namespace test
// Since the two ranges we just swapped, the order is now:
// first...third...second
while(true) {
for(;;) {
if(first == third) return second;
if(!less((*first)->value_, (*third)->value_)) break;
first = &(*first)->next_;

View File

@ -116,7 +116,7 @@ bool compare(Range1 const& x, Range2 const& y)
}
template <class Container>
bool general_erase_range_test(Container& x, int start, int end)
bool general_erase_range_test(Container& x, std::size_t start, std::size_t end)
{
collide_list l(x.begin(), x.end());
l.erase(boost::next(l.begin(), start), boost::next(l.begin(), end));

View File

@ -10,7 +10,7 @@ struct foo {
template <class T>
template <class U>
bool foo<T>::bar(U x) { return x; }
bool foo<T>::bar(U x) { return x ? true : false; }
int main() {
foo<int> x;