2009-09-04 07:03:04 +00:00
|
|
|
|
|
|
|
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
2011-06-04 16:17:07 +00:00
|
|
|
// Copyright (C) 2005-2011 Daniel James
|
2009-09-04 07:03:04 +00:00
|
|
|
// 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_MANAGER_HPP_INCLUDED
|
|
|
|
#define BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED
|
|
|
|
|
|
|
|
#include <boost/unordered/detail/node.hpp>
|
|
|
|
|
2011-04-16 18:47:33 +00:00
|
|
|
namespace boost { namespace unordered { namespace detail {
|
2009-09-04 07:03:04 +00:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
2011-04-16 18:47:33 +00:00
|
|
|
//
|
|
|
|
// Now the main data structure:
|
|
|
|
//
|
2011-04-17 00:31:35 +00:00
|
|
|
// buckets<A, Unique> functions<H, P>
|
2011-04-16 18:47:33 +00:00
|
|
|
// | |
|
|
|
|
// +---------------+--------------+
|
|
|
|
// |
|
|
|
|
// table<T>
|
|
|
|
//
|
|
|
|
// T is a class which contains typedefs for all the types we need.
|
2009-09-04 07:03:04 +00:00
|
|
|
|
2011-04-16 18:47:33 +00:00
|
|
|
// buckets
|
|
|
|
//
|
|
|
|
// This is responsible for allocating and deallocating buckets and nodes.
|
|
|
|
//
|
|
|
|
// Notes:
|
|
|
|
// 1. For the sake exception safety the consturctors 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).
|
2009-10-25 10:55:08 +00:00
|
|
|
|
2011-04-16 18:47:33 +00:00
|
|
|
template <class A, bool Unique>
|
|
|
|
class buckets
|
2009-09-04 07:03:04 +00:00
|
|
|
{
|
2011-04-16 18:47:33 +00:00
|
|
|
buckets(buckets const&);
|
|
|
|
buckets& operator=(buckets const&);
|
|
|
|
public:
|
|
|
|
// Types
|
2009-09-04 07:03:04 +00:00
|
|
|
|
2011-04-16 18:47:33 +00:00
|
|
|
typedef BOOST_DEDUCED_TYPENAME ::boost::detail::if_true<Unique>::
|
|
|
|
BOOST_NESTED_TEMPLATE then<
|
|
|
|
::boost::unordered::detail::ungrouped_node<A>,
|
|
|
|
::boost::unordered::detail::grouped_node<A>
|
|
|
|
>::type node;
|
|
|
|
|
|
|
|
typedef A value_allocator;
|
|
|
|
typedef ::boost::unordered::detail::bucket<A> bucket;
|
2011-08-11 21:17:57 +00:00
|
|
|
typedef BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type value_type;
|
2011-04-16 18:47:33 +00:00
|
|
|
|
|
|
|
typedef BOOST_DEDUCED_TYPENAME bucket::bucket_allocator
|
|
|
|
bucket_allocator;
|
2011-08-11 21:17:57 +00:00
|
|
|
typedef BOOST_DEDUCED_TYPENAME allocator_traits<bucket_allocator>::pointer bucket_ptr;
|
2011-04-16 18:47:33 +00:00
|
|
|
typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr;
|
|
|
|
|
|
|
|
typedef BOOST_DEDUCED_TYPENAME rebind_wrap<value_allocator, node>::type
|
|
|
|
node_allocator;
|
2011-08-11 21:17:57 +00:00
|
|
|
typedef BOOST_DEDUCED_TYPENAME allocator_traits<node_allocator>::pointer real_node_ptr;
|
2011-04-16 18:47:33 +00:00
|
|
|
|
|
|
|
// Members
|
|
|
|
|
|
|
|
bucket_ptr buckets_;
|
|
|
|
std::size_t bucket_count_;
|
|
|
|
::boost::compressed_pair<bucket_allocator, node_allocator> allocators_;
|
|
|
|
|
|
|
|
// 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();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::size_t max_bucket_count() const
|
|
|
|
{
|
|
|
|
// -1 to account for the start bucket.
|
2011-08-11 21:17:57 +00:00
|
|
|
return prev_prime(allocator_traits<bucket_allocator>::max_size(bucket_alloc()) - 1);
|
2011-04-16 18:47:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// Constructors and Destructors
|
|
|
|
|
|
|
|
buckets(node_allocator const& a, std::size_t bucket_count)
|
|
|
|
: buckets_(),
|
|
|
|
bucket_count_(bucket_count),
|
|
|
|
allocators_(a,a)
|
|
|
|
{
|
|
|
|
}
|
2011-08-11 21:18:19 +00:00
|
|
|
|
|
|
|
// TODO: Need to move allocators_, not copy. But compressed_pair
|
|
|
|
// doesn't support move parameters.
|
|
|
|
buckets(buckets& b, move_tag m)
|
|
|
|
: buckets_(),
|
|
|
|
bucket_count_(b.bucket_count),
|
|
|
|
allocators_(b.allocators_)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2011-04-16 18:47:33 +00:00
|
|
|
inline ~buckets()
|
|
|
|
{
|
|
|
|
if(this->buckets_) { this->delete_buckets(); }
|
|
|
|
}
|
|
|
|
|
|
|
|
void create_buckets()
|
|
|
|
{
|
|
|
|
// The array constructor will clean up in the event of an
|
|
|
|
// exception.
|
|
|
|
allocator_array_constructor<bucket_allocator>
|
|
|
|
constructor(bucket_alloc());
|
|
|
|
|
|
|
|
// Creates an extra bucket to act as the start node.
|
|
|
|
constructor.construct(bucket(), this->bucket_count_ + 1);
|
|
|
|
|
|
|
|
// Only release the buckets once everything is successfully
|
|
|
|
// done.
|
|
|
|
this->buckets_ = constructor.release();
|
|
|
|
}
|
|
|
|
|
|
|
|
// no throw
|
|
|
|
void swap(buckets& other)
|
|
|
|
{
|
|
|
|
BOOST_ASSERT(node_alloc() == other.node_alloc());
|
|
|
|
std::swap(buckets_, other.buckets_);
|
|
|
|
std::swap(bucket_count_, other.bucket_count_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void move(buckets& other)
|
|
|
|
{
|
|
|
|
BOOST_ASSERT(node_alloc() == other.node_alloc());
|
|
|
|
if(this->buckets_) { this->delete_buckets(); }
|
|
|
|
this->buckets_ = other.buckets_;
|
|
|
|
this->bucket_count_ = other.bucket_count_;
|
|
|
|
other.buckets_ = bucket_ptr();
|
|
|
|
other.bucket_count_ = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::size_t bucket_size(std::size_t index) const
|
|
|
|
{
|
|
|
|
if (!this->buckets_) return 0;
|
|
|
|
node_ptr ptr = this->buckets_[index].next_;
|
|
|
|
if (!ptr) return 0;
|
2009-09-20 21:55:15 +00:00
|
|
|
ptr = ptr->next_;
|
2011-04-16 18:47:33 +00:00
|
|
|
|
|
|
|
std::size_t count = 0;
|
|
|
|
while(BOOST_UNORDERED_BORLAND_BOOL(ptr) &&
|
|
|
|
node::get_hash(ptr) % this->bucket_count_ == index)
|
|
|
|
{
|
|
|
|
++count;
|
|
|
|
ptr = ptr->next_;
|
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
2009-09-04 07:03:04 +00:00
|
|
|
}
|
|
|
|
|
2011-04-16 18:47:33 +00:00
|
|
|
node_ptr bucket_begin(std::size_t bucket_index) const
|
|
|
|
{
|
|
|
|
if (!this->buckets_) return node_ptr();
|
|
|
|
bucket& b = this->buckets_[bucket_index];
|
|
|
|
if (!b.next_) return node_ptr();
|
|
|
|
return b.next_->next_;
|
|
|
|
}
|
2009-09-04 07:03:04 +00:00
|
|
|
|
2011-04-16 18:47:33 +00:00
|
|
|
// For the remaining functions, buckets_ must not be null.
|
|
|
|
|
|
|
|
bucket_ptr get_bucket(std::size_t bucket_index) const
|
|
|
|
{
|
|
|
|
return buckets_ + static_cast<std::ptrdiff_t>(bucket_index);
|
|
|
|
}
|
2009-09-04 07:03:04 +00:00
|
|
|
|
2011-04-16 18:47:33 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// Delete
|
|
|
|
|
|
|
|
void delete_node(node_ptr n)
|
|
|
|
{
|
|
|
|
node* raw_ptr = static_cast<node*>(&*n);
|
|
|
|
real_node_ptr real_ptr(node_alloc().address(*raw_ptr));
|
|
|
|
|
|
|
|
::boost::unordered::detail::destroy(raw_ptr->value_ptr());
|
2011-08-11 21:17:57 +00:00
|
|
|
allocator_traits<node_allocator>::destroy(node_alloc(), real_ptr);
|
|
|
|
allocator_traits<node_allocator>::deallocate(node_alloc(), real_ptr, 1);
|
2011-04-16 18:47:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void delete_buckets()
|
|
|
|
{
|
|
|
|
bucket_ptr end = this->get_bucket(this->bucket_count_);
|
|
|
|
|
|
|
|
node_ptr n = (end)->next_;
|
|
|
|
while(BOOST_UNORDERED_BORLAND_BOOL(n))
|
|
|
|
{
|
|
|
|
node_ptr node_to_delete = n;
|
|
|
|
n = n->next_;
|
|
|
|
delete_node(node_to_delete);
|
|
|
|
}
|
|
|
|
|
|
|
|
++end;
|
|
|
|
for(bucket_ptr begin = this->buckets_; begin != end; ++begin) {
|
2011-08-11 21:17:57 +00:00
|
|
|
allocator_traits<bucket_allocator>::destroy(bucket_alloc(), begin);
|
2011-04-16 18:47:33 +00:00
|
|
|
}
|
|
|
|
|
2011-08-11 21:17:57 +00:00
|
|
|
allocator_traits<bucket_allocator>::deallocate(bucket_alloc(), this->buckets_, this->bucket_count_ + 1);
|
2011-04-16 18:47:33 +00:00
|
|
|
|
|
|
|
this->buckets_ = bucket_ptr();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::size_t delete_nodes(node_ptr begin, node_ptr end)
|
|
|
|
{
|
|
|
|
std::size_t count = 0;
|
|
|
|
while(begin != end) {
|
|
|
|
node_ptr n = begin;
|
|
|
|
begin = begin->next_;
|
|
|
|
delete_node(n);
|
|
|
|
++count;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is called after erasing a node or group of nodes to fix up
|
|
|
|
// the bucket pointers.
|
|
|
|
void fix_buckets(bucket_ptr bucket, node_ptr prev, node_ptr next)
|
|
|
|
{
|
|
|
|
if (!next)
|
|
|
|
{
|
|
|
|
if (bucket->next_ == prev) bucket->next_ = node_ptr();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
bucket_ptr next_bucket = this->get_bucket(
|
|
|
|
node::get_hash(next) % this->bucket_count_);
|
|
|
|
if (next_bucket != bucket)
|
|
|
|
{
|
|
|
|
next_bucket->next_ = prev;
|
|
|
|
if (bucket->next_ == prev) bucket->next_ = node_ptr();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-09-04 07:03:04 +00:00
|
|
|
|
2011-04-16 18:47:33 +00:00
|
|
|
// This is called after erasing a range of nodes to fix any bucket
|
|
|
|
// pointers into that range.
|
|
|
|
void fix_buckets_range(
|
|
|
|
std::size_t bucket_index, node_ptr prev, node_ptr begin, node_ptr end)
|
|
|
|
{
|
|
|
|
node_ptr n = begin;
|
|
|
|
|
|
|
|
// If we're not at the start of the current bucket, then
|
|
|
|
// go to the start of the next bucket.
|
|
|
|
if (this->get_bucket(bucket_index)->next_ != prev)
|
|
|
|
{
|
|
|
|
for(;;) {
|
|
|
|
n = n->next_;
|
|
|
|
if (n == end) return;
|
|
|
|
|
|
|
|
std::size_t new_bucket_index =
|
|
|
|
node::get_hash(n) % this->bucket_count_;
|
|
|
|
if (bucket_index != new_bucket_index) {
|
|
|
|
bucket_index = new_bucket_index;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Iterate through the remaining nodes, clearing out the bucket
|
|
|
|
// pointers.
|
|
|
|
this->buckets_[bucket_index].next_ = bucket_ptr();
|
|
|
|
for(;;) {
|
|
|
|
n = n->next_;
|
|
|
|
if (n == end) break;
|
|
|
|
|
|
|
|
std::size_t new_bucket_index =
|
|
|
|
node::get_hash(n) % this->bucket_count_;
|
|
|
|
if (bucket_index != new_bucket_index) {
|
|
|
|
bucket_index = new_bucket_index;
|
|
|
|
this->buckets_[bucket_index].next_ = bucket_ptr();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Finally fix the bucket containing the trailing node.
|
|
|
|
if (BOOST_UNORDERED_BORLAND_BOOL(n)) {
|
|
|
|
this->buckets_[node::get_hash(n) % this->bucket_count_].next_
|
|
|
|
= prev;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Iterate through the nodes placing them in the correct buckets.
|
|
|
|
// pre: prev->next_ is not null.
|
|
|
|
node_ptr place_in_bucket(node_ptr prev, node_ptr end) {
|
|
|
|
bucket_ptr b = this->get_bucket(node::get_hash(prev->next_) % this->bucket_count_);
|
|
|
|
|
|
|
|
if (!b->next_) {
|
|
|
|
b->next_ = prev;
|
|
|
|
return end;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
node_ptr next = end->next_;
|
|
|
|
end->next_ = b->next_->next_;
|
|
|
|
b->next_->next_ = prev->next_;
|
|
|
|
prev->next_ = next;
|
|
|
|
return prev;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void copy_buckets_to(buckets&) const;
|
2011-08-03 08:34:33 +00:00
|
|
|
void move_buckets_to(buckets&) const;
|
2011-04-16 18:47:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Assigning and swapping the equality and hash function objects
|
|
|
|
// needs strong exception safety. To implement that normally we'd
|
|
|
|
// require one of them to be known to not throw and the other to
|
|
|
|
// guarantee strong exception safety. Unfortunately they both only
|
|
|
|
// have basic exception safety. So to acheive strong exception
|
|
|
|
// safety we have storage space for two copies, and assign the new
|
|
|
|
// copies to the unused space. Then switch to using that to use
|
|
|
|
// them. This is implemented in 'set_hash_functions' which
|
|
|
|
// atomically assigns the new function objects in a strongly
|
|
|
|
// exception safe manner.
|
|
|
|
|
|
|
|
template <class H, class P> class set_hash_functions;
|
|
|
|
|
|
|
|
template <class H, class P>
|
2011-04-17 00:31:35 +00:00
|
|
|
class functions
|
2009-09-04 07:03:04 +00:00
|
|
|
{
|
2011-04-16 18:47:33 +00:00
|
|
|
friend class set_hash_functions<H, P>;
|
2011-04-17 00:31:35 +00:00
|
|
|
functions& operator=(functions const&);
|
2011-04-16 18:47:33 +00:00
|
|
|
|
|
|
|
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;
|
2009-09-04 07:03:04 +00:00
|
|
|
|
2011-04-16 18:47:33 +00:00
|
|
|
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_]));
|
2009-09-04 07:03:04 +00:00
|
|
|
}
|
|
|
|
|
2011-04-16 18:47:33 +00:00
|
|
|
void construct(bool which, H const& hf, P const& eq)
|
|
|
|
{
|
|
|
|
new((void*) &funcs_[which]) function_pair(hf, eq);
|
|
|
|
}
|
2009-09-20 21:55:15 +00:00
|
|
|
|
2011-04-16 18:47:33 +00:00
|
|
|
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]));
|
2009-09-04 07:03:04 +00:00
|
|
|
}
|
2011-04-16 18:47:33 +00:00
|
|
|
|
|
|
|
public:
|
2009-09-04 07:03:04 +00:00
|
|
|
|
2011-04-17 00:31:35 +00:00
|
|
|
functions(H const& hf, P const& eq)
|
2011-04-16 18:47:33 +00:00
|
|
|
: current_(false)
|
|
|
|
{
|
|
|
|
construct(current_, hf, eq);
|
2009-09-04 07:03:04 +00:00
|
|
|
}
|
|
|
|
|
2011-04-17 00:31:35 +00:00
|
|
|
functions(functions const& bf)
|
2011-04-16 18:47:33 +00:00
|
|
|
: current_(false)
|
|
|
|
{
|
|
|
|
construct(current_, bf.current());
|
|
|
|
}
|
2009-09-04 07:03:04 +00:00
|
|
|
|
2011-04-17 00:31:35 +00:00
|
|
|
~functions() {
|
2011-04-16 18:47:33 +00:00
|
|
|
destroy(current_);
|
|
|
|
}
|
|
|
|
|
|
|
|
H const& hash_function() const {
|
|
|
|
return current().first();
|
|
|
|
}
|
2009-09-04 07:03:04 +00:00
|
|
|
|
2011-04-16 18:47:33 +00:00
|
|
|
P const& key_eq() const {
|
|
|
|
return current().second();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class H, class P>
|
|
|
|
class set_hash_functions
|
2009-09-20 21:55:15 +00:00
|
|
|
{
|
2011-04-16 18:47:33 +00:00
|
|
|
set_hash_functions(set_hash_functions const&);
|
|
|
|
set_hash_functions& operator=(set_hash_functions const&);
|
|
|
|
|
2011-04-17 00:31:35 +00:00
|
|
|
functions<H,P>& functions_;
|
2011-04-16 18:47:33 +00:00
|
|
|
bool tmp_functions_;
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
2011-04-17 00:31:35 +00:00
|
|
|
set_hash_functions(functions<H,P>& f, H const& h, P const& p)
|
|
|
|
: functions_(f),
|
2011-04-16 18:47:33 +00:00
|
|
|
tmp_functions_(!f.current_)
|
|
|
|
{
|
|
|
|
f.construct(tmp_functions_, h, p);
|
2009-09-20 21:55:15 +00:00
|
|
|
}
|
2011-04-16 18:47:33 +00:00
|
|
|
|
2011-04-17 00:31:35 +00:00
|
|
|
set_hash_functions(functions<H,P>& f, functions<H,P> const& other)
|
|
|
|
: functions_(f),
|
2011-04-16 18:47:33 +00:00
|
|
|
tmp_functions_(!f.current_)
|
|
|
|
{
|
|
|
|
f.construct(tmp_functions_, other.current());
|
|
|
|
}
|
|
|
|
|
|
|
|
~set_hash_functions()
|
|
|
|
{
|
2011-04-17 00:31:35 +00:00
|
|
|
functions_.destroy(tmp_functions_);
|
2011-04-16 18:47:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void commit()
|
|
|
|
{
|
2011-04-17 00:31:35 +00:00
|
|
|
functions_.current_ = tmp_functions_;
|
2011-04-16 18:47:33 +00:00
|
|
|
tmp_functions_ = !tmp_functions_;
|
|
|
|
}
|
|
|
|
};
|
2009-09-20 21:55:15 +00:00
|
|
|
|
2009-09-04 07:03:04 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////
|
2011-04-16 18:47:33 +00:00
|
|
|
// Node Constructors
|
|
|
|
|
2011-08-07 08:55:28 +00:00
|
|
|
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
|
2011-04-16 18:47:33 +00:00
|
|
|
|
|
|
|
template <class T, class... Args>
|
|
|
|
inline void construct_impl(T*, void* address, Args&&... args)
|
2009-09-20 21:55:15 +00:00
|
|
|
{
|
2011-04-16 18:47:33 +00:00
|
|
|
new(address) T(std::forward<Args>(args)...);
|
2009-09-20 21:55:15 +00:00
|
|
|
}
|
|
|
|
|
2011-04-16 18:47:33 +00:00
|
|
|
#else
|
|
|
|
|
|
|
|
#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \
|
|
|
|
template < \
|
|
|
|
class T, \
|
|
|
|
BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \
|
|
|
|
> \
|
|
|
|
inline void construct_impl( \
|
|
|
|
T*, void* address, \
|
|
|
|
BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \
|
|
|
|
) \
|
|
|
|
{ \
|
|
|
|
new(address) T( \
|
|
|
|
BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
template <class First, class Second, class Key, \
|
|
|
|
BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \
|
|
|
|
> \
|
|
|
|
inline void construct_impl( \
|
|
|
|
std::pair<First, Second>*, void* address, \
|
|
|
|
Key const& k, BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
|
|
|
|
{ \
|
|
|
|
new(address) std::pair<First, Second>(k, \
|
|
|
|
Second(BOOST_UNORDERED_CALL_PARAMS(z, num_params))); \
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
|
|
|
|
BOOST_UNORDERED_CONSTRUCT_IMPL, _)
|
|
|
|
|
|
|
|
#undef BOOST_UNORDERED_CONSTRUCT_IMPL
|
|
|
|
#endif
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Node construction
|
|
|
|
|
|
|
|
template <class Alloc, bool Unique>
|
|
|
|
class node_constructor
|
|
|
|
{
|
|
|
|
typedef ::boost::unordered::detail::buckets<Alloc, Unique> buckets;
|
|
|
|
typedef BOOST_DEDUCED_TYPENAME buckets::node node;
|
|
|
|
typedef BOOST_DEDUCED_TYPENAME buckets::real_node_ptr real_node_ptr;
|
|
|
|
typedef BOOST_DEDUCED_TYPENAME buckets::value_type value_type;
|
2011-08-11 21:17:57 +00:00
|
|
|
typedef BOOST_DEDUCED_TYPENAME buckets::node_allocator node_allocator;
|
2011-04-16 18:47:33 +00:00
|
|
|
|
|
|
|
buckets& buckets_;
|
|
|
|
real_node_ptr node_;
|
|
|
|
bool node_constructed_;
|
|
|
|
bool value_constructed_;
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
node_constructor(buckets& m) :
|
|
|
|
buckets_(m),
|
|
|
|
node_(),
|
|
|
|
node_constructed_(false),
|
|
|
|
value_constructed_(false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
~node_constructor();
|
|
|
|
void construct_preamble();
|
|
|
|
|
2011-08-07 08:55:28 +00:00
|
|
|
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
|
2011-04-16 18:47:33 +00:00
|
|
|
template <class... Args>
|
|
|
|
void construct(Args&&... args)
|
|
|
|
{
|
|
|
|
construct_preamble();
|
|
|
|
construct_impl((value_type*) 0, node_->address(),
|
|
|
|
std::forward<Args>(args)...);
|
|
|
|
value_constructed_ = true;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
|
|
|
|
#define BOOST_UNORDERED_CONSTRUCT(z, num_params, _) \
|
|
|
|
template < \
|
|
|
|
BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \
|
|
|
|
> \
|
|
|
|
void construct( \
|
|
|
|
BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \
|
|
|
|
) \
|
|
|
|
{ \
|
|
|
|
construct_preamble(); \
|
|
|
|
construct_impl( \
|
|
|
|
(value_type*) 0, node_->address(), \
|
|
|
|
BOOST_UNORDERED_CALL_PARAMS(z, num_params) \
|
|
|
|
); \
|
|
|
|
value_constructed_ = true; \
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
|
|
|
|
BOOST_UNORDERED_CONSTRUCT, _)
|
|
|
|
|
|
|
|
#undef BOOST_UNORDERED_CONSTRUCT
|
|
|
|
|
|
|
|
#endif
|
|
|
|
template <class K, class M>
|
|
|
|
void construct_pair(K const& k, M*)
|
|
|
|
{
|
|
|
|
construct_preamble();
|
|
|
|
new(node_->address()) value_type(k, M());
|
|
|
|
value_constructed_ = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
value_type& value() const
|
|
|
|
{
|
|
|
|
BOOST_ASSERT(node_);
|
|
|
|
return node_->value();
|
|
|
|
}
|
|
|
|
|
|
|
|
// no throw
|
|
|
|
BOOST_DEDUCED_TYPENAME buckets::node_ptr release()
|
|
|
|
{
|
|
|
|
real_node_ptr p = node_;
|
|
|
|
node_ = real_node_ptr();
|
|
|
|
// node_ptr cast
|
|
|
|
return buckets_.bucket_alloc().address(*p);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
node_constructor(node_constructor const&);
|
|
|
|
node_constructor& operator=(node_constructor const&);
|
|
|
|
};
|
2009-09-04 07:03:04 +00:00
|
|
|
|
2011-04-16 18:47:33 +00:00
|
|
|
// node_constructor
|
|
|
|
|
|
|
|
template <class Alloc, bool Unique>
|
|
|
|
inline node_constructor<Alloc, Unique>::~node_constructor()
|
2009-09-20 21:55:15 +00:00
|
|
|
{
|
2011-04-16 18:47:33 +00:00
|
|
|
if (node_) {
|
|
|
|
if (value_constructed_) {
|
|
|
|
#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
|
|
|
|
struct dummy { node<Alloc, Grouped> x; };
|
|
|
|
#endif
|
|
|
|
::boost::unordered::detail::destroy(node_->value_ptr());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node_constructed_)
|
2011-08-11 21:17:57 +00:00
|
|
|
allocator_traits<node_allocator>::destroy(buckets_.node_alloc(), node_);
|
2011-04-16 18:47:33 +00:00
|
|
|
|
2011-08-11 21:17:57 +00:00
|
|
|
allocator_traits<node_allocator>::deallocate(buckets_.node_alloc(), node_, 1);
|
2011-04-16 18:47:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class Alloc, bool Unique>
|
|
|
|
inline void node_constructor<Alloc, Unique>::construct_preamble()
|
|
|
|
{
|
|
|
|
if(!node_) {
|
|
|
|
node_constructed_ = false;
|
|
|
|
value_constructed_ = false;
|
|
|
|
|
2011-08-11 21:17:57 +00:00
|
|
|
node_ = allocator_traits<node_allocator>::allocate(buckets_.node_alloc(), 1);
|
|
|
|
allocator_traits<node_allocator>::construct(buckets_.node_alloc(), node_, node());
|
2011-04-16 18:47:33 +00:00
|
|
|
node_->init(buckets_.bucket_alloc().address(*node_));
|
|
|
|
|
|
|
|
node_constructed_ = true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BOOST_ASSERT(node_constructed_ && value_constructed_);
|
|
|
|
::boost::unordered::detail::destroy(node_->value_ptr());
|
|
|
|
value_constructed_ = false;
|
|
|
|
}
|
2009-09-20 21:55:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
2011-04-16 18:47:33 +00:00
|
|
|
// copy_buckets_to
|
|
|
|
//
|
2011-08-03 08:34:33 +00:00
|
|
|
// basic exception safety. If an exception is thrown this will
|
2011-04-16 18:47:33 +00:00
|
|
|
// leave dst partially filled and the buckets unset.
|
2009-09-04 07:03:04 +00:00
|
|
|
|
2011-04-16 18:47:33 +00:00
|
|
|
template <class A, bool Unique>
|
|
|
|
void buckets<A, Unique>::copy_buckets_to(buckets& dst) const
|
2009-09-20 21:55:15 +00:00
|
|
|
{
|
2011-04-16 18:47:33 +00:00
|
|
|
BOOST_ASSERT(!dst.buckets_);
|
|
|
|
|
|
|
|
dst.create_buckets();
|
|
|
|
bucket_ptr dst_start = dst.get_bucket(dst.bucket_count_);
|
|
|
|
|
|
|
|
{
|
|
|
|
node_constructor<A, Unique> a(dst);
|
|
|
|
|
|
|
|
node_ptr n = this->buckets_[this->bucket_count_].next_;
|
|
|
|
node_ptr prev = dst_start;
|
|
|
|
|
|
|
|
while(n) {
|
|
|
|
std::size_t hash = node::get_hash(n);
|
|
|
|
node_ptr group_end = node::next_group(n);
|
|
|
|
|
|
|
|
a.construct(node::get_value(n));
|
|
|
|
node_ptr first_node = a.release();
|
|
|
|
node::set_hash(first_node, hash);
|
|
|
|
node_ptr end = prev->next_ = first_node;
|
|
|
|
|
|
|
|
for(n = n->next_; n != group_end; n = n->next_) {
|
|
|
|
a.construct(node::get_value(n));
|
|
|
|
end = a.release();
|
|
|
|
node::set_hash(end, hash);
|
|
|
|
node::add_after_node(end, first_node);
|
|
|
|
}
|
|
|
|
|
|
|
|
prev = dst.place_in_bucket(prev, end);
|
|
|
|
}
|
|
|
|
}
|
2009-09-04 07:03:04 +00:00
|
|
|
}
|
2011-08-03 08:34:33 +00:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
// move_buckets_to
|
|
|
|
//
|
|
|
|
// Basic exception safety. The source nodes are left in an unusable state
|
|
|
|
// if an exception throws.
|
|
|
|
|
|
|
|
template <class A, bool Unique>
|
|
|
|
void buckets<A, Unique>::move_buckets_to(buckets& dst) const
|
|
|
|
{
|
|
|
|
BOOST_ASSERT(!dst.buckets_);
|
|
|
|
|
|
|
|
dst.create_buckets();
|
|
|
|
bucket_ptr dst_start = dst.get_bucket(dst.bucket_count_);
|
|
|
|
|
|
|
|
{
|
|
|
|
node_constructor<A, Unique> a(dst);
|
|
|
|
|
|
|
|
node_ptr n = this->buckets_[this->bucket_count_].next_;
|
|
|
|
node_ptr prev = dst_start;
|
|
|
|
|
|
|
|
while(n) {
|
|
|
|
std::size_t hash = node::get_hash(n);
|
|
|
|
node_ptr group_end = node::next_group(n);
|
|
|
|
|
|
|
|
a.construct(boost::move(node::get_value(n)));
|
|
|
|
node_ptr first_node = a.release();
|
|
|
|
node::set_hash(first_node, hash);
|
|
|
|
node_ptr end = prev->next_ = first_node;
|
|
|
|
|
|
|
|
for(n = n->next_; n != group_end; n = n->next_) {
|
|
|
|
a.construct(boost::move(node::get_value(n)));
|
|
|
|
end = a.release();
|
|
|
|
node::set_hash(end, hash);
|
|
|
|
node::add_after_node(end, first_node);
|
|
|
|
}
|
|
|
|
|
|
|
|
prev = dst.place_in_bucket(prev, end);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-04-16 18:47:33 +00:00
|
|
|
}}}
|
2009-09-04 07:03:04 +00:00
|
|
|
|
|
|
|
#endif
|