forked from boostorg/unordered
Unordered: Merge to release.
Using Boost.Move and better C++11 support. [SVN r73987]
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
/*************************************************************************************************/
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user