Unordered: Merge to release.

Using Boost.Move and better C++11 support.


[SVN r73987]
This commit is contained in:
Daniel James
2011-08-21 19:19:12 +00:00
parent 3fd5635d7d
commit a4372314c2
43 changed files with 7656 additions and 4602 deletions
@@ -1,9 +1,12 @@
// Copyright 2005-2009 Daniel James.
// Copyright 2005-2011 Daniel James.
// Copyright 2009 Pablo Halpern.
//
// 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)
// A couple of templates to make using allocators easier.
//
// Written by Daniel James using some code from Pablo Halpern's
// allocator traits implementation.
#ifndef BOOST_UNORDERED_DETAIL_ALLOCATOR_UTILITIES_HPP_INCLUDED
#define BOOST_UNORDERED_DETAIL_ALLOCATOR_UTILITIES_HPP_INCLUDED
@@ -13,6 +16,8 @@
#endif
#include <boost/config.hpp>
#include <boost/detail/select_type.hpp>
#include <boost/utility/enable_if.hpp>
#if (defined(BOOST_NO_STD_ALLOCATOR) || defined(BOOST_DINKUMWARE_STDLIB)) \
&& !defined(__BORLANDC__)
@@ -23,24 +28,257 @@
# include <boost/detail/allocator_utilities.hpp>
#endif
namespace boost { namespace unordered_detail {
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS
# include <memory>
#endif
#if !defined(BOOST_NO_0X_HDR_TYPE_TRAITS)
#include <type_traits>
namespace boost { namespace unordered { namespace detail {
using std::integral_constant;
using std::true_type;
using std::false_type;
}}}
#else
namespace boost { namespace unordered { namespace detail {
template <typename T, T Value>
struct integral_constant { enum { value = Value }; };
typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;
}}}
#endif
// TODO: Use std::addressof if available?
#include <boost/utility/addressof.hpp>
namespace boost { namespace unordered { namespace detail {
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS
template <typename Alloc>
struct allocator_traits : std::allocator_traits<Alloc> {};
template <typename Alloc, typename T>
struct rebind_wrap
{
typedef typename allocator_traits<Alloc>::rebind_alloc<T> type;
};
#else
// rebind_wrap
//
// Rebind allocators. For some problematic libraries, use rebind_to
// from <boost/detail/allocator_utilities.hpp>.
#if defined(BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES)
template <class Alloc, class T>
# if defined(BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES)
template <typename Alloc, typename T>
struct rebind_wrap : ::boost::detail::allocator::rebind_to<Alloc, T> {};
#else
template <class Alloc, class T>
# else
template <typename Alloc, typename T>
struct rebind_wrap
{
typedef BOOST_DEDUCED_TYPENAME
Alloc::BOOST_NESTED_TEMPLATE rebind<T>::other
type;
};
# endif
struct convertible_from_anything
{
template<typename T> convertible_from_anything(T const&);
};
typedef char (&no_type)[1];
typedef char (&yes_type)[2];
template <typename T> struct sfinae {
typedef yes_type type;
};
// Infrastructure for providing a default type for Tp::tname if absent.
#define BOOST_DEFAULT_TYPE_TMPLT(tname) \
template <typename Tp, typename Default> \
struct default_type_ ## tname { \
template <typename T> \
static BOOST_DEDUCED_TYPENAME sfinae< \
BOOST_DEDUCED_TYPENAME T::tname>::type test(int); \
template <typename T> \
static no_type test(long); \
\
enum { value = sizeof(test<Tp>(0)) == sizeof(yes_type) }; \
\
struct DefaultWrap { typedef Default tname; }; \
\
typedef BOOST_DEDUCED_TYPENAME \
boost::detail::if_true<value>:: \
BOOST_NESTED_TEMPLATE then<Tp, DefaultWrap> \
::type::tname type; \
}
#define BOOST_DEFAULT_TYPE(T,tname, arg) \
BOOST_DEDUCED_TYPENAME default_type_ ## tname<T, arg>::type
BOOST_DEFAULT_TYPE_TMPLT(pointer);
BOOST_DEFAULT_TYPE_TMPLT(const_pointer);
BOOST_DEFAULT_TYPE_TMPLT(void_pointer);
BOOST_DEFAULT_TYPE_TMPLT(const_void_pointer);
BOOST_DEFAULT_TYPE_TMPLT(difference_type);
BOOST_DEFAULT_TYPE_TMPLT(size_type);
BOOST_DEFAULT_TYPE_TMPLT(propagate_on_container_copy_assignment);
BOOST_DEFAULT_TYPE_TMPLT(propagate_on_container_move_assignment);
BOOST_DEFAULT_TYPE_TMPLT(propagate_on_container_swap);
#if !defined(BOOST_NO_SFINAE_EXPR) || BOOST_WORKAROUND(BOOST_MSVC, >= 1500)
// Specialization is only needed for Visual C++. Without it SFINAE doesn't
// kick in.
template <unsigned int>
struct expr_sfinae;
template <>
struct expr_sfinae<sizeof(yes_type)> {
typedef yes_type type;
};
template <typename T>
struct has_select_on_container_copy_construction
{
// This needs to be a template for Visual C++.
template <typename T2>
static yes_type to_yes_type(const T2&);
template <typename T2>
static typename expr_sfinae<sizeof(to_yes_type(
((T2 const*)0)->select_on_container_copy_construction()
))>::type check(T2*);
static no_type check(void*);
enum { value = sizeof(check((T*) 0)) == sizeof(yes_type) };
};
#else
template <typename T>
struct has_select_on_container_copy_construction
{
typedef T (T::*SelectFunc)() const;
template <SelectFunc e> struct sfinae { typedef yes_type type; };
template <class U>
static typename sfinae<&U::select_on_container_copy_construction>::type
test(int);
template <class U>
static no_type test(...);
enum { value = sizeof(test<T>(1)) == sizeof(yes_type) };
};
#endif
template <typename Alloc>
inline BOOST_DEDUCED_TYPENAME boost::enable_if<
has_select_on_container_copy_construction<Alloc>, Alloc
>::type call_select_on_container_copy_construction(const Alloc& rhs)
{
return rhs.select_on_container_copy_construction();
}
template <typename Alloc>
inline BOOST_DEDUCED_TYPENAME boost::disable_if<
has_select_on_container_copy_construction<Alloc>, Alloc
>::type call_select_on_container_copy_construction(const Alloc& rhs)
{
return rhs;
}
template <typename Alloc>
struct allocator_traits
{
typedef Alloc allocator_type;
typedef typename Alloc::value_type value_type;
typedef BOOST_DEFAULT_TYPE(Alloc, pointer, value_type*)
pointer;
// For now always use the allocator's const_pointer.
//typedef BOOST_DEFAULT_TYPE(Alloc, const_pointer,
// BOOST_DEDUCED_TYPENAME pointer_traits<pointer>::
// BOOST_NESTED_TEMPLATE rebind<const value_type>::other)
// const_pointer;
typedef BOOST_DEFAULT_TYPE(Alloc, const_pointer, value_type const*)
const_pointer;
// I'm not using void pointers for now.
//typedef BOOST_DEFAULT_TYPE(Alloc, void_pointer,
// BOOST_NESTED_TEMPLATE pointer_traits<pointer>::
// BOOST_NESTED_TEMPLATE rebind<void>::other)
// void_pointer;
//typedef BOOST_DEFAULT_TYPE(Alloc, const_void_pointer,
// BOOST_DEDUCED_TYPENAME pointer_traits<pointer>::
// BOOST_NESTED_TEMPLATE rebind<const void>::other)
// const_void_pointer;
typedef BOOST_DEFAULT_TYPE(Alloc, difference_type, std::ptrdiff_t)
difference_type;
typedef BOOST_DEFAULT_TYPE(Alloc, size_type, std::size_t)
size_type;
// TODO: rebind_alloc and rebind_traits
static pointer allocate(Alloc& a, size_type n)
{ return a.allocate(n); }
// I never use this, so I'll just comment it out for now.
//
//static pointer allocate(Alloc& a, size_type n, const_void_pointer hint)
// { return DEFAULT_FUNC(allocate, pointer)(a, n, hint); }
static void deallocate(Alloc& a, pointer p, size_type n)
{ a.deallocate(p, n); }
// Only support the basic copy constructor
// template <typename T, typename... Args>
// static void construct(Alloc& a, T* p, Args&&... args) {
// DEFAULT_FUNC(construct,void)(a, p, std::forward<Args>(args)...);
// }
template <typename T>
static void construct(Alloc& a, T* p, T const& x) {
a.construct(p, x);
}
template <typename T>
static void destroy(Alloc& a, T* p) {
// DEFAULT_FUNC(destroy,void)(a, p);
a.destroy(p);
}
static size_type max_size(const Alloc& a)
{ return a.max_size(); }
// Allocator propagation on construction
static Alloc select_on_container_copy_construction(Alloc const& rhs)
{
return boost::unordered::detail::
call_select_on_container_copy_construction(rhs);
}
// Allocator propagation on assignment and swap.
// Return true if lhs is modified.
typedef BOOST_DEFAULT_TYPE(
Alloc, propagate_on_container_copy_assignment, false_type)
propagate_on_container_copy_assignment;
typedef BOOST_DEFAULT_TYPE(
Alloc,propagate_on_container_move_assignment, false_type)
propagate_on_container_move_assignment;
typedef BOOST_DEFAULT_TYPE(
Alloc,propagate_on_container_swap,false_type)
propagate_on_container_swap;
};
#endif
// allocator_array_constructor
@@ -49,10 +287,11 @@ namespace boost { namespace unordered_detail {
// clean up if an exception is thrown before the container takes charge
// of it.
template <class Allocator>
template <typename Allocator>
struct allocator_array_constructor
{
typedef BOOST_DEDUCED_TYPENAME Allocator::pointer pointer;
typedef BOOST_DEDUCED_TYPENAME allocator_traits<Allocator>::pointer
pointer;
Allocator& alloc_;
pointer ptr_;
@@ -69,21 +308,23 @@ namespace boost { namespace unordered_detail {
~allocator_array_constructor() {
if (ptr_) {
for(pointer p = ptr_; p != constructed_; ++p)
alloc_.destroy(p);
allocator_traits<Allocator>::destroy(alloc_,
boost::addressof(*p));
alloc_.deallocate(ptr_, length_);
allocator_traits<Allocator>::deallocate(alloc_, ptr_, length_);
}
}
template <class V>
template <typename V>
void construct(V const& v, std::size_t l)
{
BOOST_ASSERT(!ptr_);
length_ = l;
ptr_ = alloc_.allocate(length_);
ptr_ = allocator_traits<Allocator>::allocate(alloc_, length_);
pointer end = ptr_ + static_cast<std::ptrdiff_t>(length_);
for(constructed_ = ptr_; constructed_ != end; ++constructed_)
alloc_.construct(constructed_, v);
allocator_traits<Allocator>::construct(alloc_,
boost::addressof(*constructed_), v);
}
pointer get() const
@@ -102,7 +343,7 @@ namespace boost { namespace unordered_detail {
allocator_array_constructor& operator=(
allocator_array_constructor const&);
};
}}
}}}
#if defined(BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES)
# undef BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES
+776 -151
View File
@@ -1,183 +1,808 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2009 Daniel James
// Copyright (C) 2005-2011 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_MANAGER_HPP_INCLUDED
#define BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED
#include <boost/config.hpp>
#include <boost/assert.hpp>
#include <boost/unordered/detail/node.hpp>
#include <boost/unordered/detail/util.hpp>
namespace boost { namespace unordered_detail {
namespace boost { namespace unordered { namespace detail {
////////////////////////////////////////////////////////////////////////////
// Buckets
//
// Now the main data structure:
//
// buckets<A, Unique> functions<H, P>
// | |
// +---------------+--------------+
// |
// table<T>
//
// T is a class which contains typedefs for all the types we need.
template <class A, class G>
inline std::size_t hash_buckets<A, G>::max_bucket_count() const {
// -1 to account for the sentinel.
return prev_prime(this->bucket_alloc().max_size() - 1);
}
// 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).
template <class A, class G>
inline BOOST_DEDUCED_TYPENAME hash_buckets<A, G>::bucket_ptr
hash_buckets<A, G>::get_bucket(std::size_t num) const
template <class A, bool Unique>
class buckets
{
return buckets_ + static_cast<std::ptrdiff_t>(num);
}
buckets(buckets const&);
buckets& operator=(buckets const&);
public:
// Types
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 get_bucket(hashed % bucket_count_);
}
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;
typedef BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type value_type;
typedef BOOST_DEDUCED_TYPENAME bucket::bucket_allocator
bucket_allocator;
typedef BOOST_DEDUCED_TYPENAME allocator_traits<bucket_allocator>::pointer bucket_ptr;
typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr;
typedef BOOST_DEDUCED_TYPENAME rebind_wrap<value_allocator, node>::type
node_allocator;
typedef BOOST_DEDUCED_TYPENAME allocator_traits<node_allocator>::pointer real_node_ptr;
// Members
bucket_ptr buckets_;
std::size_t bucket_count_;
std::size_t size_;
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.
return prev_prime(allocator_traits<bucket_allocator>::max_size(bucket_alloc()) - 1);
}
////////////////////////////////////////////////////////////////////////
// Constructors and Destructors
buckets(node_allocator const& a, std::size_t bucket_count)
: buckets_(),
bucket_count_(bucket_count),
size_(),
allocators_(a,a)
{
}
buckets(buckets& b, move_tag m)
: buckets_(),
bucket_count_(b.bucket_count_),
size_(),
allocators_(b.allocators_, m)
{
swap(b);
}
template <typename T>
buckets(table<T>& x, move_tag m)
: buckets_(),
bucket_count_(x.bucket_count_),
allocators_(x.allocators_, m)
{
swap(x);
x.size_ = 0;
}
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());
template <class A, class G>
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;
// 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();
}
void swap(buckets& other, false_type = false_type())
{
BOOST_ASSERT(node_alloc() == other.node_alloc());
std::swap(buckets_, other.buckets_);
std::swap(bucket_count_, other.bucket_count_);
std::swap(size_, other.size_);
}
void swap(buckets& other, true_type)
{
allocators_.swap(other.allocators_);
std::swap(buckets_, other.buckets_);
std::swap(bucket_count_, other.bucket_count_);
std::swap(size_, other.size_);
}
void move_buckets_from(buckets& other)
{
BOOST_ASSERT(node_alloc() == other.node_alloc());
BOOST_ASSERT(!this->buckets_);
this->buckets_ = other.buckets_;
this->bucket_count_ = other.bucket_count_;
this->size_ = other.size_;
other.buckets_ = bucket_ptr();
other.bucket_count_ = 0;
other.size_ = 0;
}
std::size_t bucket_size(std::size_t index) const
{
if (!this->size_) return 0;
node_ptr ptr = this->buckets_[index].next_;
if (!ptr) return 0;
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 num) const
{
return buckets_ ? get_bucket(num)->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_ptr());
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 n = begin;
begin = begin->next_;
delete_node(n);
++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()
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;
}
node_ptr bucket_begin(std::size_t bucket_index) const
{
if (!this->size_) return node_ptr();
bucket& b = this->buckets_[bucket_index];
if (!b.next_) return node_ptr();
return b.next_->next_;
}
// 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);
}
float load_factor() const
{
BOOST_ASSERT(this->bucket_count_ != 0);
return static_cast<float>(this->size_)
/ static_cast<float>(this->bucket_count_);
}
////////////////////////////////////////////////////////////////////////
// Delete
void delete_node(node_ptr n)
{
node* raw_ptr = static_cast<node*>(boost::addressof(*n));
real_node_ptr real_ptr(node_alloc().address(*raw_ptr));
::boost::unordered::detail::destroy(raw_ptr->value_ptr());
allocator_traits<node_allocator>::destroy(node_alloc(), raw_ptr);
allocator_traits<node_allocator>::deallocate(node_alloc(), real_ptr, 1);
--this->size_;
}
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) {
allocator_traits<bucket_allocator>::destroy(bucket_alloc(),
boost::addressof(*begin));
}
allocator_traits<bucket_allocator>::deallocate(bucket_alloc(), this->buckets_, this->bucket_count_ + 1);
this->buckets_ = bucket_ptr();
BOOST_ASSERT(this->size_ == 0);
}
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;
}
void clear()
{
if(!this->size_) return;
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_;
this->delete_node(node_to_delete);
}
++end;
for(bucket_ptr begin = this->buckets_; begin != end; ++begin) {
begin->next_ = bucket_ptr();
}
this->size_ = 0;
}
node_ptr erase(node_ptr r)
{
BOOST_ASSERT(r);
node_ptr next = r->next_;
bucket_ptr bucket = this->get_bucket(
node::get_hash(r) % this->bucket_count_);
node_ptr prev = node::unlink_node(*bucket, r);
this->fix_buckets(bucket, prev, next);
this->delete_node(r);
return next;
}
node_ptr erase_range(node_ptr r1, node_ptr r2)
{
if (r1 == r2) return r2;
std::size_t bucket_index = node::get_hash(r1) % this->bucket_count_;
node_ptr prev = node::unlink_nodes(
this->buckets_[bucket_index], r1, r2);
this->fix_buckets_range(bucket_index, prev, r1, r2);
this->delete_nodes(r1, r2);
return r2;
}
// 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();
}
}
}
// 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;
void move_buckets_to(buckets&) const;
void rehash_impl(std::size_t);
};
// 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>
class functions
{
// The array constructor will clean up in the event of an
// exception.
allocator_array_constructor<bucket_allocator>
constructor(bucket_alloc());
friend class set_hash_functions<H, P>;
functions& operator=(functions const&);
// Creates an extra bucket to act as a sentinel.
constructor.construct(bucket(), this->bucket_count_ + 1);
typedef 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;
// Set up the sentinel (node_ptr cast)
bucket_ptr sentinel = constructor.get() +
static_cast<std::ptrdiff_t>(this->bucket_count_);
sentinel->next_ = sentinel;
bool current_; // The currently active functions.
aligned_function funcs_[2];
// Only release the buckets once everything is successfully
// done.
this->buckets_ = constructor.release();
}
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:
functions(H const& hf, P const& eq)
: current_(false)
{
construct(current_, hf, eq);
}
functions(functions const& bf)
: current_(false)
{
construct(current_, bf.current());
}
~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&);
functions<H,P>& functions_;
bool tmp_functions_;
public:
set_hash_functions(functions<H,P>& f, H const& h, P const& p)
: functions_(f),
tmp_functions_(!f.current_)
{
f.construct(tmp_functions_, h, p);
}
set_hash_functions(functions<H,P>& f, functions<H,P> const& other)
: functions_(f),
tmp_functions_(!f.current_)
{
f.construct(tmp_functions_, other.current());
}
~set_hash_functions()
{
functions_.destroy(tmp_functions_);
}
void commit()
{
functions_.current_ = tmp_functions_;
tmp_functions_ = !tmp_functions_;
}
};
////////////////////////////////////////////////////////////////////////////
// Constructors and Destructors
// Node Constructors
// no throw
template <class A, class G>
inline void hash_buckets<A, G>::move(hash_buckets& other)
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
template <class T, class... Args>
inline void construct_impl(T*, void* address, Args&&... args)
{
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;
new(address) T(std::forward<Args>(args)...);
}
template <class A, class G>
inline void hash_buckets<A, G>::swap(hash_buckets<A, G>& other)
{
BOOST_ASSERT(node_alloc() == other.node_alloc());
std::swap(buckets_, other.buckets_);
std::swap(bucket_count_, other.bucket_count_);
#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;
typedef BOOST_DEDUCED_TYPENAME buckets::node_allocator node_allocator;
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();
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
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&);
};
// node_constructor
template <class Alloc, bool Unique>
inline node_constructor<Alloc, Unique>::~node_constructor()
{
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_)
allocator_traits<node_allocator>::destroy(buckets_.node_alloc(),
boost::addressof(*node_));
allocator_traits<node_allocator>::deallocate(buckets_.node_alloc(), node_, 1);
}
}
template <class Alloc, bool Unique>
inline void node_constructor<Alloc, Unique>::construct_preamble()
{
if(!node_) {
node_constructed_ = false;
value_constructed_ = false;
node_ = allocator_traits<node_allocator>::allocate(buckets_.node_alloc(), 1);
allocator_traits<node_allocator>::construct(buckets_.node_alloc(),
boost::addressof(*node_), node());
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;
}
}
////////////////////////////////////////////////////////////////////////////
// copy_buckets_to
//
// basic exception safety. If an exception is thrown this will
// leave dst partially filled and the buckets unset.
template <class A, bool Unique>
void buckets<A, Unique>::copy_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(node::get_value(n));
node_ptr first_node = a.release();
node::set_hash(first_node, hash);
node_ptr end = prev->next_ = first_node;
++dst.size_;
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);
++dst.size_;
}
prev = dst.place_in_bucket(prev, end);
}
}
}
////////////////////////////////////////////////////////////////////////////
// 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;
++dst.size_;
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);
++dst.size_;
}
prev = dst.place_in_bucket(prev, end);
}
}
}
// strong otherwise exception safety
template <class A, bool Unique>
void buckets<A, Unique>::rehash_impl(std::size_t num_buckets)
{
BOOST_ASSERT(this->size_);
buckets dst(this->node_alloc(), num_buckets);
dst.create_buckets();
bucket_ptr src_start = this->get_bucket(this->bucket_count_);
bucket_ptr dst_start = dst.get_bucket(dst.bucket_count_);
dst_start->next_ = src_start->next_;
src_start->next_ = bucket_ptr();
dst.size_ = this->size_;
this->size_ = 0;
node_ptr prev = dst_start;
while (BOOST_UNORDERED_BORLAND_BOOL(prev->next_))
prev = dst.place_in_bucket(prev, node::next_group2(prev));
// Swap the new nodes back into the container and setup the
// variables.
dst.swap(*this); // no throw
}
}}}
#endif
+241 -238
View File
@@ -1,19 +1,18 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2009 Daniel James
// Copyright (C) 2005-2011 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 {
namespace boost { namespace unordered { namespace detail {
template <class T>
class hash_equivalent_table : public T::table
class equivalent_table : public T::table_base
{
public:
typedef BOOST_DEDUCED_TYPENAME T::hasher hasher;
@@ -21,54 +20,212 @@ namespace boost { namespace unordered_detail {
typedef BOOST_DEDUCED_TYPENAME T::value_allocator value_allocator;
typedef BOOST_DEDUCED_TYPENAME T::key_type key_type;
typedef BOOST_DEDUCED_TYPENAME T::value_type value_type;
typedef BOOST_DEDUCED_TYPENAME T::table table;
typedef BOOST_DEDUCED_TYPENAME T::table_base table_base;
typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor;
typedef BOOST_DEDUCED_TYPENAME T::node_allocator node_allocator;
typedef BOOST_DEDUCED_TYPENAME T::node node;
typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr;
typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr;
typedef BOOST_DEDUCED_TYPENAME T::iterator_base iterator_base;
typedef BOOST_DEDUCED_TYPENAME T::extractor extractor;
// Constructors
hash_equivalent_table(std::size_t n,
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,
: table_base(n, hf, eq, a) {}
equivalent_table(equivalent_table const& x)
: table_base(x,
allocator_traits<node_allocator>::
select_on_container_copy_construction(x.node_alloc())) {}
equivalent_table(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,
: table_base(x, a) {}
equivalent_table(equivalent_table& x, move_tag m)
: table_base(x, m) {}
equivalent_table(equivalent_table& x,
value_allocator const& a, move_tag m)
: table(x, a, m) {}
~hash_equivalent_table() {}
: table_base(x, a, m) {}
~equivalent_table() {}
// Equality
bool equals(equivalent_table const& other) const
{
if(this->size_ != other.size_) return false;
if(!this->size_) return true;
for(node_ptr n1 = this->buckets_[this->bucket_count_].next_; n1;)
{
node_ptr n2 = other.find_matching_node(n1);
if (!n2) return false;
node_ptr end1 = node::next_group(n1);
node_ptr end2 = node::next_group(n2);
if (!group_equals(n1, end1, n2, end2)) return false;
n1 = end1;
}
return true;
}
static bool group_equals(node_ptr n1, node_ptr end1,
node_ptr n2, node_ptr end2)
{
for(;;)
{
if (node::get_value(n1) != node::get_value(n2))
break;
n1 = n1->next_;
n2 = n2->next_;
if (n1 == end1) return n2 == end2;
if (n2 == end2) return false;
}
for(node_ptr n1a = n1, n2a = n2;;)
{
n1a = n1a->next_;
n2a = n2a->next_;
if (n1a == end1)
{
if (n2a == end2) break;
else return false;
}
if (n2a == end2) return false;
}
node_ptr start = n1;
for(;n1 != end2; n1 = n1->next_)
{
value_type const& v = node::get_value(n1);
if (find(start, n1, v)) continue;
std::size_t matches = count_equal(n2, end2, v);
if (!matches || matches != 1 + count_equal(n1->next_, end1, v))
return false;
}
return true;
}
static bool find(node_ptr n, node_ptr end, value_type const& v)
{
for(;n != end; n = n->next_)
if (node::get_value(n) == v)
return true;
return false;
}
static std::size_t count_equal(node_ptr n, node_ptr end, value_type const& v)
{
std::size_t count = 0;
for(;n != end; n = n->next_)
if (node::get_value(n) == v) ++count;
return count;
}
////////////////////////////////////////////////////////////////////////
// A convenience method for adding nodes.
inline node_ptr add_node(
node_constructor& a,
std::size_t bucket_index,
std::size_t hash,
node_ptr pos)
{
node_ptr n = a.release();
node::set_hash(n, hash);
if(BOOST_UNORDERED_BORLAND_BOOL(pos)) {
node::add_after_node(n, pos);
if (n->next_) {
std::size_t next_bucket =
node::get_hash(n->next_) % this->bucket_count_;
if (next_bucket != bucket_index) {
this->buckets_[next_bucket].next_ = n;
}
}
}
else {
bucket_ptr b = this->get_bucket(bucket_index);
if (!b->next_)
{
bucket_ptr start_node =
this->get_bucket(this->bucket_count_);
if (BOOST_UNORDERED_BORLAND_BOOL(start_node->next_)) {
this->buckets_[
node::get_hash(start_node->next_) %
this->bucket_count_].next_ = n;
}
b->next_ = start_node;
n->next_ = start_node->next_;
start_node->next_ = n;
}
else
{
n->next_ = b->next_->next_;
b->next_->next_ = n;
}
}
++this->size_;
return n;
}
////////////////////////////////////////////////////////////////////////
// Insert methods
iterator_base emplace_impl(node_constructor& a);
void emplace_impl_no_rehash(node_constructor& a);
node_ptr emplace_impl(node_constructor& a)
{
key_type const& k = this->get_key(a.value());
std::size_t hash = this->hash_function()(k);
std::size_t bucket_index = hash % this->bucket_count_;
node_ptr position = this->find_node(bucket_index, hash, k);
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
if(this->reserve_for_insert(this->size_ + 1)) {
bucket_index = hash % this->bucket_count_;
}
return add_node(a, bucket_index, hash, position);
}
// equals
void emplace_impl_no_rehash(node_constructor& a)
{
key_type const& k = this->get_key(a.value());
std::size_t hash = this->hash_function()(k);
std::size_t bucket_index = hash % this->bucket_count_;
add_node(a, bucket_index, hash,
this->find_node(bucket_index, hash, k));
}
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)
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
template <class... Args>
iterator_base emplace(Args&&... args);
node_ptr 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);
}
#else
#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
iterator_base emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, n));
#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
node_ptr emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
{ \
node_constructor a(*this); \
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
return emplace_impl(a); \
}
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_INSERT_IMPL, _)
@@ -76,229 +233,75 @@ namespace boost { namespace unordered_detail {
#undef BOOST_UNORDERED_INSERT_IMPL
#endif
////////////////////////////////////////////////////////////////////////
// Insert range methods
// 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);
void insert_for_range(I i, I j, forward_traversal_tag)
{
if(i == j) return;
std::size_t distance = ::boost::unordered::detail::distance(i, j);
if(distance == 1) {
emplace(*i);
}
else {
// Only require basic exception safety here
this->reserve_for_insert(this->size_ + distance);
node_constructor a(*this);
for (; i != j; ++i) {
a.construct(*i);
emplace_impl_no_rehash(a);
}
}
}
template <class I>
void insert_for_range(I i, I j, boost::incrementable_traversal_tag);
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);
}
}
// If hash function throws, or inserting > 1 element, basic exception
// safety. Strong otherwise
template <class I>
void insert_range(I i, I j);
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);
}
};
template <class H, class P, class A>
struct multiset : public types<
BOOST_DEDUCED_TYPENAME A::value_type,
BOOST_DEDUCED_TYPENAME A::value_type,
BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type,
BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type,
H, P, A,
set_extractor<BOOST_DEDUCED_TYPENAME A::value_type>,
grouped>
set_extractor<BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type>,
false>
{
typedef hash_equivalent_table<multiset<H, P, A> > impl;
typedef hash_table<multiset<H, P, A> > table;
typedef equivalent_table<multiset<H, P, A> > impl;
typedef table<multiset<H, P, A> > table_base;
};
template <class K, class H, class P, class A>
struct multimap : public types<
K, BOOST_DEDUCED_TYPENAME A::value_type,
K, BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type,
H, P, A,
map_extractor<K, BOOST_DEDUCED_TYPENAME A::value_type>,
grouped>
map_extractor<K, BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type>,
false>
{
typedef hash_equivalent_table<multimap<K, H, P, A> > impl;
typedef hash_table<multimap<K, H, P, A> > table;
typedef equivalent_table<multimap<K, H, P, A> > impl;
typedef table<multimap<K, H, P, A> > table_base;
};
////////////////////////////////////////////////////////////////////////////
// Equality
template <class T>
bool hash_equivalent_table<T>
::equals(hash_equivalent_table<T> 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(this->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 T>
inline BOOST_DEDUCED_TYPENAME hash_equivalent_table<T>::node_ptr
hash_equivalent_table<T>
::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 T>
inline BOOST_DEDUCED_TYPENAME
hash_equivalent_table<T>::iterator_base
hash_equivalent_table<T>::emplace_impl(node_constructor& a)
{
key_type const& k = this->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 = this->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 T>
inline void hash_equivalent_table<T>
::emplace_impl_no_rehash(node_constructor& a)
{
key_type const& k = this->get_key(a.value());
bucket_ptr bucket = this->get_bucket(this->bucket_index(k));
add_node(a, bucket, this->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 T>
template <class... Args>
BOOST_DEDUCED_TYPENAME hash_equivalent_table<T>::iterator_base
hash_equivalent_table<T>
::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);
}
#else
#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \
template <class T> \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
BOOST_DEDUCED_TYPENAME hash_equivalent_table<T>::iterator_base \
hash_equivalent_table<T> \
::emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
{ \
node_constructor a(*this); \
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
return emplace_impl(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 T>
template <class I>
inline void hash_equivalent_table<T>
::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 T>
template <class I>
inline void hash_equivalent_table<T>
::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
template <class T>
template <class I>
void hash_equivalent_table<T>::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
+22 -9
View File
@@ -1,17 +1,16 @@
// Copyright (C) 2005-2009 Daniel James
// Copyright (C) 2005-2011 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_EXTRACT_KEY_HPP_INCLUDED
#define BOOST_UNORDERED_DETAIL_EXTRACT_KEY_HPP_INCLUDED
#include <boost/config.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/unordered/detail/fwd.hpp>
#include <boost/unordered/detail/table.hpp>
namespace boost {
namespace unordered_detail {
namespace unordered {
namespace detail {
// key extractors
//
@@ -39,12 +38,19 @@ namespace unordered_detail {
return v;
}
#if BOOST_UNORDERED_USE_RV_REF
static key_type const& extract(BOOST_RV_REF(key_type) v)
{
return v;
}
#endif
static no_key extract()
{
return no_key();
}
#if defined(BOOST_UNORDERED_STD_FORWARD)
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
template <class... Args>
static no_key extract(Args const&...)
{
@@ -75,7 +81,7 @@ namespace unordered_detail {
struct map_extractor
{
typedef ValueType value_type;
typedef BOOST_DEDUCED_TYPENAME boost::remove_const<Key>::type key_type;
typedef BOOST_DEDUCED_TYPENAME ::boost::remove_const<Key>::type key_type;
static key_type const& extract(value_type const& v)
{
@@ -87,6 +93,13 @@ namespace unordered_detail {
return v;
}
// TODO: Why does this cause errors?
//
//static key_type const& extract(BOOST_RV_REF(key_type) v)
//{
// return v;
//}
template <class Second>
static key_type const& extract(std::pair<key_type, Second> const& v)
{
@@ -100,7 +113,7 @@ namespace unordered_detail {
return v.first;
}
#if defined(BOOST_UNORDERED_STD_FORWARD)
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
template <class Arg1, class... Args>
static key_type const& extract(key_type const& k,
Arg1 const&, Args const&...)
@@ -143,6 +156,6 @@ namespace unordered_detail {
return x.second == y.second;
}
};
}}
}}}
#endif
+37 -919
View File
@@ -1,932 +1,50 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2009 Daniel James
// Copyright (C) 2008-2011 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)
// This contains the basic data structure, apart from the actual values. There's
// no construction or deconstruction here. So this only depends on the pointer
// type.
#ifndef BOOST_UNORDERED_FWD_HPP_INCLUDED
#define BOOST_UNORDERED_FWD_HPP_INCLUDED
#ifndef BOOST_UNORDERED_DETAIL_FWD_HPP_INCLUDED
#define BOOST_UNORDERED_DETAIL_FWD_HPP_INCLUDED
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
#include <boost/config.hpp>
#include <boost/iterator.hpp>
#include <boost/compressed_pair.hpp>
#include <boost/type_traits/aligned_storage.hpp>
#include <boost/type_traits/alignment_of.hpp>
#include <boost/unordered/detail/allocator_helpers.hpp>
#include <algorithm>
#include <memory>
#include <functional>
#include <boost/functional/hash_fwd.hpp>
// 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
// of preprocessor metaprogramming - they are in unique.hpp and equivalent.hpp.
namespace boost
{
namespace unordered
{
template <class K,
class T,
class H = hash<K>,
class P = std::equal_to<K>,
class A = std::allocator<std::pair<const K, T> > >
class unordered_map;
// Template parameters:
//
// H = Hash Function
// P = Predicate
// A = Value Allocator
// G = Bucket group policy, 'grouped' or 'ungrouped'
// E = Key Extractor
template <class K,
class T,
class H = hash<K>,
class P = std::equal_to<K>,
class A = std::allocator<std::pair<const K, T> > >
class unordered_multimap;
#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)
# if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)
// STLport doesn't have std::forward.
# else
# define BOOST_UNORDERED_STD_FORWARD
# endif
#endif
template <class T,
class H = hash<T>,
class P = std::equal_to<T>,
class A = std::allocator<T> >
class unordered_set;
#if !defined(BOOST_UNORDERED_EMPLACE_LIMIT)
#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, num_params) \
BOOST_PP_ENUM_PARAMS_Z(z, num_params, class Arg)
#define BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \
BOOST_PP_ENUM_BINARY_PARAMS_Z(z, num_params, Arg, const& arg)
#define BOOST_UNORDERED_CALL_PARAMS(z, num_params) \
BOOST_PP_ENUM_PARAMS_Z(z, num_params, arg)
#endif
namespace boost { namespace unordered_detail {
static const float minimum_max_load_factor = 1e-3f;
static const std::size_t default_bucket_count = 11;
struct move_tag {};
template <class T> class hash_unique_table;
template <class T> class hash_equivalent_table;
template <class Alloc, class Grouped>
class hash_node_constructor;
template <class ValueType>
struct set_extractor;
template <class Key, class ValueType>
struct map_extractor;
struct no_key;
// Explicitly call a destructor
#if defined(BOOST_MSVC)
#pragma warning(push)
#pragma warning(disable:4100) // unreferenced formal parameter
#endif
template <class T>
inline void destroy(T* x) {
x->~T();
}
#if defined(BOOST_MSVC)
#pragma warning(pop)
#endif
////////////////////////////////////////////////////////////////////////////
//
// This section implements buckets and nodes. Here's a rough
// inheritance diagram, to show how they pull together.
//
// For unordered_set/unordered_map:
//
// hash_bucket<A>
// |
// ungrouped_node_base<A> value_base<A::value_type>
// | |
// +--------------+-------------+
// |
// hash_node<A, ungrouped>
//
// For unordered_multiset/unordered_multimap:
//
// hash_bucket<A>
// |
// grouped_node_base<A> value_base<A::value_type>
// | |
// +--------------+-------------+
// |
// hash_node<A, grouped>
// hash_bucket
//
// hash_bucket is used for both the buckets and as a base class for
// nodes. By using 'bucket_ptr' for 'node_ptr', 'next_' can point
// to either a bucket or a node. This is used later to implement a
// sentinel at the end of the bucket array.
template <class A>
class hash_bucket
{
hash_bucket& operator=(hash_bucket const&);
public:
typedef hash_bucket<A> bucket;
typedef BOOST_DEDUCED_TYPENAME
boost::unordered_detail::rebind_wrap<A, bucket>::type
bucket_allocator;
typedef BOOST_DEDUCED_TYPENAME bucket_allocator::pointer bucket_ptr;
typedef bucket_ptr node_ptr;
node_ptr next_;
hash_bucket() : next_() {}
};
// In containers with equivalent keys (unordered_multimap and
// unordered_multiset) equivalent nodes are grouped together, in
// containers with unique keys (unordered_map and unordered_set)
// individual nodes are treated as groups of one. The following two
// classes implement the data structure.
// This is used for containers with unique keys. There are no groups
// so it doesn't add any extra members, and just treats individual
// nodes as groups of one.
template <class A>
struct ungrouped_node_base : hash_bucket<A> {
typedef hash_bucket<A> bucket;
typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr;
typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr;
ungrouped_node_base() : bucket() {}
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_after_node(node_ptr n, node_ptr position);
static void unlink_node(bucket& b, node_ptr n);
static void unlink_nodes(bucket& b, node_ptr begin, node_ptr end);
static void unlink_nodes(bucket& b, node_ptr end);
};
// This is used for containers with equivalent keys. It implements a
// circular list running in the opposite direction to the linked
// list through the nodes.
template <class A>
struct grouped_node_base : hash_bucket<A>
{
typedef hash_bucket<A> bucket;
typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr;
typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr;
node_ptr group_prev_;
grouped_node_base() : bucket(), group_prev_() {}
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_after_node(node_ptr n, node_ptr position);
static void unlink_node(bucket& b, node_ptr n);
static void unlink_nodes(bucket& b, node_ptr begin, node_ptr end);
static void unlink_nodes(bucket& b, node_ptr end);
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);
}
};
// These two classes implement an easy way to pass around the node
// group policy classes without the messy template parameters.
// Whenever you see the template parameter 'G' it's one of these.
struct ungrouped
{
template <class A>
struct base {
typedef ungrouped_node_base<A> type;
};
};
struct grouped
{
template <class A>
struct base {
typedef grouped_node_base<A> type;
};
};
// The space used to store values in a node.
template <class ValueType>
struct value_base
{
typedef ValueType value_type;
BOOST_DEDUCED_TYPENAME boost::aligned_storage<
sizeof(value_type),
::boost::alignment_of<value_type>::value>::type data_;
void* address() {
return this;
}
value_type& value() {
return *(ValueType*) this;
}
value_type* value_ptr() {
return (ValueType*) this;
}
private:
value_base& operator=(value_base const&);
};
// Node
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 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_ptr(node_ptr p) {
return static_cast<hash_node&>(*p).value_ptr();
}
private:
hash_node& operator=(hash_node const&);
};
////////////////////////////////////////////////////////////////////////////
//
// Iterator Base
//
// This is the iterator used internally, the external iterators are
// provided by lightweight wrappers (hash_iterator and
// hast_const_iterator) which provide the full iterator interface.
template <class A, class G>
class hash_iterator_base
{
public:
typedef A value_allocator;
typedef hash_bucket<A> bucket;
typedef hash_node<A, G> node;
typedef BOOST_DEDUCED_TYPENAME A::value_type value_type;
typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr;
typedef BOOST_DEDUCED_TYPENAME bucket::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 ? 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_; }
value_type& operator*() const {
return node::get_value(node_);
}
void increment_bucket(node_ptr n) {
while(!n) {
++bucket_;
n = bucket_->next_;
}
node_ = bucket_ == n ? node_ptr() : n;
}
void increment() {
increment_bucket(node_->next_);
}
};
////////////////////////////////////////////////////////////////////////////
//
// Now the main data structure:
//
// hash_buckets<A, G> hash_buffered_functions<H, P>
// | |
// +-------------+--------------+
// |
// hash_table<T>
//
// T is a class which contains typedefs for all the types we need.
// hash_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).
template <class A, class G>
class hash_buckets
{
hash_buckets(hash_buckets const&);
hash_buckets& operator=(hash_buckets const&);
public:
// Types
typedef A value_allocator;
typedef hash_bucket<A> bucket;
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 bucket::bucket_allocator
bucket_allocator;
typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr;
typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr;
typedef BOOST_DEDUCED_TYPENAME rebind_wrap<value_allocator, node>::type
node_allocator;
typedef BOOST_DEDUCED_TYPENAME node_allocator::pointer real_node_ptr;
// 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;
// Constructors
hash_buckets(node_allocator const& a, std::size_t n);
void create_buckets();
~hash_buckets();
// no throw
void swap(hash_buckets& other);
void move(hash_buckets& other);
// For the remaining functions, buckets_ must not be null.
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;
// Alloc/Dealloc
void delete_node(node_ptr);
//
void delete_buckets();
void clear_bucket(bucket_ptr);
std::size_t delete_nodes(node_ptr begin, node_ptr end);
std::size_t delete_to_bucket_end(node_ptr begin);
};
// 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>
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_;
}
};
// This implements almost all of the required functionality, apart
// from some things that are specific to containers with unique and
// equivalent keys which is implemented in hash_unique_table and
// hash_equivalent_table. See unique.hpp and equivalent.hpp for
// their declaration and implementation.
template <class T>
class hash_table : public T::buckets, public T::buffered_functions
{
hash_table(hash_table const&);
public:
typedef BOOST_DEDUCED_TYPENAME T::hasher hasher;
typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal;
typedef BOOST_DEDUCED_TYPENAME T::value_allocator value_allocator;
typedef BOOST_DEDUCED_TYPENAME T::key_type key_type;
typedef BOOST_DEDUCED_TYPENAME T::value_type value_type;
typedef BOOST_DEDUCED_TYPENAME T::buffered_functions base;
typedef BOOST_DEDUCED_TYPENAME T::buckets buckets;
typedef BOOST_DEDUCED_TYPENAME T::extractor extractor;
typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor;
typedef BOOST_DEDUCED_TYPENAME T::node node;
typedef BOOST_DEDUCED_TYPENAME T::bucket bucket;
typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr;
typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr;
typedef BOOST_DEDUCED_TYPENAME T::iterator_base iterator_base;
typedef BOOST_DEDUCED_TYPENAME T::node_allocator node_allocator;
typedef BOOST_DEDUCED_TYPENAME T::iterator_pair iterator_pair;
// Members
std::size_t size_;
float mlf_;
// Cached data - invalid if !this->buckets_
bucket_ptr cached_begin_bucket_;
std::size_t max_load_;
// 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;
template <class Key, class Pred>
node_ptr find_iterator(bucket_ptr bucket, Key const& k,
Pred const&) const;
node_ptr find_iterator(bucket_ptr bucket, key_type const& k) const;
node_ptr find_iterator(key_type const& k) const;
node_ptr* find_for_erase(bucket_ptr bucket, key_type const& k) const;
// Load methods
std::size_t max_size() const;
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;
std::size_t calculate_max_load();
// Constructors
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, node_allocator const& a, move_tag m);
~hash_table() {}
hash_table& operator=(hash_table const&);
// Iterators
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
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);
// Move/copy buckets
void move_buckets_to(buckets& dst);
void copy_buckets_to(buckets& dst) const;
// Misc. key methods
std::size_t count(key_type const& k) const;
iterator_base find(key_type const& k) const;
template <class Key, class Hash, class Pred>
iterator_base find(Key const& k, Hash const& h, Pred const& eq) const;
value_type& at(key_type const& k) const;
iterator_pair equal_range(key_type const& k) const;
// Erase
//
// no throw
void clear();
std::size_t erase_key(key_type const& k);
iterator_base erase_return_iterator(iterator_base r);
void erase(iterator_base r);
std::size_t erase_group(node_ptr* it, bucket_ptr bucket);
iterator_base erase_range(iterator_base r1, iterator_base r2);
// 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
//
// no throw
void recompute_begin_bucket(bucket_ptr b);
// This is called when a range has been erased
//
// no throw
void recompute_begin_bucket(bucket_ptr b1, bucket_ptr b2);
// no throw
float load_factor() const;
iterator_base emplace_empty_impl_with_node(
node_constructor&, std::size_t);
};
///////////////////////////////////////////////////////////////////
//
// Iterators
// iterator_access is used to access the internal iterator without
// making it publicly available.
class iterator_access
{
public:
template <class Iterator>
static BOOST_DEDUCED_TYPENAME Iterator::base const&
get(Iterator const& it)
{
return it.base_;
}
};
template <class A, class G> class hash_iterator;
template <class A, class G> class hash_const_iterator;
template <class A, class G> class hash_local_iterator;
template <class A, class G> class hash_const_local_iterator;
// Local Iterators
//
// all no throw
template <class A, class G>
class hash_local_iterator
: public boost::iterator <
std::forward_iterator_tag,
BOOST_DEDUCED_TYPENAME A::value_type,
std::ptrdiff_t,
BOOST_DEDUCED_TYPENAME A::pointer,
BOOST_DEDUCED_TYPENAME A::reference>
{
public:
typedef BOOST_DEDUCED_TYPENAME A::value_type value_type;
private:
typedef hash_buckets<A, G> buckets;
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>;
node_ptr ptr_;
public:
hash_local_iterator() : 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(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>
class hash_const_local_iterator
: public boost::iterator <
std::forward_iterator_tag,
BOOST_DEDUCED_TYPENAME A::value_type,
std::ptrdiff_t,
BOOST_DEDUCED_TYPENAME A::const_pointer,
BOOST_DEDUCED_TYPENAME A::const_reference >
{
public:
typedef BOOST_DEDUCED_TYPENAME A::value_type value_type;
private:
typedef hash_buckets<A, G> buckets;
typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr ptr;
typedef BOOST_DEDUCED_TYPENAME buckets::node node;
typedef hash_local_iterator<A, G> local_iterator;
friend class hash_local_iterator<A, G>;
ptr ptr_;
public:
hash_const_local_iterator() : ptr_() {}
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(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
//
// all no throw
template <class A, class G>
class hash_iterator
: public boost::iterator <
std::forward_iterator_tag,
BOOST_DEDUCED_TYPENAME A::value_type,
std::ptrdiff_t,
BOOST_DEDUCED_TYPENAME A::pointer,
BOOST_DEDUCED_TYPENAME A::reference >
{
public:
typedef BOOST_DEDUCED_TYPENAME A::value_type value_type;
private:
typedef hash_buckets<A, G> buckets;
typedef BOOST_DEDUCED_TYPENAME buckets::node node;
typedef BOOST_DEDUCED_TYPENAME buckets::iterator_base base;
typedef hash_const_iterator<A, G> const_iterator;
friend class hash_const_iterator<A, G>;
base base_;
public:
hash_iterator() : base_() {}
explicit hash_iterator(base const& x) : base_(x) {}
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>
class hash_const_iterator
: public boost::iterator <
std::forward_iterator_tag,
BOOST_DEDUCED_TYPENAME A::value_type,
std::ptrdiff_t,
BOOST_DEDUCED_TYPENAME A::const_pointer,
BOOST_DEDUCED_TYPENAME A::const_reference >
{
public:
typedef BOOST_DEDUCED_TYPENAME A::value_type value_type;
private:
typedef hash_buckets<A, G> buckets;
typedef BOOST_DEDUCED_TYPENAME buckets::node node;
typedef BOOST_DEDUCED_TYPENAME buckets::iterator_base base;
typedef hash_iterator<A, G> iterator;
friend class hash_iterator<A, G>;
friend class iterator_access;
base base_;
public:
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 *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_;
}
};
////////////////////////////////////////////////////////////////////////////
//
// types
//
// This is used to convieniently pass around a container's typedefs
// without having 7 template parameters.
template <class K, class V, class H, class P, class A, class E, class G>
struct types
{
public:
typedef K key_type;
typedef V value_type;
typedef H hasher;
typedef P key_equal;
typedef A value_allocator;
typedef E extractor;
typedef G group_type;
typedef hash_node_constructor<value_allocator, group_type>
node_constructor;
typedef hash_buckets<value_allocator, group_type> buckets;
typedef hash_buffered_functions<hasher, key_equal> buffered_functions;
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;
typedef BOOST_DEDUCED_TYPENAME buckets::node_allocator node_allocator;
typedef std::pair<iterator_base, iterator_base> iterator_pair;
};
}}
template <class T,
class H = hash<T>,
class P = std::equal_to<T>,
class A = std::allocator<T> >
class unordered_multiset;
}
}
#endif
-243
View File
@@ -1,243 +0,0 @@
/*
Copyright 2005-2007 Adobe Systems Incorporated
Use, modification and distribution are subject to 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_MOVE_HEADER
#define BOOST_UNORDERED_DETAIL_MOVE_HEADER
#include <boost/config.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/and.hpp>
#include <boost/mpl/or.hpp>
#include <boost/mpl/not.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/is_class.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/detail/workaround.hpp>
/*************************************************************************************************/
#if defined(BOOST_NO_SFINAE)
# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
#elif defined(__GNUC__) && \
(__GNUC__ < 3 || __GNUC__ == 3 && __GNUC_MINOR__ <= 3)
# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
#elif BOOST_WORKAROUND(BOOST_INTEL, < 900) || \
BOOST_WORKAROUND(__EDG_VERSION__, < 304) || \
BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0593))
# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
#endif
/*************************************************************************************************/
namespace boost {
namespace unordered_detail {
/*************************************************************************************************/
namespace move_detail {
/*************************************************************************************************/
#if !defined(BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN)
/*************************************************************************************************/
template <typename T>
struct class_has_move_assign {
class type {
typedef T& (T::*E)(T t);
typedef char (&no_type)[1];
typedef char (&yes_type)[2];
template <E e> struct sfinae { typedef yes_type type; };
template <class U>
static typename sfinae<&U::operator=>::type test(int);
template <class U>
static no_type test(...);
public:
enum {value = sizeof(test<T>(1)) == sizeof(yes_type)};
};
};
/*************************************************************************************************/
template<typename T>
struct has_move_assign : boost::mpl::and_<boost::is_class<T>, class_has_move_assign<T> > {};
/*************************************************************************************************/
class test_can_convert_anything { };
/*************************************************************************************************/
#endif // BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
/*************************************************************************************************/
/*
REVISIT (sparent@adobe.com): This is a work around for Boost 1.34.1 and VC++ 2008 where
boost::is_convertible<T, T> fails to compile.
*/
template <typename T, typename U>
struct is_convertible : boost::mpl::or_<
boost::is_same<T, U>,
boost::is_convertible<T, U>
> { };
/*************************************************************************************************/
} //namespace move_detail
/*************************************************************************************************/
/*!
\ingroup move_related
\brief move_from is used for move_ctors.
*/
template <typename T>
struct move_from
{
explicit move_from(T& x) : source(x) { }
T& source;
private:
move_from& operator=(move_from const&);
};
/*************************************************************************************************/
#if !defined(BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN)
/*************************************************************************************************/
/*!
\ingroup move_related
\brief The is_movable trait can be used to identify movable types.
*/
template <typename T>
struct is_movable : boost::mpl::and_<
boost::is_convertible<move_from<T>, T>,
move_detail::has_move_assign<T>,
boost::mpl::not_<boost::is_convertible<move_detail::test_can_convert_anything, T> >
> { };
/*************************************************************************************************/
#else // BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
// On compilers which don't have adequate SFINAE support, treat most types as unmovable,
// unless the trait is specialized.
template <typename T>
struct is_movable : boost::mpl::false_ { };
#endif
/*************************************************************************************************/
#if !defined(BOOST_NO_SFINAE)
/*************************************************************************************************/
/*!
\ingroup move_related
\brief copy_sink and move_sink are used to select between overloaded operations according to
whether type T is movable and convertible to type U.
\sa move
*/
template <typename T,
typename U = T,
typename R = void*>
struct copy_sink : boost::enable_if<
boost::mpl::and_<
boost::unordered_detail::move_detail::is_convertible<T, U>,
boost::mpl::not_<is_movable<T> >
>,
R
>
{ };
/*************************************************************************************************/
/*!
\ingroup move_related
\brief move_sink and copy_sink are used to select between overloaded operations according to
whether type T is movable and convertible to type U.
\sa move
*/
template <typename T,
typename U = T,
typename R = void*>
struct move_sink : boost::enable_if<
boost::mpl::and_<
boost::unordered_detail::move_detail::is_convertible<T, U>,
is_movable<T>
>,
R
>
{ };
/*************************************************************************************************/
/*!
\ingroup move_related
\brief This version of move is selected when T is_movable . It in turn calls the move
constructor. This call, with the help of the return value optimization, will cause x to be moved
instead of copied to its destination. See adobe/test/move/main.cpp for examples.
*/
template <typename T>
T move(T& x, typename move_sink<T>::type = 0) { return T(move_from<T>(x)); }
/*************************************************************************************************/
/*!
\ingroup move_related
\brief This version of move is selected when T is not movable . The net result will be that
x gets copied.
*/
template <typename T>
T& move(T& x, typename copy_sink<T>::type = 0) { return x; }
/*************************************************************************************************/
#else // BOOST_NO_SFINAE
// On compilers without SFINAE, define copy_sink to always use the copy function.
template <typename T,
typename U = T,
typename R = void*>
struct copy_sink
{
typedef R type;
};
// Always copy the element unless this is overloaded.
template <typename T>
T& move(T& x) {
return x;
}
#endif // BOOST_NO_SFINAE
} // namespace unordered_detail
} // namespace boost
/*************************************************************************************************/
#endif
/*************************************************************************************************/
+321 -181
View File
@@ -1,6 +1,6 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2009 Daniel James
// Copyright (C) 2005-2011 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)
@@ -11,10 +11,7 @@
#ifndef BOOST_UNORDERED_DETAIL_NODE_HPP_INCLUDED
#define BOOST_UNORDERED_DETAIL_NODE_HPP_INCLUDED
#include <boost/config.hpp>
#include <boost/assert.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/unordered/detail/fwd.hpp>
#include <boost/unordered/detail/util.hpp>
#if BOOST_WORKAROUND(__BORLANDC__, <= 0X0582)
#define BOOST_UNORDERED_BORLAND_BOOL(x) (bool)(x)
@@ -22,205 +19,348 @@
#define BOOST_UNORDERED_BORLAND_BOOL(x) x
#endif
namespace boost { namespace unordered_detail {
namespace boost { namespace unordered { namespace detail {
// Some forward declarations for buckets and tables
template <typename T> class table;
template <class A, bool Unique> class buckets;
////////////////////////////////////////////////////////////////////////////
// ungrouped node implementation
//
// This section implements buckets and nodes. Here's a rough
// inheritance diagram, to show how they pull together.
//
// For unordered_set/unordered_map:
//
// bucket<A> value_base<allocator_traits<A>::value_type>
// | |
// +--------------+-------------+
// |
// ungrouped_node<A>
//
// For unordered_multiset/unordered_multimap:
//
// bucket<A> value_base<allocator_traits<A>::value_type>
// | |
// +--------------+-------------+
// |
// grouped_node<A>
// bucket
//
// bucket is used for both the buckets and as a base class for
// nodes. By using 'bucket_ptr' for 'node_ptr', 'next_' can point
// to either a bucket or a node. This is used later to implement a
// sentinel at the end of the bucket array.
template <class A>
inline BOOST_DEDUCED_TYPENAME ungrouped_node_base<A>::node_ptr&
ungrouped_node_base<A>::next_group(node_ptr ptr)
class bucket
{
return ptr->next_;
}
template <class A>
inline std::size_t ungrouped_node_base<A>::group_count(node_ptr)
{
return 1;
}
template <class A>
inline void ungrouped_node_base<A>::add_to_bucket(node_ptr n, bucket& b)
{
n->next_ = b.next_;
b.next_ = n;
}
template <class A>
inline void ungrouped_node_base<A>::add_after_node(node_ptr n,
node_ptr position)
{
n->next_ = position->next_;
position->next_ = position;
}
bucket& operator=(bucket const&);
public:
typedef BOOST_DEDUCED_TYPENAME
::boost::unordered::detail::rebind_wrap<A, bucket>::type
bucket_allocator;
typedef BOOST_DEDUCED_TYPENAME
allocator_traits<bucket_allocator>::pointer bucket_ptr;
typedef bucket_ptr node_ptr;
template <class A>
inline void ungrouped_node_base<A>::unlink_nodes(bucket& b,
node_ptr begin, node_ptr end)
node_ptr next_;
bucket() : next_() {}
};
// The space used to store values in a node.
template <class ValueType>
struct value_base
{
node_ptr* pos = &b.next_;
while(*pos != begin) pos = &(*pos)->next_;
*pos = end;
}
typedef ValueType value_type;
BOOST_DEDUCED_TYPENAME ::boost::aligned_storage<
sizeof(value_type),
::boost::alignment_of<value_type>::value>::type data_;
template <class A>
inline void ungrouped_node_base<A>::unlink_nodes(bucket& b, node_ptr end)
{
b.next_ = end;
}
template <class A>
inline void ungrouped_node_base<A>::unlink_node(bucket& b, node_ptr n)
{
unlink_nodes(b, n, n->next_);
}
////////////////////////////////////////////////////////////////////////////
// grouped node implementation
// 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 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>
inline std::size_t grouped_node_base<A>::group_count(node_ptr ptr)
{
node_ptr start = ptr;
std::size_t size = 0;
do {
++size;
ptr = get(ptr).group_prev_;
} while(ptr != start);
return size;
}
template <class A>
inline void grouped_node_base<A>::add_to_bucket(node_ptr n, bucket& b)
{
n->next_ = b.next_;
get(n).group_prev_ = n;
b.next_ = n;
}
template <class A>
inline void grouped_node_base<A>::add_after_node(node_ptr n, node_ptr pos)
{
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
// of the second group (if split is at the beginning then don't
// split).
template <class A>
inline BOOST_DEDUCED_TYPENAME grouped_node_base<A>::node_ptr
grouped_node_base<A>::split_group(node_ptr split)
{
node_ptr first = first_in_group(split);
if(first == split) return split;
node_ptr last = get(first).group_prev_;
get(first).group_prev_ = get(split).group_prev_;
get(split).group_prev_ = last;
return first;
}
template <class A>
void grouped_node_base<A>::unlink_node(bucket& b, node_ptr n)
{
node_ptr next = n->next_;
node_ptr* pos = &next_group(n);
if(*pos != n) {
// The node is at the beginning of a group.
// Find the previous node pointer:
pos = &b.next_;
while(*pos != n) pos = &next_group(*pos);
// Remove from group
if(BOOST_UNORDERED_BORLAND_BOOL(next) &&
get(next).group_prev_ == n)
{
get(next).group_prev_ = get(n).group_prev_;
}
void* address() {
return this;
}
else if(BOOST_UNORDERED_BORLAND_BOOL(next) &&
get(next).group_prev_ == n)
value_type& value() {
return *(ValueType*) this;
}
value_type* value_ptr() {
return (ValueType*) this;
}
private:
value_base& operator=(value_base const&);
};
// In containers with equivalent keys (unordered_multimap and
// unordered_multiset) equivalent nodes are grouped together, in
// containers with unique keys (unordered_map and unordered_set)
// individual nodes are treated as groups of one. The following two
// classes implement the data structure.
// This is used for containers with unique keys. There are no groups
// so it doesn't add any extra members, and just treats individual
// nodes as groups of one.
template <class A>
struct ungrouped_node
: ::boost::unordered::detail::bucket<A>,
value_base<BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type>
{
typedef ::boost::unordered::detail::bucket<A> bucket;
typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr;
typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr;
typedef BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type value_type;
std::size_t hash_;
ungrouped_node() : bucket() {}
void init(node_ptr) {}
static node_ptr next_group(node_ptr ptr)
{
// The deleted node is not at the end of the group, so
// change the link from the next node.
get(next).group_prev_ = get(n).group_prev_;
return ptr->next_;
}
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 = get(n).group_prev_;
while(get(x).group_prev_ != n) {
x = get(x).group_prev_;
}
get(x).group_prev_ = get(n).group_prev_;
static node_ptr next_group2(node_ptr ptr)
{
return ptr->next_;
}
*pos = next;
}
static std::size_t group_count(node_ptr n)
{
return !n ? 0 : 1;
}
static void add_after_node(node_ptr n, node_ptr position)
{
n->next_ = position->next_;
position->next_ = position;
}
static node_ptr unlink_node(bucket& b, node_ptr n)
{
return unlink_nodes(b, n, n->next_);
}
static node_ptr unlink_nodes(bucket& b, node_ptr begin, node_ptr end)
{
node_ptr prev = b.next_;
while(prev->next_ != begin) prev = prev->next_;
prev->next_ = end;
return prev;
}
static std::size_t get_hash(node_ptr p)
{
return static_cast<ungrouped_node&>(*p).hash_;
}
static void set_hash(node_ptr p, std::size_t hash)
{
static_cast<ungrouped_node&>(*p).hash_ = hash;
}
static value_type& get_value(node_ptr p)
{
return static_cast<ungrouped_node&>(*p).value();
}
static value_type* get_value_ptr(node_ptr p)
{
return static_cast<ungrouped_node&>(*p).value_ptr();
}
};
// This is used for containers with equivalent keys. It implements a
// circular list running in the opposite direction to the linked
// list through the nodes.
template <class A>
void grouped_node_base<A>::unlink_nodes(bucket& b,
node_ptr begin, node_ptr end)
struct grouped_node
: ::boost::unordered::detail::bucket<A>,
value_base<BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type>
{
node_ptr* pos = &next_group(begin);
typedef ::boost::unordered::detail::bucket<A> bucket;
typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr;
typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr;
typedef BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type value_type;
if(*pos != begin) {
// The node is at the beginning of a group.
std::size_t hash_;
node_ptr group_prev_;
// Find the previous node pointer:
pos = &b.next_;
while(*pos != begin) pos = &next_group(*pos);
// Remove from group
if(BOOST_UNORDERED_BORLAND_BOOL(end)) split_group(end);
grouped_node() : bucket(), group_prev_() {}
void init(node_ptr n)
{
group_prev_ = n;
}
else {
node_ptr group1 = split_group(begin);
if(BOOST_UNORDERED_BORLAND_BOOL(end)) {
node_ptr group2 = split_group(end);
if(begin == group2) {
node_ptr end1 = get(group1).group_prev_;
node_ptr end2 = get(group2).group_prev_;
get(group1).group_prev_ = end2;
get(group2).group_prev_ = end1;
static node_ptr next_group(node_ptr ptr)
{
return get(ptr).group_prev_->next_;
}
static node_ptr next_group2(node_ptr ptr)
{
return get(ptr->next_).group_prev_;
}
static std::size_t group_count(node_ptr ptr)
{
if (!ptr) return 0;
node_ptr start = ptr;
std::size_t size = 0;
do {
++size;
ptr = get(ptr).group_prev_;
} while(ptr != start);
return size;
}
static void add_after_node(node_ptr n, node_ptr pos)
{
n->next_ = get(pos).group_prev_->next_;
get(n).group_prev_ = get(pos).group_prev_;
get(pos).group_prev_->next_ = n;
get(pos).group_prev_ = n;
}
static node_ptr unlink_node(bucket& b, node_ptr n)
{
node_ptr next = n->next_;
node_ptr prev = get(n).group_prev_;
if(prev->next_ != n) {
// The node is at the beginning of a group.
// Find the previous node pointer:
prev = b.next_;
while(prev->next_ != n) {
prev = next_group2(prev);
}
// Remove from group
if(BOOST_UNORDERED_BORLAND_BOOL(next) &&
get(next).group_prev_ == n)
{
get(next).group_prev_ = get(n).group_prev_;
}
}
else if(BOOST_UNORDERED_BORLAND_BOOL(next) &&
get(next).group_prev_ == n)
{
// The deleted node is not at the end of the group, so
// change the link from the next node.
get(next).group_prev_ = get(n).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 = get(n).group_prev_;
while(get(x).group_prev_ != n) {
x = get(x).group_prev_;
}
get(x).group_prev_ = get(n).group_prev_;
}
prev->next_ = next;
return prev;
}
*pos = end;
}
template <class A>
void grouped_node_base<A>::unlink_nodes(bucket& b, node_ptr end)
static node_ptr unlink_nodes(bucket& b, node_ptr begin, node_ptr end)
{
node_ptr prev = get(begin).group_prev_;
if(prev->next_ != begin) {
// The node is at the beginning of a group.
// Find the previous node pointer:
prev = b.next_;
while(prev->next_ != begin) prev = next_group2(prev);
if(BOOST_UNORDERED_BORLAND_BOOL(end)) split_group(end);
}
else {
node_ptr group1 = split_group(begin);
if(BOOST_UNORDERED_BORLAND_BOOL(end)) {
node_ptr group2 = split_group(end);
if(begin == group2) {
node_ptr end1 = get(group1).group_prev_;
node_ptr end2 = get(group2).group_prev_;
get(group1).group_prev_ = end2;
get(group2).group_prev_ = end1;
}
}
}
prev->next_ = end;
return prev;
}
// Break a ciruclar list into two, with split as the beginning
// of the second group (if split is at the beginning then don't
// split).
static node_ptr split_group(node_ptr split)
{
// Find first node in group.
node_ptr first = split;
while(next_group(first) == first)
first = get(first).group_prev_;
if(first == split) return split;
node_ptr last = get(first).group_prev_;
get(first).group_prev_ = get(split).group_prev_;
get(split).group_prev_ = last;
return first;
}
static std::size_t get_hash(node_ptr p) {
return static_cast<grouped_node&>(*p).hash_;
}
static void set_hash(node_ptr p, std::size_t hash) {
static_cast<grouped_node&>(*p).hash_ = hash;
}
static value_type& get_value(node_ptr p) {
return static_cast<grouped_node&>(*p).value();
}
static value_type* get_value_ptr(node_ptr p) {
return static_cast<grouped_node&>(*p).value_ptr();
}
static grouped_node& get(node_ptr ptr) {
return static_cast<grouped_node&>(*ptr);
}
};
// These two classes implement an easy way to pass around the node
// group policy classes without the messy template parameters.
// Whenever you see the template parameter 'G' it's one of these.
struct ungrouped
{
split_group(end);
b.next_ = end;
}
}}
template <class A>
struct node {
typedef ungrouped_node<A> type;
};
};
struct grouped
{
template <class A>
struct node {
typedef grouped_node<A> type;
};
};
}}}
#endif
File diff suppressed because it is too large Load Diff
+327 -423
View File
@@ -1,19 +1,18 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2010 Daniel James
// Copyright (C) 2005-2011 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 {
namespace boost { namespace unordered { namespace detail {
template <class T>
class hash_unique_table : public T::table
class unique_table : public T::table_base
{
public:
typedef BOOST_DEDUCED_TYPENAME T::hasher hasher;
@@ -21,493 +20,398 @@ namespace boost { namespace unordered_detail {
typedef BOOST_DEDUCED_TYPENAME T::value_allocator value_allocator;
typedef BOOST_DEDUCED_TYPENAME T::key_type key_type;
typedef BOOST_DEDUCED_TYPENAME T::value_type value_type;
typedef BOOST_DEDUCED_TYPENAME T::table table;
typedef BOOST_DEDUCED_TYPENAME T::table_base table_base;
typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor;
typedef BOOST_DEDUCED_TYPENAME T::node_allocator node_allocator;
typedef BOOST_DEDUCED_TYPENAME T::node node;
typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr;
typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr;
typedef BOOST_DEDUCED_TYPENAME T::iterator_base iterator_base;
typedef BOOST_DEDUCED_TYPENAME T::extractor extractor;
typedef std::pair<iterator_base, bool> emplace_return;
typedef std::pair<node_ptr, bool> emplace_return;
// Constructors
hash_unique_table(std::size_t n, hasher const& hf, key_equal const& eq,
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,
: table_base(n, hf, eq, a) {}
unique_table(unique_table const& x)
: table_base(x,
allocator_traits<node_allocator>::
select_on_container_copy_construction(x.node_alloc())) {}
unique_table(unique_table const& x, value_allocator const& a)
: table_base(x, a) {}
unique_table(unique_table& x, move_tag m)
: table_base(x, m) {}
unique_table(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);
: table_base(x, a, m) {}
~unique_table() {}
// 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>
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
#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)> \
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_PP_REPEAT_FROM_TO(1, 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 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_impl2(node_constructor&, 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>
struct set : public types<
BOOST_DEDUCED_TYPENAME A::value_type,
BOOST_DEDUCED_TYPENAME A::value_type,
H, P, A,
set_extractor<BOOST_DEDUCED_TYPENAME A::value_type>,
ungrouped>
{
typedef hash_unique_table<set<H, P, A> > impl;
typedef hash_table<set<H, P, A> > table;
};
template <class K, class H, class P, class A>
struct map : public types<
K, BOOST_DEDUCED_TYPENAME A::value_type,
H, P, A,
map_extractor<K, BOOST_DEDUCED_TYPENAME A::value_type>,
ungrouped>
{
typedef hash_unique_table<map<K, H, P, A> > impl;
typedef hash_table<map<K, H, P, A> > table;
};
////////////////////////////////////////////////////////////////////////////
// Equality
template <class T>
bool hash_unique_table<T>
::equals(hash_unique_table<T> 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)
bool equals(unique_table const& other) const
{
node_ptr it1 = i->next_;
while(BOOST_UNORDERED_BORLAND_BOOL(it1))
if(this->size_ != other.size_) return false;
if(!this->size_) return true;
for(node_ptr n1 = this->get_bucket(this->bucket_count_)->next_;
n1; n1 = n1->next_)
{
node_ptr it2 = other.find_iterator(this->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)))
node_ptr n2 = other.find_matching_node(n1);
if(!n2 || node::get_value(n1) != node::get_value(n2))
return false;
it1 = it1->next_;
}
return true;
}
return true;
}
////////////////////////////////////////////////////////////////////////
// A convenience method for adding nodes.
////////////////////////////////////////////////////////////////////////////
// A convenience method for adding nodes.
template <class T>
inline BOOST_DEDUCED_TYPENAME hash_unique_table<T>::node_ptr
hash_unique_table<T>::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 T>
BOOST_DEDUCED_TYPENAME hash_unique_table<T>::value_type&
hash_unique_table<T>::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 add_node(
node_constructor& a,
std::size_t bucket_index,
std::size_t hash)
{
bucket_ptr b = this->get_bucket(bucket_index);
node_ptr n = a.release();
node::set_hash(n, hash);
if (!b->next_)
{
bucket_ptr start_node = this->get_bucket(this->bucket_count_);
if (start_node->next_) {
this->buckets_[
node::get_hash(start_node->next_) % this->bucket_count_
].next_ = n;
}
b->next_ = start_node;
n->next_ = start_node->next_;
start_node->next_ = n;
}
else
{
n->next_ = b->next_->next_;
b->next_->next_ = n;
}
++this->size_;
return n;
}
node_ptr pos = this->find_iterator(bucket, k);
////////////////////////////////////////////////////////////////////////////
// Insert methods
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
return node::get_value(pos);
}
else {
// Side effects only in this block.
// if hash function throws, basic exception safety
// strong otherwise
value_type& operator[](key_type const& k)
{
typedef BOOST_DEDUCED_TYPENAME value_type::second_type mapped_type;
std::size_t hash = this->hash_function()(k);
std::size_t bucket_index = hash % this->bucket_count_;
node_ptr pos = this->find_node(bucket_index, hash, k);
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
return node::get_value(pos);
}
// 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);
bucket_index = hash % this->bucket_count_;
// Nothing after this point can throw.
return node::get_value(add_node(a, bucket));
return node::get_value(add_node(a, bucket_index, hash));
}
}
template <class T>
inline BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
hash_unique_table<T>::emplace_impl_with_node(node_constructor& a)
{
// No side effects in this initial code
key_type const& k = this->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 = this->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 {
emplace_return emplace_impl_with_node(node_constructor& a)
{
// No side effects in this initial code
key_type const& k = this->get_key(a.value());
std::size_t hash = this->hash_function()(k);
std::size_t bucket_index = hash % this->bucket_count_;
node_ptr pos = this->find_node(bucket_index, hash, k);
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
// Found an existing key, return it (no throw).
return emplace_return(pos, false);
}
// 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);
bucket_index = hash % this->bucket_count_;
// Nothing after this point can throw.
return emplace_return(
iterator_base(bucket, add_node(a, bucket)),
true);
return emplace_return(add_node(a, bucket_index, hash), true);
}
}
#if defined(BOOST_UNORDERED_STD_FORWARD)
emplace_return insert(value_type const& v)
{
key_type const& k = extractor::extract(v);
std::size_t hash = this->hash_function()(k);
std::size_t bucket_index = hash % this->bucket_count_;
node_ptr pos = this->find_node(bucket_index, hash, k);
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
// Found an existing key, return it (no throw).
return emplace_return(pos, false);
}
// Isn't in table, add to bucket.
// Create the node before rehashing in case it throws an
// exception (need strong safety in such a case).
node_constructor a(*this);
a.construct(v);
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
if(this->reserve_for_insert(this->size_ + 1))
bucket_index = hash % this->bucket_count_;
// Nothing after this point can throw.
return emplace_return(add_node(a, bucket_index, hash), true);
}
template <class T>
template<class... Args>
inline BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
hash_unique_table<T>::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 = this->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);
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
} else {
template<class... Args>
emplace_return emplace(Args&&... args)
{
return emplace_impl(
extractor::extract(std::forward<Args>(args)...),
std::forward<Args>(args)...);
}
template<class... Args>
emplace_return emplace_impl(key_type const& k, Args&&... args)
{
// No side effects in this initial code
std::size_t hash = this->hash_function()(k);
std::size_t bucket_index = hash % this->bucket_count_;
node_ptr pos = this->find_node(bucket_index, hash, k);
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
// Found an existing key, return it (no throw).
return emplace_return(pos, false);
}
// 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 T>
template<class... Args>
inline BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
hash_unique_table<T>::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 T>
template<class... Args>
inline BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
hash_unique_table<T>::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, num_params, _) \
template <class T> \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
inline BOOST_DEDUCED_TYPENAME \
hash_unique_table<T>::emplace_return \
hash_unique_table<T>::emplace_impl( \
key_type const& k, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
{ \
std::size_t hash_value = this->hash_function()(k); \
bucket_ptr bucket \
= this->bucket_ptr_from_hash(hash_value); \
node_ptr pos = this->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, num_params)); \
\
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 T> \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
inline BOOST_DEDUCED_TYPENAME \
hash_unique_table<T>::emplace_return \
hash_unique_table<T>:: \
emplace_impl(no_key, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
{ \
node_constructor a(*this); \
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
return emplace_impl_with_node(a); \
} \
\
template <class T> \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
inline BOOST_DEDUCED_TYPENAME \
hash_unique_table<T>::emplace_return \
hash_unique_table<T>:: \
emplace_empty_impl( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
{ \
node_constructor a(*this); \
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
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 T>
template<class... Args>
BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
hash_unique_table<T>::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)...);
}
#else
template <class T>
template <class Arg0>
BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
hash_unique_table<T>::emplace(Arg0 const& arg0)
{
return this->size_ ?
emplace_impl(extractor::extract(arg0), arg0) :
emplace_empty_impl(arg0);
}
#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \
template <class T> \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return \
hash_unique_table<T>::emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
{ \
return this->size_ ? \
emplace_impl(extractor::extract(arg0, arg1), \
BOOST_UNORDERED_CALL_PARAMS(z, num_params)) : \
emplace_empty_impl( \
BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
}
BOOST_PP_REPEAT_FROM_TO(2, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_INSERT_IMPL, _)
#undef BOOST_UNORDERED_INSERT_IMPL
#endif
bucket_index = hash % this->bucket_count_;
////////////////////////////////////////////////////////////////////////////
// Insert range methods
// Nothing after this point can throw.
return emplace_return(add_node(a, bucket_index, hash), true);
}
template <class T>
template <class InputIt>
inline void hash_unique_table<T>::insert_range_impl2(
node_constructor& a, key_type const& k, InputIt i, InputIt j)
{
// 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 = this->find_iterator(bucket, k);
template<class... Args>
emplace_return 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
if (!BOOST_UNORDERED_BORLAND_BOOL(pos)) {
// Doesn't already exist, add to bucket.
// Side effects only in this block.
template <class Arg0>
emplace_return emplace(BOOST_FWD_REF(Arg0) arg0)
{
return emplace_impl(
extractor::extract(boost::forward<Arg0>(arg0)),
boost::forward<Arg0>(arg0));
}
// Create the node before rehashing in case it throws an
// exception (need strong safety in such a case).
a.construct(*i);
#define BOOST_UNORDERED_INSERT1_IMPL(z, n, _) \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
emplace_return emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
{ \
return emplace_impl(extractor::extract(arg0, arg1), \
BOOST_UNORDERED_CALL_PARAMS(z, n)); \
}
// 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);
#define BOOST_UNORDERED_INSERT2_IMPL(z, n, _) \
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
emplace_return emplace_impl(key_type const& k, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
{ \
std::size_t hash = this->hash_function()(k); \
std::size_t bucket_index = hash % this->bucket_count_; \
node_ptr pos = this->find_node(bucket_index, hash, k); \
\
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { \
return emplace_return(pos, false); \
} else { \
node_constructor a(*this); \
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \
\
if(this->reserve_for_insert(this->size_ + 1)) \
bucket_index = hash % this->bucket_count_; \
\
return emplace_return( \
add_node(a, bucket_index, hash), \
true); \
} \
} \
\
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
emplace_return 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_PP_REPEAT_FROM_TO(2, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_INSERT1_IMPL, _)
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_INSERT2_IMPL, _)
#undef BOOST_UNORDERED_INSERT1_IMPL
#undef BOOST_UNORDERED_INSERT2_IMPL
#endif
////////////////////////////////////////////////////////////////////////
// Insert range methods
//
// if hash function throws, or inserting > 1 element, basic exception
// safety strong otherwise
template <class InputIt>
void insert_range(InputIt i, InputIt j)
{
if(i != j)
return insert_range_impl(extractor::extract(*i), i, j);
}
template <class InputIt>
void insert_range_impl(key_type const&, InputIt i, InputIt j)
{
node_constructor a(*this);
// Special case for empty buckets so that we can use
// max_load_ (which isn't valid when buckets_ is null).
if (!this->buckets_) {
insert_range_empty(a, extractor::extract(*i), i, j);
if (++i == j) return;
}
// Nothing after this point can throw.
add_node(a, bucket);
do {
// Note: can't use get_key as '*i' might not be value_type - it
// could be a pair with first_types as key_type without const or a
// different second_type.
//
// TODO: Might be worth storing the value_type instead of the key
// here. Could be more efficient if '*i' is expensive. Could be
// less efficient if copying the full value_type is expensive.
insert_range_impl2(a, extractor::extract(*i), i, j);
} while(++i != j);
}
}
template <class T>
template <class InputIt>
inline void hash_unique_table<T>::insert_range_impl(
key_type const&, InputIt i, InputIt j)
{
node_constructor a(*this);
if(!this->size_) {
template <class InputIt>
void insert_range_empty(node_constructor& a, key_type const& k,
InputIt i, InputIt j)
{
std::size_t hash = this->hash_function()(k);
a.construct(*i);
this->emplace_empty_impl_with_node(a, 1);
++i;
if(i == j) return;
this->reserve_for_insert(this->size_ + insert_size(i, j));
add_node(a, hash % this->bucket_count_, hash);
}
do {
// Note: can't use get_key as '*i' might not be value_type - it
// could be a pair with first_types as key_type without const or a
// different second_type.
//
// TODO: Might be worth storing the value_type instead of the key
// here. Could be more efficient if '*i' is expensive. Could be
// less efficient if copying the full value_type is expensive.
insert_range_impl2(a, extractor::extract(*i), i, j);
} while(++i != j);
}
template <class T>
template <class InputIt>
inline void hash_unique_table<T>::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 {
template <class InputIt>
void insert_range_impl2(node_constructor& a, key_type const& k,
InputIt i, InputIt j)
{
// No side effects in this initial code
a.construct(*i);
emplace_impl_with_node(a);
} while(++i != j);
}
std::size_t hash = this->hash_function()(k);
std::size_t bucket_index = hash % this->bucket_count_;
node_ptr pos = this->find_node(bucket_index, hash, 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_index = hash % this->bucket_count_;
}
// Nothing after this point can throw.
add_node(a, bucket_index, hash);
}
}
// if hash function throws, or inserting > 1 element, basic exception safety
// strong otherwise
template <class T>
template <class InputIt>
void hash_unique_table<T>::insert_range(InputIt i, InputIt j)
template <class InputIt>
void insert_range_impl(no_key, InputIt i, InputIt j)
{
node_constructor a(*this);
do {
// No side effects in this initial code
a.construct(*i);
emplace_impl_with_node(a);
} while(++i != j);
}
};
template <class H, class P, class A>
struct set : public types<
BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type,
BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type,
H, P, A,
set_extractor<BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type>,
true>
{
typedef ::boost::unordered::detail::unique_table<set<H, P, A> > impl;
typedef ::boost::unordered::detail::table<set<H, P, A> > table_base;
};
template <class K, class H, class P, class A>
struct map : public types<
K, BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type,
H, P, A,
map_extractor<K, BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type>,
true>
{
if(i != j)
return insert_range_impl(extractor::extract(*i), i, j);
}
}}
typedef ::boost::unordered::detail::unique_table<map<K, H, P, A> > impl;
typedef ::boost::unordered::detail::table<map<K, H, P, A> > table_base;
};
}}}
#endif
+196 -172
View File
@@ -1,22 +1,127 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2009 Daniel James
// Copyright (C) 2005-2011 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_UTIL_HPP_INCLUDED
#define BOOST_UNORDERED_DETAIL_UTIL_HPP_INCLUDED
#include <cstddef>
#include <utility>
#include <algorithm>
#include <cstddef>
#include <stdexcept>
#include <utility>
#include <boost/limits.hpp>
#include <boost/config.hpp>
#include <boost/config/no_tr1/cmath.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/detail/select_type.hpp>
#include <boost/assert.hpp>
#include <boost/iterator.hpp>
#include <boost/iterator/iterator_categories.hpp>
#include <boost/type_traits/aligned_storage.hpp>
#include <boost/type_traits/alignment_of.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/type_traits/is_empty.hpp>
#include <boost/throw_exception.hpp>
#include <boost/unordered/detail/allocator_helpers.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/unordered/detail/fwd.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/move/move.hpp>
#include <boost/swap.hpp>
namespace boost { namespace unordered_detail {
// Template parameters:
//
// H = Hash Function
// P = Predicate
// A = Value Allocator
// G = Bucket group policy, 'grouped' or 'ungrouped'
// E = Key Extractor
#if !defined(BOOST_NO_RVALUE_REFERENCES) && \
!defined(BOOST_NO_VARIADIC_TEMPLATES)
# if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)
# elif defined(__STD_RWCOMPILER_H__) || defined(_RWSTD_VER)
# elif defined(_LIBCPP_VERSION)
# define BOOST_UNORDERED_STD_FORWARD_MOVE
# elif defined(__GLIBCPP__) || defined(__GLIBCXX__)
# if defined(__GLIBCXX__) && __GLIBCXX__ >= 20090804
# define BOOST_UNORDERED_STD_FORWARD_MOVE
# endif
# elif defined(__STL_CONFIG_H)
# elif defined(__MSL_CPP__)
# elif defined(__IBMCPP__)
# elif defined(MSIPL_COMPILE_H)
# elif (defined(_YVALS) && !defined(__IBMCPP__)) || defined(_CPPLIB_VER)
// Visual C++. A version check would be a good idea.
# define BOOST_UNORDERED_STD_FORWARD_MOVE
# endif
#endif
#if !defined(BOOST_UNORDERED_EMPLACE_LIMIT)
#define BOOST_UNORDERED_EMPLACE_LIMIT 10
#endif
#if defined(__SUNPRO_CC)
#define BOOST_UNORDERED_USE_RV_REF 0
#else
#define BOOST_UNORDERED_USE_RV_REF 1
#endif
#if !defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
#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, num_params) \
BOOST_PP_ENUM_PARAMS_Z(z, num_params, class Arg)
#define BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \
BOOST_PP_ENUM_##z(num_params, BOOST_UNORDERED_FUNCTION_PARAMS2, _)
#define BOOST_UNORDERED_FUNCTION_PARAMS2(z, i, _) \
BOOST_FWD_REF(Arg##i) arg##i
#define BOOST_UNORDERED_CALL_PARAMS(z, num_params) \
BOOST_PP_ENUM_##z(num_params, BOOST_UNORDERED_CALL_PARAMS2, _)
#define BOOST_UNORDERED_CALL_PARAMS2(z, i, _) \
boost::forward<Arg##i>(arg##i)
#endif
namespace boost { namespace unordered { namespace detail {
static const float minimum_max_load_factor = 1e-3f;
static const std::size_t default_bucket_count = 11;
struct move_tag {};
struct empty_emplace {};
template <class T> class unique_table;
template <class T> class equivalent_table;
template <class Alloc, bool Unique> class node_constructor;
template <class ValueType>
struct set_extractor;
template <class Key, class ValueType>
struct map_extractor;
struct no_key;
// Explicitly call a destructor
#if defined(BOOST_MSVC)
#pragma warning(push)
#pragma warning(disable:4100) // unreferenced formal parameter
#endif
template <class T>
inline void destroy(T* x) {
x->~T();
}
#if defined(BOOST_MSVC)
#pragma warning(pop)
#endif
////////////////////////////////////////////////////////////////////////////
// convert double to std::size_t
@@ -95,12 +200,19 @@ namespace boost { namespace unordered_detail {
////////////////////////////////////////////////////////////////////////////
// pair_cast - because some libraries don't have the full pair constructors.
#if 0
template <class Dst1, class Dst2, class Src1, class Src2>
inline std::pair<Dst1, Dst2> pair_cast(std::pair<Src1, Src2> const& x)
{
return std::pair<Dst1, Dst2>(Dst1(x.first), Dst2(x.second));
}
#define BOOST_UNORDERED_PAIR_CAST(First, Last, Argument) \
::boost::unordered::detail::pair_cast<First, Last>(Argument)
#else
#define BOOST_UNORDERED_PAIR_CAST(First, Last, Argument) \
Argument
#endif
////////////////////////////////////////////////////////////////////////////
// insert_size/initial_size
@@ -116,13 +228,13 @@ namespace boost { namespace unordered_detail {
#endif
template <class I>
inline std::size_t insert_size(I i, I j, boost::forward_traversal_tag)
inline std::size_t insert_size(I i, I j, ::boost::forward_traversal_tag)
{
return std::distance(i, j);
}
template <class I>
inline std::size_t insert_size(I, I, boost::incrementable_traversal_tag)
inline std::size_t insert_size(I, I, ::boost::incrementable_traversal_tag)
{
return 1;
}
@@ -130,202 +242,114 @@ namespace boost { namespace unordered_detail {
template <class I>
inline std::size_t insert_size(I i, I j)
{
BOOST_DEDUCED_TYPENAME boost::iterator_traversal<I>::type
BOOST_DEDUCED_TYPENAME ::boost::iterator_traversal<I>::type
iterator_traversal_tag;
return insert_size(i, j, iterator_traversal_tag);
}
template <class I>
inline std::size_t initial_size(I i, I j,
std::size_t num_buckets = boost::unordered_detail::default_bucket_count)
std::size_t num_buckets = ::boost::unordered::detail::default_bucket_count)
{
return (std::max)(static_cast<std::size_t>(insert_size(i, j)) + 1,
num_buckets);
}
////////////////////////////////////////////////////////////////////////////
// Node Constructors
// compressed_pair
#if defined(BOOST_UNORDERED_STD_FORWARD)
template <class T, class... Args>
inline void construct_impl(T*, void* address, Args&&... args)
template <typename T, int Index>
struct compressed_base : private T
{
new(address) T(std::forward<Args>(args)...);
}
compressed_base(T const& x) : T(x) {}
compressed_base(T& x, move_tag) : T(boost::move(x)) {}
#if defined(BOOST_UNORDERED_CPP0X_PAIR)
template <class First, class Second, class Key, class Arg0, class... Args>
inline void construct_impl(std::pair<First, Second>*, void* address,
Key&& k, Arg0&& arg0, Args&&... args)
)
T& get() { return *this; }
T const& get() const { return *this; }
};
template <typename T, int Index>
struct uncompressed_base
{
new(address) std::pair<First, Second>(k,
Second(arg0, std::forward<Args>(args)...);
}
#endif
uncompressed_base(T const& x) : value_(x) {}
uncompressed_base(T& x, move_tag) : value_(boost::move(x)) {}
#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
// hash_node_constructor
//
// Used to construct nodes in an exception safe manner.
template <class Alloc, class Grouped>
class hash_node_constructor
T& get() { return value_; }
T const& get() const { return value_; }
private:
T value_;
};
template <typename T, int Index>
struct generate_base
: boost::detail::if_true<
boost::is_empty<T>::value
>:: BOOST_NESTED_TEMPLATE then<
compressed_base<T, Index>,
uncompressed_base<T, Index>
>
{};
template <typename T1, typename T2>
struct compressed_pair
: private generate_base<T1, 1>::type,
private generate_base<T2, 2>::type
{
typedef hash_buckets<Alloc, Grouped> 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;
typedef BOOST_DEDUCED_TYPENAME generate_base<T1, 1>::type base1;
typedef BOOST_DEDUCED_TYPENAME generate_base<T2, 2>::type base2;
buckets& buckets_;
real_node_ptr node_;
bool node_constructed_;
bool value_constructed_;
public:
hash_node_constructor(buckets& m) :
buckets_(m),
node_(),
node_constructed_(false),
value_constructed_(false)
{
typedef T1 first_type;
typedef T2 second_type;
first_type& first() {
return static_cast<base1*>(this)->get();
}
~hash_node_constructor();
void construct_preamble();
#if defined(BOOST_UNORDERED_STD_FORWARD)
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; \
first_type const& first() const {
return static_cast<base1 const*>(this)->get();
}
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;
second_type& second() {
return static_cast<base2*>(this)->get();
}
value_type& value() const
{
BOOST_ASSERT(node_);
return node_->value();
second_type const& second() const {
return static_cast<base2 const*>(this)->get();
}
// no throw
BOOST_DEDUCED_TYPENAME buckets::node_ptr release()
template <typename First, typename Second>
compressed_pair(First const& x1, Second const& x2)
: base1(x1), base2(x2) {}
compressed_pair(compressed_pair const& x)
: base1(x.first()), base2(x.second()) {}
compressed_pair(compressed_pair& x, move_tag m)
: base1(x.first(), m), base2(x.second(), m) {}
void assign(compressed_pair const& x)
{
real_node_ptr p = node_;
node_ = real_node_ptr();
// node_ptr cast
return buckets_.bucket_alloc().address(*p);
first() = x.first();
second() = x.second();
}
void move_assign(compressed_pair& x)
{
first() = boost::move(x.first());
second() = boost::move(x.second());
}
void swap(compressed_pair& x)
{
boost::swap(first(), x.first());
boost::swap(second(), x.second());
}
private:
hash_node_constructor(hash_node_constructor const&);
hash_node_constructor& operator=(hash_node_constructor const&);
// Prevent assignment just to make use of assign or
// move_assign explicit.
compressed_pair& operator=(compressed_pair const&);
};
// hash_node_constructor
template <class Alloc, class Grouped>
inline hash_node_constructor<Alloc, Grouped>::~hash_node_constructor()
{
if (node_) {
if (value_constructed_) {
#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
struct dummy { hash_node<Alloc, Grouped> x; };
#endif
boost::unordered_detail::destroy(node_->value_ptr());
}
if (node_constructed_)
buckets_.node_alloc().destroy(node_);
buckets_.node_alloc().deallocate(node_, 1);
}
}
template <class Alloc, class Grouped>
inline void hash_node_constructor<Alloc, Grouped>::construct_preamble()
{
if(!node_) {
node_constructed_ = false;
value_constructed_ = false;
node_ = buckets_.node_alloc().allocate(1);
buckets_.node_alloc().construct(node_, node());
node_constructed_ = true;
}
else {
BOOST_ASSERT(node_constructed_ && value_constructed_);
boost::unordered_detail::destroy(node_->value_ptr());
value_constructed_ = false;
}
}
}}
}}}
#endif
File diff suppressed because it is too large Load Diff
+29 -35
View File
@@ -1,5 +1,5 @@
// Copyright (C) 2008-2009 Daniel James.
// Copyright (C) 2008-2011 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)
@@ -10,44 +10,38 @@
# pragma once
#endif
#include <boost/config.hpp>
#include <memory>
#include <functional>
#include <boost/functional/hash_fwd.hpp>
#include <boost/unordered/detail/fwd.hpp>
namespace boost
{
template <class K,
class T,
class H = hash<K>,
class P = std::equal_to<K>,
class A = std::allocator<std::pair<const K, T> > >
class unordered_map;
template <class K, class T, class H, class P, class A>
inline bool operator==(unordered_map<K, T, H, P, A> const&,
unordered_map<K, T, H, P, A> const&);
template <class K, class T, class H, class P, class A>
inline bool operator!=(unordered_map<K, T, H, P, A> const&,
unordered_map<K, T, H, P, A> const&);
template <class K, class T, class H, class P, class A>
inline void swap(unordered_map<K, T, H, P, A>&,
unordered_map<K, T, H, P, A>&);
namespace unordered
{
template <class K, class T, class H, class P, class A>
inline bool operator==(unordered_map<K, T, H, P, A> const&,
unordered_map<K, T, H, P, A> const&);
template <class K, class T, class H, class P, class A>
inline bool operator!=(unordered_map<K, T, H, P, A> const&,
unordered_map<K, T, H, P, A> const&);
template <class K, class T, class H, class P, class A>
inline void swap(unordered_map<K, T, H, P, A>&,
unordered_map<K, T, H, P, A>&);
template <class K,
class T,
class H = hash<K>,
class P = std::equal_to<K>,
class A = std::allocator<std::pair<const K, T> > >
class unordered_multimap;
template <class K, class T, class H, class P, class A>
inline bool operator==(unordered_multimap<K, T, H, P, A> const&,
unordered_multimap<K, T, H, P, A> const&);
template <class K, class T, class H, class P, class A>
inline bool operator!=(unordered_multimap<K, T, H, P, A> const&,
unordered_multimap<K, T, H, P, A> const&);
template <class K, class T, class H, class P, class A>
inline void swap(unordered_multimap<K, T, H, P, A>&,
unordered_multimap<K, T, H, P, A>&);
template <class K, class T, class H, class P, class A>
inline bool operator==(unordered_multimap<K, T, H, P, A> const&,
unordered_multimap<K, T, H, P, A> const&);
template <class K, class T, class H, class P, class A>
inline bool operator!=(unordered_multimap<K, T, H, P, A> const&,
unordered_multimap<K, T, H, P, A> const&);
template <class K, class T, class H, class P, class A>
inline void swap(unordered_multimap<K, T, H, P, A>&,
unordered_multimap<K, T, H, P, A>&);
}
using ::boost::unordered::unordered_map;
using ::boost::unordered::unordered_multimap;
using ::boost::unordered::swap;
using ::boost::unordered::operator==;
using ::boost::unordered::operator!=;
}
#endif
File diff suppressed because it is too large Load Diff
+29 -33
View File
@@ -1,5 +1,5 @@
// Copyright (C) 2008-2009 Daniel James.
// Copyright (C) 2008-2011 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)
@@ -10,42 +10,38 @@
# pragma once
#endif
#include <boost/config.hpp>
#include <memory>
#include <functional>
#include <boost/functional/hash_fwd.hpp>
#include <boost/unordered/detail/fwd.hpp>
namespace boost
{
template <class T,
class H = hash<T>,
class P = std::equal_to<T>,
class A = std::allocator<T> >
class unordered_set;
template <class T, class H, class P, class A>
inline bool operator==(unordered_set<T, H, P, A> const&,
unordered_set<T, H, P, A> const&);
template <class T, class H, class P, class A>
inline bool operator!=(unordered_set<T, H, P, A> const&,
unordered_set<T, H, P, A> const&);
template <class T, class H, class P, class A>
inline void swap(unordered_set<T, H, P, A> &m1,
unordered_set<T, H, P, A> &m2);
namespace unordered
{
template <class T, class H, class P, class A>
inline bool operator==(unordered_set<T, H, P, A> const&,
unordered_set<T, H, P, A> const&);
template <class T, class H, class P, class A>
inline bool operator!=(unordered_set<T, H, P, A> const&,
unordered_set<T, H, P, A> const&);
template <class T, class H, class P, class A>
inline void swap(unordered_set<T, H, P, A> &m1,
unordered_set<T, H, P, A> &m2);
template <class T,
class H = hash<T>,
class P = std::equal_to<T>,
class A = std::allocator<T> >
class unordered_multiset;
template <class T, class H, class P, class A>
inline bool operator==(unordered_multiset<T, H, P, A> const&,
unordered_multiset<T, H, P, A> const&);
template <class T, class H, class P, class A>
inline bool operator!=(unordered_multiset<T, H, P, A> const&,
unordered_multiset<T, H, P, A> const&);
template <class T, class H, class P, class A>
inline void swap(unordered_multiset<T, H, P, A> &m1,
unordered_multiset<T, H, P, A> &m2);
template <class T, class H, class P, class A>
inline bool operator==(unordered_multiset<T, H, P, A> const&,
unordered_multiset<T, H, P, A> const&);
template <class T, class H, class P, class A>
inline bool operator!=(unordered_multiset<T, H, P, A> const&,
unordered_multiset<T, H, P, A> const&);
template <class T, class H, class P, class A>
inline void swap(unordered_multiset<T, H, P, A> &m1,
unordered_multiset<T, H, P, A> &m2);
}
using ::boost::unordered::unordered_set;
using ::boost::unordered::unordered_multiset;
using ::boost::unordered::swap;
using ::boost::unordered::operator==;
using ::boost::unordered::operator!=;
}
#endif