Initial checkin of new version of Boost.Unordered.

- More template use, less preprocessor use.
 - Removed some of the Visual C++ 6 workarounds.
 - Reduced memory use of the main object.
 - Split into smaller headers.

[SVN r55878]
This commit is contained in:
Daniel James
2009-08-30 16:42:28 +00:00
parent 4350660626
commit 386d9f28d7
19 changed files with 3622 additions and 3431 deletions

View File

@ -3,6 +3,8 @@
// 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.
#ifndef BOOST_UNORDERED_DETAIL_ALLOCATOR_UTILITIES_HPP_INCLUDED
#define BOOST_UNORDERED_DETAIL_ALLOCATOR_UTILITIES_HPP_INCLUDED
@ -21,159 +23,85 @@
# include <boost/detail/allocator_utilities.hpp>
#endif
#include <boost/mpl/aux_/config/eti.hpp>
namespace boost { namespace unordered_detail {
namespace boost {
namespace unordered_detail {
// 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>
struct rebind_wrap : ::boost::detail::allocator::rebind_to<Alloc, T> {};
template <class Alloc, class T>
struct rebind_wrap : ::boost::detail::allocator::rebind_to<Alloc, T> {};
#else
template <class Alloc, class T>
struct rebind_wrap
{
typedef BOOST_DEDUCED_TYPENAME
Alloc::BOOST_NESTED_TEMPLATE rebind<T>::other
type;
};
template <class Alloc, class T>
struct rebind_wrap
{
typedef BOOST_DEDUCED_TYPENAME
Alloc::BOOST_NESTED_TEMPLATE rebind<T>::other
type;
};
#endif
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1300)
template <class T>
inline void reset(T& x) { x = T(); }
// allocator_array_constructor
//
// Allocate and construct an array in an exception safe manner, and
// clean up if an exception is thrown before the container takes charge
// of it.
template <class Ptr>
inline Ptr null_ptr() { return Ptr(); }
#else
template <class T>
inline void reset_impl(T& x, ...) { x = T(); }
template <class T>
inline void reset_impl(T*& x, int) { x = 0; }
template <class T>
inline void reset(T& x) { reset_impl(x); }
template <class Allocator>
struct allocator_array_constructor
{
typedef BOOST_DEDUCED_TYPENAME Allocator::pointer pointer;
template <class Ptr>
inline Ptr null_ptr() { Ptr x; reset(x); return x; }
#endif
Allocator& alloc_;
pointer ptr_;
pointer constructed_;
std::size_t length_;
// Work around for Microsoft's ETI bug.
template <class Allocator> struct allocator_value_type
allocator_array_constructor(Allocator& a)
: alloc_(a), ptr_(), constructed_(), length_(0)
{
typedef BOOST_DEDUCED_TYPENAME Allocator::value_type type;
};
constructed_ = pointer();
ptr_ = pointer();
}
template <class Allocator> struct allocator_pointer
{
typedef BOOST_DEDUCED_TYPENAME Allocator::pointer type;
};
template <class Allocator> struct allocator_const_pointer
{
typedef BOOST_DEDUCED_TYPENAME Allocator::const_pointer type;
};
template <class Allocator> struct allocator_reference
{
typedef BOOST_DEDUCED_TYPENAME Allocator::reference type;
};
template <class Allocator> struct allocator_const_reference
{
typedef BOOST_DEDUCED_TYPENAME Allocator::const_reference type;
};
#if defined(BOOST_MPL_CFG_MSVC_ETI_BUG)
~allocator_array_constructor() {
if (ptr_) {
for(pointer p = ptr_; p != constructed_; ++p)
alloc_.destroy(p);
template <>
struct allocator_value_type<int>
{
typedef int type;
};
template <>
struct allocator_pointer<int>
{
typedef int type;
};
template <>
struct allocator_const_pointer<int>
{
typedef int type;
};
template <>
struct allocator_reference<int>
{
typedef int type;
};
template <>
struct allocator_const_reference<int>
{
typedef int type;
};
#endif
template <class Allocator>
struct allocator_array_constructor
{
typedef BOOST_DEDUCED_TYPENAME allocator_pointer<Allocator>::type pointer;
Allocator& alloc_;
pointer ptr_;
pointer constructed_;
std::size_t length_;
allocator_array_constructor(Allocator& a)
: alloc_(a), ptr_(), constructed_(), length_(0)
{
#if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
unordered_detail::reset(constructed_);
unordered_detail::reset(ptr_);
#endif
alloc_.deallocate(ptr_, length_);
}
}
~allocator_array_constructor() {
if (ptr_) {
for(pointer p = ptr_; p != constructed_; ++p)
alloc_.destroy(p);
template <class V>
void construct(V const& v, std::size_t l)
{
BOOST_ASSERT(!ptr_);
length_ = l;
ptr_ = alloc_.allocate(length_);
pointer end = ptr_ + static_cast<std::ptrdiff_t>(length_);
for(constructed_ = ptr_; constructed_ != end; ++constructed_)
alloc_.construct(constructed_, v);
}
alloc_.deallocate(ptr_, length_);
}
}
pointer get() const
{
return ptr_;
}
template <class V>
void construct(V const& v, std::size_t l)
{
BOOST_ASSERT(!ptr_);
length_ = l;
ptr_ = alloc_.allocate(length_);
pointer end = ptr_ + static_cast<std::ptrdiff_t>(length_);
for(constructed_ = ptr_; constructed_ != end; ++constructed_)
alloc_.construct(constructed_, v);
}
pointer get() const
{
return ptr_;
}
pointer release()
{
pointer p(ptr_);
unordered_detail::reset(ptr_);
return p;
}
private:
allocator_array_constructor(allocator_array_constructor const&);
allocator_array_constructor& operator=(allocator_array_constructor const&);
};
}
}
pointer release()
{
pointer p(ptr_);
ptr_ = pointer();
return p;
}
private:
allocator_array_constructor(allocator_array_constructor const&);
allocator_array_constructor& operator=(allocator_array_constructor const&);
};
}}
#if defined(BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES)
# undef BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES

View File

@ -1,30 +0,0 @@
// Copyright 2008-2009 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#if !defined(BOOST_UNORDERED_DETAIL_CONFIG_HEADER)
#define BOOST_UNORDERED_DETAIL_CONFIG_HEADER
#include <boost/config.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
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
# if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)
// STLport doesn't have std::forward.
# else
# define BOOST_UNORDERED_STD_FORWARD
# endif
#endif
#endif

View File

@ -0,0 +1,156 @@
// Copyright (C) 2005-2009 Daniel James
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_UNORDERED_DETAIL_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>
namespace boost {
namespace unordered_detail {
// key extractors
//
// no throw
//
// 'extract_key' is called with the emplace parameters to return a
// key if available or 'no_key' is one isn't and will need to be
// constructed. This could be done by overloading the emplace implementation
// for the different cases, but that's a bit tricky on compilers without
// variadic templates.
struct no_key {
no_key() {}
template <class T> no_key(T const&) {}
};
struct set_extractor
{
template <class ValueType>
struct apply
{
typedef ValueType value_type;
typedef ValueType key_type;
static key_type const& extract(key_type const& v)
{
return v;
}
static no_key extract()
{
return no_key();
}
#if defined(BOOST_UNORDERED_STD_FORWARD)
template <class... Args>
static no_key extract(Args const&...)
{
return no_key();
}
#else
template <class Arg>
static no_key extract(Arg const&)
{
return no_key();
}
template <class Arg>
static no_key extract(Arg const&, Arg const&)
{
return no_key();
}
#endif
};
};
struct map_extractor
{
template <class ValueType>
struct apply
{
typedef ValueType value_type;
typedef BOOST_DEDUCED_TYPENAME remove_const<BOOST_DEDUCED_TYPENAME ValueType::first_type>::type key_type;
static key_type const& extract(value_type const& v)
{
return v.first;
}
static key_type const& extract(key_type const& v)
{
return v;
}
template <class Second>
static key_type const& extract(std::pair<key_type, Second> const& v)
{
return v.first;
}
template <class Second>
static key_type const& extract(std::pair<key_type const, Second> const& v)
{
return v.first;
}
/*
template <class Second>
static key_type const& extract(std::pair<key_type&, Second> const& v)
{
return v.first;
}
template <class Second>
static key_type const& extract(std::pair<key_type const&, Second> const& v)
{
return v.first;
}
*/
#if defined(BOOST_UNORDERED_STD_FORWARD)
template <class Arg1, class... Args>
static key_type const& extract(key_type const& k, Arg1 const&, Args const&...)
{
return k;
}
template <class... Args>
static no_key extract(Args const&...)
{
return no_key();
}
#else
template <class Arg1>
static key_type const& extract(key_type const& k, Arg1 const&)
{
return k;
}
static no_key extract()
{
return no_key();
}
template <class Arg>
static no_key extract(Arg const&)
{
return no_key();
}
template <class Arg, class Arg1>
static no_key extract(Arg const&, Arg1 const&)
{
return no_key();
}
#endif
};
};
}}
#endif

View File

@ -0,0 +1,625 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2009 Daniel James
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// 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_DETAIL_FWD_HPP_INCLUDED
#define BOOST_UNORDERED_DETAIL_FWD_HPP_INCLUDED
#include <boost/config.hpp>
#include <boost/assert.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>
// 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 insert.hpp
// Template parameters:
//
// H = Hash Function
// P = Predicate
// A = Value Allocator
// G = Grouped/Ungrouped
// K = Key Extractor
#include <boost/config.hpp>
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
# if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)
// STLport doesn't have std::forward.
# else
# define BOOST_UNORDERED_STD_FORWARD
# endif
#endif
#if !defined(BOOST_UNORDERED_EMPLACE_LIMIT)
#define BOOST_UNORDERED_EMPLACE_LIMIT 10
#endif
namespace boost { namespace unordered_detail {
static const float minimum_max_load_factor = 1e-3f;
static const std::size_t default_initial_bucket_count = 11;
struct move_tag {};
// hash_bucket
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_() {}
// Only copy construct when allocating.
hash_bucket(hash_bucket const& x) : next_()
{ BOOST_ASSERT(!x.next_); }
};
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_group_to_bucket(node_ptr n, bucket& b);
static inline void add_after_node(node_ptr n, node_ptr position);
static void unlink_node(bucket& b, node_ptr node);
static void unlink_nodes(bucket& b, node_ptr begin, node_ptr end);
static void unlink_nodes(bucket& b, node_ptr end);
static inline void unlink_group(node_ptr* b);
};
template <class A>
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& group_prev(node_ptr ptr);
static inline node_ptr& next_group(node_ptr ptr);
static inline std::size_t group_count(node_ptr ptr);
static inline void add_to_bucket(node_ptr n, bucket& b);
static inline void add_group_to_bucket(node_ptr n, bucket& b);
static inline void add_after_node(node_ptr n, node_ptr position);
static void unlink_node(bucket& b, node_ptr node);
static void unlink_nodes(bucket& b, node_ptr begin, node_ptr end);
static void unlink_nodes(bucket& b, node_ptr end);
static inline void unlink_group(node_ptr* b);
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); }
};
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;
};
};
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; }
};
// Node
template <class NodeBase, class ValueType>
class hash_node : public NodeBase, public value_base<ValueType>
{
typedef ValueType value_type;
typedef BOOST_DEDUCED_TYPENAME NodeBase::node_ptr node_ptr;
public:
static value_type& get_value(node_ptr p) { return static_cast<hash_node&>(*p).value(); }
};
template <class A, class G>
struct hash_structure
{
typedef BOOST_DEDUCED_TYPENAME
G::BOOST_NESTED_TEMPLATE base<A>::type
node_base;
typedef BOOST_DEDUCED_TYPENAME node_base::bucket_allocator bucket_allocator;
typedef BOOST_DEDUCED_TYPENAME node_base::bucket_ptr bucket_ptr;
typedef BOOST_DEDUCED_TYPENAME node_base::node_ptr node_ptr;
// The actual data structure
bucket_ptr buckets_;
bucket_ptr cached_begin_bucket_;
std::size_t size_;
std::size_t bucket_count_;
// Constructor
hash_structure() : buckets_(), cached_begin_bucket_(), size_() {}
void swap(hash_structure& other);
// Buckets
std::size_t bucket_count() const;
std::size_t bucket_from_hash(std::size_t hashed) const;
bucket_ptr bucket_ptr_from_hash(std::size_t hashed) const;
bucket_ptr buckets_begin() const;
bucket_ptr buckets_end() const;
std::size_t bucket_size(std::size_t index) const;
// Link a node
void link_node(node_ptr n, node_ptr position);
void link_node_in_bucket(node_ptr n, bucket_ptr bucket);
void unlink_node(bucket_ptr bucket, node_ptr pos);
void unlink_nodes(bucket_ptr bucket, node_ptr begin, node_ptr end);
void unlink_nodes(bucket_ptr bucket, node_ptr end);
std::size_t unlink_group(node_ptr* pos);
void link_group(node_ptr n, bucket_ptr bucket, std::size_t count);
bucket_ptr get_bucket(std::size_t n) const;
node_ptr bucket_begin(std::size_t n) const;
node_ptr bucket_end(std::size_t) const;
// recompute_begin_bucket
//
// 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
template <class BucketPtr>
class hash_iterator_base
{
public:
typedef BucketPtr bucket_ptr;
typedef BucketPtr node_ptr;
bucket_ptr bucket_;
node_ptr node_;
hash_iterator_base() : bucket_(), node_() {}
explicit hash_iterator_base(bucket_ptr b) : bucket_(b), node_(b->next_) {}
hash_iterator_base(bucket_ptr b, node_ptr n) : bucket_(b), node_(n) {}
bool operator==(hash_iterator_base const& x) const { return node_ == x.node_; }
bool operator!=(hash_iterator_base const& x) const { return node_ != x.node_; }
bool is_end() const { return node_ == bucket_; }
node_ptr get() const { return node_; }
void increment(node_ptr node);
void increment();
};
// hash_table_manager
//
// This is responsible for allocating and deallocating buckets and nodes.
//
// Notes:
// 1. For the sake exception safety the allocators themselves don't allocate anything.
// 2. It's the callers responsibility to allocate the buckets before calling any of the
// methods (other than getters and setters).
template <class A, class G>
struct hash_table_manager :
hash_structure<A, G>
{
// Types
typedef hash_bucket<A> bucket;
typedef hash_structure<A, G> structure;
typedef BOOST_DEDUCED_TYPENAME structure::bucket_allocator bucket_allocator;
typedef BOOST_DEDUCED_TYPENAME structure::node_base node_base;
typedef BOOST_DEDUCED_TYPENAME structure::bucket_ptr bucket_ptr;
typedef BOOST_DEDUCED_TYPENAME structure::node_ptr node_ptr;
typedef A value_allocator;
typedef BOOST_DEDUCED_TYPENAME A::value_type value_type;
typedef hash_node<node_base, value_type> node;
typedef BOOST_DEDUCED_TYPENAME rebind_wrap<value_allocator, node>::type node_allocator;
typedef BOOST_DEDUCED_TYPENAME node_allocator::pointer real_node_ptr;
typedef hash_iterator_base<bucket_ptr> iterator_base;
// Members
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(); }
iterator_base begin() const { return iterator_base(this->cached_begin_bucket_); }
iterator_base end() const { return iterator_base(this->buckets_end()); }
std::size_t max_bucket_count() const {
// -1 to account for the sentinel.
return prev_prime(this->bucket_alloc().max_size() - 1);
}
// Constructors
//
// The copy constructor doesn't copy the buckets.
hash_table_manager();
explicit hash_table_manager(value_allocator const& a);
explicit hash_table_manager(hash_table_manager const& h);
hash_table_manager(hash_table_manager& x, move_tag m);
hash_table_manager(hash_table_manager& x, value_allocator const& a, move_tag m);
~hash_table_manager();
// no throw
void move(hash_table_manager& other);
// Methods
void create_buckets(std::size_t bucket_count);
// Alloc/Dealloc
void destruct_node(node_ptr);
//
void delete_buckets();
void clear();
void clear_bucket(bucket_ptr);
void delete_group(node_ptr first_node);
void delete_nodes(node_ptr begin, node_ptr end);
void delete_to_bucket_end(node_ptr begin);
// Erase
//
// no throw
iterator_base 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);
};
template <class H, class P, class A, class G, class K>
class hash_table :
public hash_table_manager<A, G>
{
public:
typedef H hasher;
typedef P key_equal;
typedef A value_allocator;
typedef G grouped;
typedef K key_extractor;
typedef hash_table_manager<A, G> manager;
typedef BOOST_DEDUCED_TYPENAME value_allocator::value_type value_type;
typedef BOOST_DEDUCED_TYPENAME key_extractor::BOOST_NESTED_TEMPLATE apply<value_type>
extractor;
typedef BOOST_DEDUCED_TYPENAME extractor::key_type key_type;
typedef BOOST_DEDUCED_TYPENAME manager::node node;
typedef BOOST_DEDUCED_TYPENAME manager::bucket bucket;
typedef BOOST_DEDUCED_TYPENAME manager::node_ptr node_ptr;
typedef BOOST_DEDUCED_TYPENAME manager::bucket_ptr bucket_ptr;
typedef BOOST_DEDUCED_TYPENAME manager::iterator_base iterator_base;
// Types for storing functions
typedef boost::compressed_pair<hasher, key_equal> functions;
typedef bool functions_ptr;
typedef BOOST_DEDUCED_TYPENAME boost::aligned_storage<
sizeof(functions),
::boost::alignment_of<functions>::value>::type aligned_function;
// Members
bool func_; // The currently active functions.
aligned_function funcs_[2];
float mlf_;
std::size_t max_load_;
// Buffered Functions
functions* get_functions(bool which) {
return static_cast<functions*>(static_cast<void*>(&this->funcs_[which]));
}
functions const* get_functions(bool which) const {
return static_cast<functions const*>(static_cast<void const*>(&this->funcs_[which]));
}
functions const& current() const {
return *this->get_functions(this->func_);
}
hasher const& hash_function() const {
return this->current().first();
}
key_equal const& key_eq() const {
return this->current().second();
}
functions_ptr buffer_functions(hash_table const& x) {
functions_ptr ptr = !func_;
*this->get_functions(ptr) = x.current();
return ptr;
}
void set_functions(functions_ptr ptr) {
BOOST_ASSERT(ptr != func_);
func_ = ptr;
}
// Helper methods
bool equal(key_type const& k, value_type const& v) const;
node_ptr find_iterator(bucket_ptr bucket, key_type const& k) const;
node_ptr find_iterator(key_type const& k) const;
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;
void calculate_max_load();
// Constructors
hash_table(std::size_t n, hasher const& hf, key_equal const& eq, value_allocator const& a);
hash_table(hash_table const& x);
hash_table(hash_table const& x, value_allocator const& a);
hash_table(hash_table& x, move_tag m);
hash_table(hash_table& x, value_allocator const& a, move_tag m);
~hash_table();
hash_table& operator=(hash_table const&);
// Swap & Move
void swap(hash_table& x);
void move(hash_table& x);
// Reserve and rehash
bool reserve(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(manager& dst);
void copy_buckets_to(manager& dst) const;
// Misc. key methods
std::size_t erase_key(key_type const& k);
std::size_t count(key_type const& k) const;
iterator_base find(key_type const& k) const;
value_type& at(key_type const& k) const;
std::pair<iterator_base, iterator_base> equal_range(key_type const& k) const;
};
// Iterator Access
class iterator_access
{
public:
template <class Iterator>
static BOOST_DEDUCED_TYPENAME Iterator::base const& get(Iterator const& it) {
return it.base_;
}
};
// Iterators
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_table_manager<A, G> manager;
typedef BOOST_DEDUCED_TYPENAME manager::node_ptr ptr;
typedef BOOST_DEDUCED_TYPENAME manager::node node;
typedef hash_const_local_iterator<A, G> const_local_iterator;
friend class hash_const_local_iterator<A, G>;
ptr ptr_;
public:
hash_local_iterator() : ptr_() {}
explicit hash_local_iterator(ptr x) : ptr_(x) {}
BOOST_DEDUCED_TYPENAME A::reference operator*() const
{ return node::get_value(ptr_); }
value_type* operator->() const { return &node::get_value(ptr_); }
hash_local_iterator& operator++() { ptr_ = next_node(ptr_); return *this; }
hash_local_iterator operator++(int) { hash_local_iterator tmp(ptr_); ptr_ = next_node(ptr_); return tmp; }
bool operator==(hash_local_iterator x) const { return ptr_ == x.ptr_; }
bool operator==(const_local_iterator x) const { return ptr_ == x.ptr_; }
bool operator!=(hash_local_iterator x) const { return ptr_ != x.ptr_; }
bool operator!=(const_local_iterator x) const { return ptr_ != x.ptr_; }
};
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_table_manager<A, G> manager;
typedef BOOST_DEDUCED_TYPENAME manager::node_ptr ptr;
typedef BOOST_DEDUCED_TYPENAME manager::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_); }
hash_const_local_iterator& operator++() { ptr_ = next_node(ptr_); return *this; }
hash_const_local_iterator operator++(int) { hash_const_local_iterator tmp(ptr_); ptr_ = next_node(ptr_); return tmp; }
bool operator==(local_iterator x) const { return ptr_ == x.ptr_; }
bool operator==(hash_const_local_iterator x) const { return ptr_ == x.ptr_; }
bool operator!=(local_iterator x) const { return ptr_ != x.ptr_; }
bool operator!=(hash_const_local_iterator x) const { return ptr_ != x.ptr_; }
};
// 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_table_manager<A, G> manager;
typedef BOOST_DEDUCED_TYPENAME manager::node node;
typedef BOOST_DEDUCED_TYPENAME manager::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 node::get_value(base_.get()); }
value_type* operator->() const { return &node::get_value(base_.get()); }
hash_iterator& operator++() { base_.increment(); return *this; }
hash_iterator operator++(int) { hash_iterator tmp(base_); base_.increment(); return tmp; }
bool operator==(hash_iterator const& x) const { return base_ == x.base_; }
bool operator==(const_iterator const& x) const { return base_ == x.base_; }
bool operator!=(hash_iterator const& x) const { return base_ != x.base_; }
bool operator!=(const_iterator const& x) const { return base_ != x.base_; }
};
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_table_manager<A, G> manager;
typedef BOOST_DEDUCED_TYPENAME manager::node node;
typedef BOOST_DEDUCED_TYPENAME manager::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 node::get_value(base_.get()); }
value_type const* operator->() const { return &node::get_value(base_.get()); }
hash_const_iterator& operator++() { base_.increment(); return *this; }
hash_const_iterator operator++(int) { hash_const_iterator tmp(base_); base_.increment(); return tmp; }
bool operator==(iterator const& x) const { return base_ == x.base_; }
bool operator==(hash_const_iterator const& x) const { return base_ == x.base_; }
bool operator!=(iterator const& x) const { return base_ != x.base_; }
bool operator!=(hash_const_iterator const& x) const { return base_ != x.base_; }
};
}}
#endif

View File

@ -1,347 +0,0 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2009 Daniel James
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_UNORDERED_DETAIL_HASH_TABLE_HPP_INCLUDED
#define BOOST_UNORDERED_DETAIL_HASH_TABLE_HPP_INCLUDED
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
#include <boost/config.hpp>
#include <boost/unordered/detail/config.hpp>
#if !defined(BOOST_UNORDERED_EMPLACE_LIMIT)
#define BOOST_UNORDERED_EMPLACE_LIMIT 10
#endif
#include <cstddef>
#include <boost/config/no_tr1/cmath.hpp>
#include <algorithm>
#include <utility>
#include <stdexcept>
#include <boost/iterator.hpp>
#include <boost/iterator/iterator_categories.hpp>
#include <boost/limits.hpp>
#include <boost/assert.hpp>
#include <boost/static_assert.hpp>
#include <boost/unordered/detail/allocator_helpers.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/aligned_storage.hpp>
#include <boost/type_traits/alignment_of.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/and.hpp>
#include <boost/mpl/or.hpp>
#include <boost/mpl/not.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/utility/swap.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/mpl/aux_/config/eti.hpp>
#if !(defined(BOOST_UNORDERED_STD_FORWARD))
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#define BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
BOOST_PP_ENUM_PARAMS_Z(z, n, typename Arg)
#define BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, Arg, const& arg)
#define BOOST_UNORDERED_CALL_PARAMS(z, n) \
BOOST_PP_ENUM_PARAMS_Z(z, n, arg)
#endif
#if defined(BOOST_MSVC)
#pragma warning(push)
#if BOOST_MSVC >= 1400
#pragma warning(disable:4267) // conversion from 'size_t' to 'unsigned int',
// possible loss of data.
#endif
#endif
#if BOOST_WORKAROUND(__BORLANDC__, <= 0x0582)
#define BOOST_UNORDERED_BORLAND_BOOL(x) (bool)(x)
#else
#define BOOST_UNORDERED_BORLAND_BOOL(x) x
#endif
#if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
#define BOOST_UNORDERED_MSVC_RESET_PTR(x) unordered_detail::reset(x)
#else
#define BOOST_UNORDERED_MSVC_RESET_PTR(x)
#endif
namespace boost {
namespace unordered_detail {
template <class T> struct type_wrapper {};
static const std::size_t default_initial_bucket_count = 11;
static const float minimum_max_load_factor = 1e-3f;
inline std::size_t double_to_size_t(double f)
{
return f >= static_cast<double>((std::numeric_limits<std::size_t>::max)()) ?
(std::numeric_limits<std::size_t>::max)() :
static_cast<std::size_t>(f);
}
// prime number list, accessor
template<typename T> struct prime_list_template
{
static std::size_t const value[];
static std::ptrdiff_t const length;
};
#define BOOST_UNORDERED_PRIMES \
(5ul)(11ul)(17ul)(29ul)(37ul)(53ul)(67ul)(79ul) \
(97ul)(131ul)(193ul)(257ul)(389ul)(521ul)(769ul) \
(1031ul)(1543ul)(2053ul)(3079ul)(6151ul)(12289ul)(24593ul) \
(49157ul)(98317ul)(196613ul)(393241ul)(786433ul) \
(1572869ul)(3145739ul)(6291469ul)(12582917ul)(25165843ul) \
(50331653ul)(100663319ul)(201326611ul)(402653189ul)(805306457ul) \
(1610612741ul)(3221225473ul)(4294967291ul)
template<typename T>
std::size_t const prime_list_template<T>::value[] = {
BOOST_PP_SEQ_ENUM(BOOST_UNORDERED_PRIMES)
};
template<typename T>
std::ptrdiff_t const prime_list_template<T>::length
= BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES);
#undef BOOST_UNORDERED_PRIMES
typedef prime_list_template<std::size_t> prime_list;
// no throw
inline std::size_t next_prime(std::size_t n) {
std::size_t const* const prime_list_begin = prime_list::value;
std::size_t const* const prime_list_end = prime_list_begin +
prime_list::length;
std::size_t const* bound =
std::lower_bound(prime_list_begin, prime_list_end, n);
if(bound == prime_list_end)
bound--;
return *bound;
}
// no throw
inline std::size_t prev_prime(std::size_t n) {
std::size_t const* const prime_list_begin = prime_list::value;
std::size_t const* const prime_list_end = prime_list_begin +
prime_list::length;
std::size_t const* bound =
std::upper_bound(prime_list_begin,prime_list_end, n);
if(bound != prime_list_begin)
bound--;
return *bound;
}
// Controls how many buckets are allocated and which buckets hash
// values map to. Does not contain the buckets themselves, or ever
// deal with them directly.
struct bucket_manager {
std::size_t bucket_count_;
bucket_manager()
: bucket_count_(0) {}
explicit bucket_manager(std::size_t n)
: bucket_count_(next_prime(n)) {}
std::size_t bucket_count() const {
return bucket_count_;
}
std::size_t bucket_from_hash(std::size_t hashed) const {
return hashed % bucket_count_;
}
std::size_t max_bucket_count(std::size_t max_size) const {
return prev_prime(max_size);
}
};
// pair_cast - used to convert between pair types.
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));
}
#if !defined(BOOST_NO_STD_DISTANCE)
using ::std::distance;
#else
template <class ForwardIterator>
inline std::size_t distance(ForwardIterator i, ForwardIterator j) {
std::size_t x;
std::distance(i, j, x);
return x;
}
#endif
struct move_tag {};
// Both hasher and key_equal's copy/assign can throw so double
// buffering is used to copy them.
template <typename Hash, typename Pred>
struct buffered_functions
{
typedef Hash hasher;
typedef Pred key_equal;
class functions
{
std::pair<hasher, key_equal> functions_;
public:
functions(hasher const& h, key_equal const& k)
: functions_(h, k) {}
hasher const& hash_function() const
{
return functions_.first;
}
key_equal const& key_eq() const
{
return functions_.second;
}
};
typedef functions buffered_functions::*functions_ptr;
buffered_functions(hasher const& h, key_equal const& k)
: func1_(h, k), func2_(h, k), func_(&buffered_functions::func1_) {}
// This copies the given function objects into the currently unused
// function objects and returns a pointer, that func_ can later be
// set to, to commit the change.
//
// Strong exception safety (since only usued function objects are
// changed).
functions_ptr buffer(buffered_functions const& x) {
functions_ptr ptr = func_ == &buffered_functions::func1_
? &buffered_functions::func2_ : &buffered_functions::func1_;
this->*ptr = x.current();
return ptr;
}
void set(functions_ptr ptr) {
BOOST_ASSERT(ptr != func_);
func_ = ptr;
}
functions const& current() const {
return this->*func_;
}
private:
functions func1_;
functions func2_;
functions_ptr func_; // The currently active functions.
};
#if defined(BOOST_MSVC)
# define BOOST_UNORDERED_DESTRUCT(x, type) (x)->~type();
#else
# define BOOST_UNORDERED_DESTRUCT(x, type) boost::unordered_detail::destroy(x)
template <typename T>
void destroy(T* x) {
x->~T();
}
#endif
}
}
#define BOOST_UNORDERED_EQUIVALENT_KEYS 1
#include <boost/unordered/detail/hash_table_impl.hpp>
#undef BOOST_UNORDERED_EQUIVALENT_KEYS
#define BOOST_UNORDERED_EQUIVALENT_KEYS 0
#include <boost/unordered/detail/hash_table_impl.hpp>
#undef BOOST_UNORDERED_EQUIVALENT_KEYS
namespace boost {
namespace unordered_detail {
class iterator_access
{
public:
template <class Iterator>
static BOOST_DEDUCED_TYPENAME Iterator::base const& get(Iterator const& it) {
return it.base_;
}
};
template <class ValueType, class KeyType,
class Hash, class Pred, class Alloc>
class hash_types_unique_keys
{
public:
typedef BOOST_DEDUCED_TYPENAME
boost::unordered_detail::rebind_wrap<Alloc, ValueType>::type
value_allocator;
typedef hash_table_unique_keys<ValueType, KeyType, Hash, Pred,
value_allocator> hash_table;
typedef hash_table_data_unique_keys<value_allocator> data;
typedef BOOST_DEDUCED_TYPENAME data::iterator_base iterator_base;
typedef hash_const_local_iterator_unique_keys<value_allocator> const_local_iterator;
typedef hash_local_iterator_unique_keys<value_allocator> local_iterator;
typedef hash_const_iterator_unique_keys<value_allocator> const_iterator;
typedef hash_iterator_unique_keys<value_allocator> iterator;
typedef BOOST_DEDUCED_TYPENAME data::size_type size_type;
typedef std::ptrdiff_t difference_type;
};
template <class ValueType, class KeyType,
class Hash, class Pred, class Alloc>
class hash_types_equivalent_keys
{
public:
typedef BOOST_DEDUCED_TYPENAME
boost::unordered_detail::rebind_wrap<Alloc, ValueType>::type
value_allocator;
typedef hash_table_equivalent_keys<ValueType, KeyType, Hash, Pred,
value_allocator> hash_table;
typedef hash_table_data_equivalent_keys<value_allocator> data;
typedef BOOST_DEDUCED_TYPENAME data::iterator_base iterator_base;
typedef hash_const_local_iterator_equivalent_keys<value_allocator> const_local_iterator;
typedef hash_local_iterator_equivalent_keys<value_allocator> local_iterator;
typedef hash_const_iterator_equivalent_keys<value_allocator> const_iterator;
typedef hash_iterator_equivalent_keys<value_allocator> iterator;
typedef BOOST_DEDUCED_TYPENAME data::size_type size_type;
typedef std::ptrdiff_t difference_type;
};
} // namespace boost::unordered_detail
} // namespace boost
#undef BOOST_UNORDERED_BORLAND_BOOL
#undef BOOST_UNORDERED_MSVC_RESET_PTR
#if defined(BOOST_MSVC)
#pragma warning(pop)
#endif
#endif // BOOST_UNORDERED_DETAIL_HASH_TABLE_HPP_INCLUDED

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -0,0 +1,270 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2009 Daniel James
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED
#define BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED
#include <boost/config.hpp>
#include <boost/assert.hpp>
#include <boost/unordered/detail/structure.hpp>
namespace boost { namespace unordered_detail {
////////////////////////////////////////////////////////////////////////////
// Explicitly call a destructor
#if defined(BOOST_MSVC)
# define BOOST_UNORDERED_DESTRUCT(x, type) (x)->~type();
#else
# define BOOST_UNORDERED_DESTRUCT(x, type) boost::unordered_detail::destroy(x)
template <class T>
void destroy(T* x) {
x->~T();
}
#endif
// Constructors
template <class A, class G>
hash_table_manager<A, G>::hash_table_manager()
: structure(), allocators_() {}
template <class A, class G>
hash_table_manager<A, G>::hash_table_manager(value_allocator const& a)
: structure(), allocators_(a,a) {}
template <class A, class G>
hash_table_manager<A, G>::hash_table_manager(hash_table_manager const& h)
: structure(), allocators_(h.allocators_) {}
template <class A, class G>
hash_table_manager<A, G>::hash_table_manager(hash_table_manager& x, move_tag m)
: structure(), allocators_(x.allocators_)
{
this->buckets_ = x.buckets_;
this->cached_begin_bucket_ = x.cached_begin_bucket_;
this->size_ = x.size_;
this->bucket_count_ = x.bucket_count_;
x.buckets_ = bucket_ptr();
x.cached_begin_bucket_ = bucket_ptr();
x.size_ = 0;
x.bucket_count_ = 0;
}
template <class A, class G>
hash_table_manager<A, G>::hash_table_manager(hash_table_manager& x, value_allocator const& a, move_tag m) :
structure(), allocators_(a,a)
{
if(this->node_alloc() == x.node_alloc()) {
this->buckets_ = x.buckets_;
this->cached_begin_bucket_ = x.cached_begin_bucket_;
this->size_ = x.size_;
this->bucket_count_ = x.bucket_count_;
x.buckets_ = bucket_ptr();
x.cached_begin_bucket_ = bucket_ptr();
x.size_ = 0;
x.bucket_count_ = 0;
}
}
template <class A, class G>
hash_table_manager<A, G>::~hash_table_manager()
{
if(this->buckets_) { delete_buckets(); }
}
// no throw
template <class A, class G>
void hash_table_manager<A, G>::move(hash_table_manager& other)
{
delete_buckets();
this->buckets_ = other.buckets_;
this->cached_begin_bucket_ = other.cached_begin_bucket_;
this->size_ = other.size_;
this->bucket_count_ = other.bucket_count_;
other.buckets_ = bucket_ptr();
other.cached_begin_bucket_ = bucket_ptr();
other.size_ = 0;
other.bucket_count_ = 0;
}
// Construct/destruct
template <class A, class G>
void hash_table_manager<A, G>::create_buckets(std::size_t bucket_count) {
BOOST_ASSERT(!this->buckets_ && !this->size_);
// The array constructor will clean up in the event of an
// exception.
allocator_array_constructor<bucket_allocator>
constructor(bucket_alloc());
// Creates an extra bucket to act as a sentinel.
constructor.construct(bucket(), bucket_count + 1);
this->cached_begin_bucket_ = constructor.get() + static_cast<ptrdiff_t>(bucket_count);
// Set up the sentinel (node_ptr cast)
this->cached_begin_bucket_->next_ = this->cached_begin_bucket_;
// Only release the buckets once everything is successfully
// done.
this->buckets_ = constructor.release();
this->bucket_count_ = bucket_count;
}
template <class A, class G>
void hash_table_manager<A, G>::destruct_node(node_ptr b)
{
node* raw_ptr = static_cast<node*>(&*b);
BOOST_UNORDERED_DESTRUCT(&raw_ptr->value(), value_type);
real_node_ptr n(node_alloc().address(*raw_ptr));
node_alloc().destroy(n);
node_alloc().deallocate(n, 1);
}
// Delete and clear buckets
template <class A, class G>
void hash_table_manager<A, G>::delete_group(node_ptr first_node)
{
delete_nodes(first_node, node::next_group(first_node));
}
template <class A, class G>
void hash_table_manager<A, G>::delete_nodes(node_ptr begin, node_ptr end)
{
while(begin != end) {
node_ptr node = begin;
begin = next_node(begin);
destruct_node(node);
}
}
template <class A, class G>
void hash_table_manager<A, G>::delete_to_bucket_end(node_ptr begin)
{
while(BOOST_UNORDERED_BORLAND_BOOL(begin)) {
node_ptr node = begin;
begin = next_node(begin);
destruct_node(node);
}
}
template <class A, class G>
void hash_table_manager<A, G>::clear_bucket(bucket_ptr b)
{
node_ptr node_it = b->next_;
b->next_ = node_ptr();
while(node_it) {
node_ptr node_to_destruct = node_it;
node_it = next_node(node_it);
destruct_node(node_to_destruct);
}
}
template <class A, class G>
void hash_table_manager<A, G>::clear()
{
for(bucket_ptr begin = this->buckets_begin(), end = this->buckets_end(); begin != end; ++begin) {
clear_bucket(begin);
}
this->cached_begin_bucket_ = this->buckets_end();
this->size_ = 0;
}
template <class A, class G>
void hash_table_manager<A, G>::delete_buckets()
{
clear();
// Destroy the buckets (including the sentinel bucket).
bucket_ptr end = this->buckets_end();
++end;
for(bucket_ptr begin = this->buckets_begin(); begin != end; ++begin) {
bucket_alloc().destroy(begin);
}
bucket_alloc().deallocate(this->buckets_begin(), this->bucket_count() + 1);
this->buckets_= bucket_ptr();
}
template <class A, class G>
BOOST_DEDUCED_TYPENAME hash_table_manager<A, G>::iterator_base
hash_table_manager<A, G>::erase(iterator_base r)
{
BOOST_ASSERT(!r.is_end());
iterator_base next = r;
next.increment();
this->unlink_node(r.bucket_, r.node_);
destruct_node(r.node_);
// r has been invalidated but its bucket is still valid
this->recompute_begin_bucket(r.bucket_, next.bucket_);
return next;
}
template <class A, class G>
std::size_t hash_table_manager<A, G>::erase_group(node_ptr* it, bucket_ptr bucket)
{
node_ptr pos = *it;
std::size_t count = this->unlink_group(it);
delete_group(pos);
this->recompute_begin_bucket(bucket);
return count;
}
template <class A, class G>
BOOST_DEDUCED_TYPENAME hash_table_manager<A, G>::iterator_base
hash_table_manager<A, G>::erase_range(iterator_base r1, iterator_base r2)
{
if(r1 != r2)
{
BOOST_ASSERT(!r1.is_end());
if (r1.bucket_ == r2.bucket_) {
this->unlink_nodes(r1.bucket_, r1.node_, r2.node_);
delete_nodes(r1.node_, r2.node_);
// No need to call recompute_begin_bucket because
// the nodes are only deleted from one bucket, which
// still contains r2 after the erase.
BOOST_ASSERT(r1.bucket_->next_);
}
else {
BOOST_ASSERT(r1.bucket_ < r2.bucket_);
this->unlink_nodes(r1.bucket_, r1.node_, node_ptr());
delete_to_bucket_end(r1.node_);
bucket_ptr i = r1.bucket_;
for(++i; i != r2.bucket_; ++i) {
this->size_ -= node_count(i->next_, node_ptr());
clear_bucket(i);
}
if(!r2.is_end()) {
node_ptr first = r2.bucket_->next_;
this->unlink_nodes(r2.bucket_, r2.node_);
delete_nodes(first, r2.node_);
}
// r1 has been invalidated but its bucket is still
// valid.
this->recompute_begin_bucket(r1.bucket_, r2.bucket_);
}
}
return r2;
}
}}
#endif

View File

@ -11,7 +11,7 @@
#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>
@ -20,7 +20,20 @@
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/is_class.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/unordered/detail/config.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
/*************************************************************************************************/

View File

@ -0,0 +1,265 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2009 Daniel James
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// 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_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>
#if BOOST_WORKAROUND(__BORLANDC__, <= 0X0582)
#define BOOST_UNORDERED_BORLAND_BOOL(x) (bool)(x)
#else
#define BOOST_UNORDERED_BORLAND_BOOL(x) x
#endif
namespace boost { namespace unordered_detail {
template <class BucketPtr>
static inline BucketPtr& next_node(BucketPtr ptr)
{
return ptr->next_;
}
template <class BucketPtr>
static inline std::size_t node_count(BucketPtr ptr, BucketPtr end)
{
std::size_t count = 0;
while(ptr != end) {
++count;
ptr = next_node(ptr);
}
return count;
}
////////////////////////////////////////////////////////////////////////////
// ungrouped node implementation
template <class A>
inline BOOST_DEDUCED_TYPENAME ungrouped_node_base<A>::node_ptr&
ungrouped_node_base<A>::next_group(node_ptr ptr)
{
return next_node(ptr);
}
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)
{
next_node(n) = b.next_;
b.next_ = n;
}
template <class A>
inline void ungrouped_node_base<A>::add_group_to_bucket(node_ptr n, bucket& b)
{
next_node(n) = b.next_;
b.next_ = n;
}
template <class A>
inline void ungrouped_node_base<A>::add_after_node(node_ptr n, node_ptr position)
{
next_node(n) = next_node(position);
next_node(position) = position;
}
template <class A>
void ungrouped_node_base<A>::unlink_node(bucket& b, node_ptr node)
{
unlink_nodes(b, node, next_node(node));
}
template <class A>
void ungrouped_node_base<A>::unlink_nodes(bucket& b, node_ptr begin, node_ptr end)
{
node_ptr* pos = &b.next_;
while(*pos != begin) pos = &next_node(*pos);
*pos = end;
}
template <class A>
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_group(node_ptr* b)
{
*b = next_node(*b);
}
////////////////////////////////////////////////////////////////////////////
// grouped node implementation
template <class A>
inline BOOST_DEDUCED_TYPENAME grouped_node_base<A>::node_ptr&
grouped_node_base<A>::group_prev(node_ptr ptr)
{
return get(ptr).group_prev_;
}
template <class A>
inline BOOST_DEDUCED_TYPENAME grouped_node_base<A>::node_ptr&
grouped_node_base<A>::next_group(node_ptr ptr)
{
return next_node(group_prev(ptr));
}
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 = group_prev(ptr);
} while(ptr != start);
return size;
}
template <class A>
inline void grouped_node_base<A>::add_to_bucket(node_ptr n, bucket& b)
{
next_node(n) = b.next_;
group_prev(n) = n;
b.next_ = n;
}
template <class A>
inline void grouped_node_base<A>::add_group_to_bucket(node_ptr n, bucket& b)
{
next_group(n) = b.next_;
b.next_ = n;
}
template <class A>
inline void grouped_node_base<A>::add_after_node(node_ptr n, node_ptr position)
{
next_node(n) = next_group(position);
group_prev(n) = group_prev(position);
next_group(position) = n;
group_prev(position) = n;
}
// 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)
{
// If split is at the beginning of the group then there's
// nothing to split.
if(next_node(group_prev(split)) != split)
return split;
// Find the start of the group.
node_ptr start = split;
do {
start = group_prev(start);
} while(next_node(group_prev(start)) == start);
node_ptr last = group_prev(start);
group_prev(start) = group_prev(split);
group_prev(split) = last;
return start;
}
template <class A>
void grouped_node_base<A>::unlink_node(bucket& b, node_ptr node)
{
node_ptr next = next_node(node);
node_ptr* pos = &next_node(group_prev(node));
if(*pos != node) {
// The node is at the beginning of a group.
// Find the previous node pointer:
pos = &b.next_;
while(*pos != node) pos = &next_group(*pos);
// Remove from group
if(BOOST_UNORDERED_BORLAND_BOOL(next) && group_prev(next) == node)
group_prev(next) = group_prev(node);
}
else if(BOOST_UNORDERED_BORLAND_BOOL(next) && group_prev(next) == node) {
// The deleted node is not at the end of the group, so
// change the link from the next node.
group_prev(next) = group_prev(node);
}
else {
// The deleted node is at the end of the group, so the
// first node in the group is pointing to it.
// Find that to change its pointer.
node_ptr x = group_prev(node);
while(group_prev(x) != node) {
x = group_prev(x);
}
group_prev(x) = group_prev(node);
}
*pos = next;
}
template <class A>
void grouped_node_base<A>::unlink_nodes(bucket& b, node_ptr begin, node_ptr end)
{
node_ptr* pos = &next_node(group_prev(begin));
if(*pos != begin) {
// The node is at the beginning of a group.
// 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);
}
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 = group_prev(group1);
node_ptr end2 = group_prev(group2);
group_prev(group1) = end2;
group_prev(group2) = end1;
}
}
}
*pos = end;
}
template <class A>
void grouped_node_base<A>::unlink_nodes(bucket& b, node_ptr end)
{
split_group(end);
b.next_ = end;
}
template <class A>
inline void grouped_node_base<A>::unlink_group(node_ptr* b)
{
*b = next_group(*b);
}
}}
#endif

View File

@ -0,0 +1,220 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2009 Daniel James
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// 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_DETAIL_STRUCTURE_HPP_INCLUDED
#define BOOST_UNORDERED_DETAIL_STRUCTURE_HPP_INCLUDED
#include <boost/unordered/detail/node.hpp>
namespace boost { namespace unordered_detail {
////////////////////////////////////////////////////////////////////////////
// hash_structure implementation
template <class A, class G>
void hash_structure<A, G>::swap(hash_structure<A, G>& other)
{
std::swap(buckets_, other.buckets_);
std::swap(cached_begin_bucket_, other.cached_begin_bucket_);
std::swap(size_, other.size_);
std::swap(bucket_count_, other.bucket_count_);
}
template <class A, class G>
std::size_t hash_structure<A, G>::bucket_count() const
{
return bucket_count_;
}
template <class A, class G>
std::size_t hash_structure<A, G>::bucket_from_hash(std::size_t hashed) const
{
return hashed % bucket_count_;
}
template <class A, class G>
BOOST_DEDUCED_TYPENAME hash_structure<A, G>::bucket_ptr
hash_structure<A, G>::bucket_ptr_from_hash(std::size_t hashed) const
{
return buckets_ + static_cast<std::ptrdiff_t>(
bucket_from_hash(hashed));
}
template <class A, class G>
BOOST_DEDUCED_TYPENAME hash_structure<A, G>::bucket_ptr
hash_structure<A, G>::buckets_begin() const
{
return buckets_;
}
template <class A, class G>
BOOST_DEDUCED_TYPENAME hash_structure<A, G>::bucket_ptr
hash_structure<A, G>::buckets_end() const
{
return buckets_ + static_cast<std::ptrdiff_t>(bucket_count_);
}
template <class A, class G>
std::size_t hash_structure<A, G>::bucket_size(std::size_t index) const
{
bucket_ptr ptr = (buckets_ + static_cast<std::ptrdiff_t>(index))->next_;
std::size_t count = 0;
while(ptr) {
++count;
ptr = next_node(ptr);
}
return count;
}
// Link a node
template <class A, class G>
void hash_structure<A, G>::link_node(node_ptr n, node_ptr position)
{
node_base::add_after_node(n, position);
++size_;
}
template <class A, class G>
void hash_structure<A, G>::link_node_in_bucket(node_ptr n, bucket_ptr bucket)
{
node_base::add_to_bucket(n, *bucket);
++size_;
if(bucket < cached_begin_bucket_) cached_begin_bucket_ = bucket;
}
template <class A, class G>
void hash_structure<A, G>::unlink_node(bucket_ptr bucket, node_ptr pos)
{
--size_;
node_base::unlink_node(*bucket, pos);
}
template <class A, class G>
void hash_structure<A, G>::unlink_nodes(
bucket_ptr bucket, node_ptr begin, node_ptr end)
{
size_ -= node_count(begin, end);
node_base::unlink_nodes(*bucket, begin, end);
}
template <class A, class G>
void hash_structure<A, G>::unlink_nodes(bucket_ptr bucket, node_ptr end)
{
size_ -= node_count(bucket->next_, end);
node_base::unlink_nodes(*bucket, end);
}
template <class A, class G>
std::size_t hash_structure<A, G>::unlink_group(node_ptr* pos)
{
std::size_t count = node_base::group_count(*pos);
size_ -= count;
node_base::unlink_group(pos);
return count;
}
template <class A, class G>
void hash_structure<A, G>::link_group(
node_ptr n, bucket_ptr bucket, std::size_t count)
{
node_base::add_group_to_bucket(n, *bucket);
size_ += count;
if(bucket < cached_begin_bucket_) cached_begin_bucket_ = bucket;
}
template <class A, class G>
BOOST_DEDUCED_TYPENAME hash_structure<A, G>::bucket_ptr
hash_structure<A, G>::get_bucket(std::size_t n) const
{
return buckets_ + static_cast<std::ptrdiff_t>(n);
}
template <class A, class G>
BOOST_DEDUCED_TYPENAME hash_structure<A, G>::node_ptr
hash_structure<A, G>::bucket_begin(std::size_t n) const
{
return (buckets_ + static_cast<std::ptrdiff_t>(n))->next_;
}
template <class A, class G>
BOOST_DEDUCED_TYPENAME hash_structure<A, G>::node_ptr
hash_structure<A, G>::bucket_end(std::size_t) const
{
return node_ptr();
}
// recompute_begin_bucket
//
// After an erase cached_begin_bucket_ might be left pointing to
// an empty bucket, so this is called to update it
//
// no throw
template <class A, class G>
void hash_structure<A, G>::recompute_begin_bucket(bucket_ptr b)
{
BOOST_ASSERT(!(b < cached_begin_bucket_));
if(b == cached_begin_bucket_)
{
if (size_ != 0) {
while (!cached_begin_bucket_->next_)
++cached_begin_bucket_;
} else {
cached_begin_bucket_ = buckets_end();
}
}
}
// This is called when a range has been erased
//
// no throw
template <class A, class G>
void hash_structure<A, G>::recompute_begin_bucket(bucket_ptr b1, bucket_ptr b2)
{
BOOST_ASSERT(!(b1 < cached_begin_bucket_) && !(b2 < b1));
BOOST_ASSERT(BOOST_UNORDERED_BORLAND_BOOL(b2->next_));
if(b1 == cached_begin_bucket_ && !b1->next_)
cached_begin_bucket_ = b2;
}
// no throw
template <class A, class G>
inline float hash_structure<A, G>::load_factor() const
{
BOOST_ASSERT(bucket_count_ != 0);
return static_cast<float>(size_)
/ static_cast<float>(bucket_count_);
}
////////////////////////////////////////////////////////////////////////////
// hash_iterator_base implementation
template <class BucketPtr>
inline void hash_iterator_base<BucketPtr>::increment(node_ptr node) {
while(!node) {
++bucket_;
node = bucket_->next_;
}
node_ = node;
}
template <class BucketPtr>
inline void hash_iterator_base<BucketPtr>::increment()
{
increment(next_node(node_));
}
}}
#endif

View File

@ -0,0 +1,561 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2009 Daniel James
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED
#define BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED
#include <cstddef>
#include <stdexcept>
#include <algorithm>
#include <boost/config/no_tr1/cmath.hpp>
#include <boost/iterator/iterator_categories.hpp>
#include <boost/unordered/detail/manager.hpp>
#include <boost/unordered/detail/util.hpp>
namespace boost { namespace unordered_detail {
////////////////////////////////////////////////////////////////////////////
// Helper methods
// strong exception safety, no side effects
template <class H, class P, class A, class G, class K>
inline bool hash_table<H, P, A, G, K>
::equal(key_type const& k, value_type const& v) const
{
return this->key_eq()(k, extractor::extract(v));
}
// strong exception safety, no side effects
template <class H, class P, class A, class G, class K>
inline BOOST_DEDUCED_TYPENAME hash_table<H, P, A, G, K>::node_ptr
hash_table<H, P, A, G, K>
::find_iterator(bucket_ptr bucket, key_type const& k) const
{
node_ptr it = bucket->next_;
while (BOOST_UNORDERED_BORLAND_BOOL(it) && !equal(k, node::get_value(it))) {
it = node::next_group(it);
}
return it;
}
// strong exception safety, no side effects
template <class H, class P, class A, class G, class K>
inline BOOST_DEDUCED_TYPENAME hash_table<H, P, A, G, K>::node_ptr
hash_table<H, P, A, G, K>
::find_iterator(key_type const& k) const
{
return find_iterator(this->get_bucket(this->bucket_index(k)), k);
}
// strong exception safety, no side effects
template <class H, class P, class A, class G, class K>
BOOST_DEDUCED_TYPENAME hash_table<H, P, A, G, K>::node_ptr*
hash_table<H, P, A, G, K>
::find_for_erase(bucket_ptr bucket, key_type const& k) const
{
node_ptr* it = &bucket->next_;
while(BOOST_UNORDERED_BORLAND_BOOL(*it) && !equal(k, node::get_value(*it)))
it = &node::next_group(*it);
return it;
}
////////////////////////////////////////////////////////////////////////////
// Load methods
// no throw
template <class H, class P, class A, class G, class K>
std::size_t hash_table<H, P, A, G, K>
::max_size() const
{
using namespace std;
// size < mlf_ * count
return double_to_size_t(ceil(
(double) this->mlf_ * this->max_bucket_count())) - 1;
}
// strong safety
template <class H, class P, class A, class G, class K>
std::size_t hash_table<H, P, A, G, K>
::bucket_index(key_type const& k) const
{
// hash_function can throw:
return this->bucket_from_hash(this->hash_function()(k));
}
template <class H, class P, class A, class G, class K>
void hash_table<H, P, A, G, K>
::max_load_factor(float z)
{
BOOST_ASSERT(z > 0);
mlf_ = (std::max)(z, minimum_max_load_factor);
this->calculate_max_load();
}
// no throw
template <class H, class P, class A, class G, class K>
std::size_t hash_table<H, P, A, G, K>
::min_buckets_for_size(std::size_t n) const
{
BOOST_ASSERT(this->mlf_ != 0);
using namespace std;
// From 6.3.1/13:
// size < mlf_ * count
// => count > size / mlf_
//
// Or from rehash post-condition:
// count > size / mlf_
return double_to_size_t(floor(n / (double) mlf_)) + 1;
}
// no throw
template <class H, class P, class A, class G, class K>
void hash_table<H, P, A, G, K>
::calculate_max_load()
{
using namespace std;
// From 6.3.1/13:
// Only resize when size >= mlf_ * count
max_load_ = double_to_size_t(ceil((double) mlf_ * this->bucket_count()));
}
////////////////////////////////////////////////////////////////////////////
// Constructors
template <class H, class P, class A, class G, class K>
hash_table<H, P, A, G, K>
::hash_table(std::size_t n, hasher const& hf, key_equal const& eq, value_allocator const& a) :
manager(a), func_(false), mlf_(1.0f), max_load_(0)
{
std::uninitialized_fill((functions*)this->funcs_, (functions*)this->funcs_+2,
functions(hf, eq));
this->create_buckets(next_prime(n));
this->calculate_max_load();
}
template <class H, class P, class A, class G, class K>
hash_table<H, P, A, G, K>
::hash_table(hash_table const& x) :
manager(x), func_(false), mlf_(x.mlf_), max_load_(0)
{
std::uninitialized_fill((functions*)this->funcs_, (functions*)this->funcs_+2,
x.current());
this->create_buckets(next_prime(x.min_buckets_for_size(x.size_)));
this->calculate_max_load();
x.copy_buckets_to(*this);
}
// Copy Construct with allocator
template <class H, class P, class A, class G, class K>
hash_table<H, P, A, G, K>
::hash_table(hash_table const& x, value_allocator const& a) :
manager(a), func_(false), mlf_(x.mlf_), max_load_(0)
{
std::uninitialized_fill((functions*)this->funcs_, (functions*)this->funcs_+2,
x.current());
this->create_buckets(next_prime(x.min_buckets_for_size(x.size_)));
this->calculate_max_load();
x.copy_buckets_to(*this);
}
// Move Construct
template <class H, class P, class A, class G, class K>
hash_table<H, P, A, G, K>
::hash_table(hash_table& x, move_tag m) :
manager(x, m), func_(false), mlf_(x.mlf_), max_load_(0)
{
// TODO: Shouldn't I move the functions if poss.
std::uninitialized_fill((functions*)this->funcs_, (functions*)this->funcs_+2,
x.current());
}
template <class H, class P, class A, class G, class K>
hash_table<H, P, A, G, K>
::hash_table(hash_table& x, value_allocator const& a, move_tag m) :
manager(x, a, m), func_(false), mlf_(x.mlf_), max_load_(0)
{
std::uninitialized_fill((functions*)this->funcs_, (functions*)this->funcs_+2,
x.current());
this->calculate_max_load(); // no throw
if(!this->buckets_) {
this->create_buckets(next_prime(x.min_buckets_for_size(x.size_)));
// This can throw, but hash_table_manager's destructor will clean
// up.
x.copy_buckets_to(*this);
}
}
template <class H, class P, class A, class G, class K>
hash_table<H, P, A, G, K>::~hash_table()
{
BOOST_UNORDERED_DESTRUCT(this->get_functions(false), functions);
BOOST_UNORDERED_DESTRUCT(this->get_functions(true), functions);
}
template <class H, class P, class A, class G, class K>
hash_table<H, P, A, G, K>& hash_table<H, P, A, G, K>::operator=(hash_table const& x)
{
if(this != &x) {
this->clear(); // no throw
this->set_functions(
this->buffer_functions(x)); // throws, strong
this->mlf_ = x.mlf_; // no throw
this->calculate_max_load(); // no throw
this->reserve(x.size_); // throws
x.copy_buckets_to(*this); // throws
}
return *this;
}
////////////////////////////////////////////////////////////////////////////
// Swap & Move
// Swap
//
// Strong exception safety
//
// Can throw if hash or predicate object's copy constructor throws
// or if allocators are unequal.
template <class H, class P, class A, class G, class K>
void hash_table<H, P, A, G, K>
::swap(hash_table& x)
{
// The swap code can work when swapping a container with itself
// but it triggers an assertion in buffered_functions.
// At the moment, I'd rather leave that assertion in and add a
// check here, rather than remove the assertion. I might change
// this at a later date.
if(this == &x) return;
// These can throw, but they only affect the function objects
// that aren't in use so it is strongly exception safe, via.
// double buffering.
functions_ptr new_func_this = this->buffer_functions(x);
functions_ptr new_func_that = x.buffer_functions(*this);
if(this->node_alloc() == x.node_alloc()) {
this->manager::swap(x); // No throw
}
else {
// Create new buckets in separate hash_table_manager objects
// which will clean up if anything throws an exception.
// (all can throw, but with no effect as these are new objects).
manager new_this(*this);
new_this.create_buckets(x.min_buckets_for_size(x.size_));
x.copy_buckets_to(new_this);
manager new_that(x);
new_that.create_buckets(this->min_buckets_for_size(this->size_));
copy_buckets_to(new_that);
// Modifying the data, so no throw from now on.
this->manager::swap(new_this);
x.manager::swap(new_that);
}
// The rest is no throw.
std::swap(this->mlf_, x.mlf_);
this->set_functions(new_func_this);
x.set_functions(new_func_that);
//TODO: Test that this works:
this->calculate_max_load();
x.calculate_max_load();
}
// Move
//
// Strong exception safety (might change unused function objects)
//
// Can throw if hash or predicate object's copy constructor throws
// or if allocators are unequal.
template <class H, class P, class A, class G, class K>
void hash_table<H, P, A, G, K>
::move(hash_table& x)
{
// This can throw, but it only affects the function objects
// that aren't in use so it is strongly exception safe, via.
// double buffering.
functions_ptr new_func_this = this->buffer_functions(x);
if(this->node_alloc() == x.node_alloc()) {
this->manager::move(x); // no throw
}
else {
// Create new buckets in separate HASH_TABLE_DATA objects
// which will clean up if anything throws an exception.
// (all can throw, but with no effect as these are new objects).
manager new_this(*this);
new_this.create_buckets(next_prime(x.min_buckets_for_size(x.size_)));
x.copy_buckets_to(new_this);
// Start updating the data here, no throw from now on.
this->manager::move(new_this);
}
// We've made it, the rest is no throw.
this->mlf_ = x.mlf_;
this->set_functions(new_func_this);
this->calculate_max_load();
}
////////////////////////////////////////////////////////////////////////////
// Reserve & Rehash
// basic exception safety
template <class H, class P, class A, class G, class K>
bool hash_table<H, P, A, G, K>
::reserve(std::size_t n)
{
bool need_to_reserve = n >= this->max_load_;
// throws - basic:
if (need_to_reserve) rehash_impl(this->min_buckets_for_size(n));
BOOST_ASSERT(n < this->max_load_ || n > max_size());
return need_to_reserve;
}
// basic exception safety
template <class H, class P, class A, class G, class K>
bool hash_table<H, P, A, G, K>
::reserve_for_insert(std::size_t n)
{
bool need_to_reserve = n >= this->max_load_;
// throws - basic:
if (need_to_reserve) {
std::size_t s = this->size_;
s = s + (s >> 1);
s = s > n ? s : n;
rehash_impl(this->min_buckets_for_size(s));
}
BOOST_ASSERT(n < this->max_load_ || n > max_size());
return need_to_reserve;
}
// if hash function throws, basic exception safety
// strong otherwise.
template <class H, class P, class A, class G, class K>
void hash_table<H, P, A, G, K>
::rehash(std::size_t n)
{
using namespace std;
// no throw:
std::size_t min_size = this->min_buckets_for_size(this->size_);
// basic/strong:
rehash_impl(min_size > n ? min_size : n);
BOOST_ASSERT((float) this->bucket_count() > (float) this->size_ / this->mlf_
&& this->bucket_count() >= n);
}
// if hash function throws, basic exception safety
// strong otherwise
template <class H, class P, class A, class G, class K>
void hash_table<H, P, A, G, K>
::rehash_impl(std::size_t n)
{
n = next_prime(n); // no throw
if (n == this->bucket_count()) // no throw
return;
manager new_buckets(*this); // throws, seperate
new_buckets.create_buckets(n); // throws, seperate
move_buckets_to(new_buckets); // basic/no throw
new_buckets.swap(*this); // no throw
this->calculate_max_load(); // no throw
}
////////////////////////////////////////////////////////////////////////////
// move_buckets_to & copy_buckets_to
// move_buckets_to
//
// if the hash function throws, basic excpetion safety
// no throw otherwise
template <class H, class P, class A, class G, class K>
void hash_table<H, P, A, G, K>
::move_buckets_to(manager& dst)
{
BOOST_ASSERT(this->node_alloc() == dst.node_alloc());
BOOST_ASSERT(this->buckets_ && dst.buckets_);
hasher const& hf = this->hash_function();
bucket_ptr end = this->buckets_end();
for(; this->cached_begin_bucket_ != end; ++this->cached_begin_bucket_) {
bucket_ptr src_bucket = this->cached_begin_bucket_;
while(src_bucket->next_) {
// Move the first group of equivalent nodes in
// src_bucket to dst.
// This next line throws iff the hash function throws.
bucket_ptr dst_bucket = dst.bucket_ptr_from_hash(
hf(extractor::extract(node::get_value(src_bucket->next_))));
node_ptr n = src_bucket->next_;
std::size_t count = this->unlink_group(&src_bucket->next_);
dst.link_group(n, dst_bucket, count);
}
}
}
// copy_buckets_to
//
// basic excpetion safety. If an exception is thrown this will
// leave dst partially filled.
template <class H, class P, class A, class G, class K>
void hash_table<H, P, A, G, K>
::copy_buckets_to(manager& dst) const
{
BOOST_ASSERT(this->buckets_ && dst.buckets_);
hasher const& hf = this->hash_function();
bucket_ptr end = this->buckets_end();
hash_node_constructor<A, G> a(dst);
// no throw:
for(bucket_ptr i = this->cached_begin_bucket_; i != end; ++i) {
// no throw:
for(node_ptr it = i->next_; it;) {
// hash function can throw.
bucket_ptr dst_bucket = dst.bucket_ptr_from_hash(
hf(extractor::extract(node::get_value(it))));
// throws, strong
node_ptr group_end = node::next_group(it);
a.construct(node::get_value(it));
node_ptr n = a.release();
dst.link_node_in_bucket(n, dst_bucket);
for(it = next_node(it); it != group_end; it = next_node(it)) {
a.construct(node::get_value(it));
dst.link_node(a.release(), n);
}
}
}
}
////////////////////////////////////////////////////////////////////////////
// Misc. key methods
// strong exception safety
template <class H, class P, class A, class G, class K>
std::size_t hash_table<H, P, A, G, K>
::erase_key(key_type const& k)
{
// No side effects in initial section
bucket_ptr bucket = this->get_bucket(this->bucket_index(k));
node_ptr* it = find_for_erase(bucket, k);
// No throw.
return *it ? this->erase_group(it, bucket) : 0;
}
// count
//
// strong exception safety, no side effects
template <class H, class P, class A, class G, class K>
std::size_t hash_table<H, P, A, G, K>
::count(key_type const& k) const
{
if(!this->size_) return 0;
node_ptr it = find_iterator(k); // throws, strong
return BOOST_UNORDERED_BORLAND_BOOL(it) ? node::group_count(it) : 0;
}
// find
//
// strong exception safety, no side effects
template <class H, class P, class A, class G, class K>
BOOST_DEDUCED_TYPENAME hash_table<H, P, A, G, K>::iterator_base
hash_table<H, P, A, G, K>
::find(key_type const& k) const
{
if(!this->size_) return this->end();
bucket_ptr bucket = this->get_bucket(this->bucket_index(k));
node_ptr it = find_iterator(bucket, k);
if (BOOST_UNORDERED_BORLAND_BOOL(it))
return iterator_base(bucket, it);
else
return this->end();
}
template <class H, class P, class A, class G, class K>
BOOST_DEDUCED_TYPENAME A::value_type&
hash_table<H, P, A, G, K>
::at(key_type const& k) const
{
if(!this->size_)
throw std::out_of_range("Unable to find key in unordered_map.");
bucket_ptr bucket = this->get_bucket(this->bucket_index(k));
node_ptr it = find_iterator(bucket, k);
if (BOOST_UNORDERED_BORLAND_BOOL(it))
return node::get_value(it);
else
throw std::out_of_range("Unable to find key in unordered_map.");
}
// equal_range
//
// strong exception safety, no side effects
template <class H, class P, class A, class G, class K>
std::pair<
BOOST_DEDUCED_TYPENAME hash_table<H, P, A, G, K>::iterator_base,
BOOST_DEDUCED_TYPENAME hash_table<H, P, A, G, K>::iterator_base
>
hash_table<H, P, A, G, K>
::equal_range(key_type const& k) const
{
if(!this->size_)
return std::pair<iterator_base, iterator_base>(this->end(), this->end());
bucket_ptr bucket = this->get_bucket(this->bucket_index(k));
node_ptr it = find_iterator(bucket, k);
if (BOOST_UNORDERED_BORLAND_BOOL(it)) {
iterator_base first(iterator_base(bucket, it));
iterator_base second(first);
second.increment(node::next_group(second.node_));
return std::pair<iterator_base, iterator_base>(first, second);
}
else {
return std::pair<iterator_base, iterator_base>(this->end(), this->end());
}
}
}}
#endif

View File

@ -0,0 +1,333 @@
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
// Copyright (C) 2005-2009 Daniel James
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_UNORDERED_DETAIL_UTIL_HPP_INCLUDED
#define BOOST_UNORDERED_DETAIL_UTIL_HPP_INCLUDED
#include <cstddef>
#include <utility>
#include <algorithm>
#include <boost/limits.hpp>
#include <boost/iterator/iterator_categories.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/unordered/detail/manager.hpp>
#if !defined(BOOST_UNORDERED_STD_FORWARD)
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#define BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
BOOST_PP_ENUM_PARAMS_Z(z, n, class Arg)
#define BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, Arg, const& arg)
#define BOOST_UNORDERED_CALL_PARAMS(z, n) \
BOOST_PP_ENUM_PARAMS_Z(z, n, arg)
#endif
namespace boost { namespace unordered_detail {
////////////////////////////////////////////////////////////////////////////
// convert double to std::size_t
inline std::size_t double_to_size_t(double f)
{
return f >= static_cast<double>((std::numeric_limits<std::size_t>::max)()) ?
(std::numeric_limits<std::size_t>::max)() :
static_cast<std::size_t>(f);
}
////////////////////////////////////////////////////////////////////////////
// primes
template<class T> struct prime_list_template
{
static std::size_t const value[];
static std::ptrdiff_t const length;
};
#define BOOST_UNORDERED_PRIMES \
(5ul)(11ul)(17ul)(29ul)(37ul)(53ul)(67ul)(79ul) \
(97ul)(131ul)(193ul)(257ul)(389ul)(521ul)(769ul) \
(1031ul)(1543ul)(2053ul)(3079ul)(6151ul)(12289ul)(24593ul) \
(49157ul)(98317ul)(196613ul)(393241ul)(786433ul) \
(1572869ul)(3145739ul)(6291469ul)(12582917ul)(25165843ul) \
(50331653ul)(100663319ul)(201326611ul)(402653189ul)(805306457ul) \
(1610612741ul)(3221225473ul)(4294967291ul)
template<class T>
std::size_t const prime_list_template<T>::value[] = {
BOOST_PP_SEQ_ENUM(BOOST_UNORDERED_PRIMES)
};
template<class T>
std::ptrdiff_t const prime_list_template<T>::length
= BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES);
#undef BOOST_UNORDERED_PRIMES
typedef prime_list_template<std::size_t> prime_list;
// no throw
inline std::size_t next_prime(std::size_t n) {
std::size_t const* const prime_list_begin = prime_list::value;
std::size_t const* const prime_list_end = prime_list_begin +
prime_list::length;
std::size_t const* bound =
std::lower_bound(prime_list_begin, prime_list_end, n);
if(bound == prime_list_end)
bound--;
return *bound;
}
// no throw
inline std::size_t prev_prime(std::size_t n) {
std::size_t const* const prime_list_begin = prime_list::value;
std::size_t const* const prime_list_end = prime_list_begin +
prime_list::length;
std::size_t const* bound =
std::upper_bound(prime_list_begin,prime_list_end, n);
if(bound != prime_list_begin)
bound--;
return *bound;
}
////////////////////////////////////////////////////////////////////////////
// pair_cast - because some libraries don't have the full pair constructors.
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));
}
////////////////////////////////////////////////////////////////////////////
// insert_size/initial_size
#if !defined(BOOST_NO_STD_DISTANCE)
using ::std::distance;
#else
template <class ForwardIterator>
inline std::size_t distance(ForwardIterator i, ForwardIterator j) {
std::size_t x;
std::distance(i, j, x);
return x;
}
#endif
template <class I>
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)
{
return 1;
}
template <class I>
inline std::size_t insert_size(I i, I j)
{
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 n = boost::unordered_detail::default_initial_bucket_count)
{
return (std::max)(static_cast<std::size_t>(insert_size(i, j)) + 1, n);
}
////////////////////////////////////////////////////////////////////////////
// Node Constructors
#if defined(BOOST_UNORDERED_STD_FORWARD)
template <class T, class... Args>
inline void construct_impl(T*, void* address, Args&&... args)
{
new(address) T(std::forward<Args>(args)...);
}
#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)
)
{
new(address) std::pair<First, Second>(k,
Second(arg0, std::forward<Args>(args)...);
}
#endif
#else
#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, n, _) \
template < \
class T, \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
inline void construct_impl( \
T*, void* address, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
new(address) T( \
BOOST_UNORDERED_CALL_PARAMS(z, n)); \
} \
\
template <class First, class Second, class Key, \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
inline void construct_impl( \
std::pair<First, Second>*, void* address, \
Key const& k, BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
{ \
new(address) std::pair<First, Second>(k, \
Second(BOOST_UNORDERED_CALL_PARAMS(z, n))); \
}
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
{
typedef hash_table_manager<Alloc, Grouped> manager;
typedef BOOST_DEDUCED_TYPENAME manager::node node;
typedef BOOST_DEDUCED_TYPENAME manager::real_node_ptr real_node_ptr;
typedef BOOST_DEDUCED_TYPENAME manager::value_type value_type;
manager& manager_;
real_node_ptr node_;
bool node_constructed_;
bool value_constructed_;
public:
hash_node_constructor(manager& m) :
manager_(m),
node_(),
node_constructed_(false),
value_constructed_(false)
{
}
~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, n, _) \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
void construct( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
construct_preamble(); \
construct_impl( \
(value_type*) 0, node_->address(), \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
); \
value_constructed_ = true; \
}
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
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;
}
real_node_ptr get() const
{
BOOST_ASSERT(node_);
return node_;
}
// no throw
BOOST_DEDUCED_TYPENAME manager::node_ptr release()
{
real_node_ptr p = node_;
node_ = real_node_ptr();
// node_ptr cast
return manager_.bucket_alloc().address(*p);
}
private:
hash_node_constructor(hash_node_constructor const&);
hash_node_constructor& operator=(hash_node_constructor const&);
};
// hash_node_constructor
template <class Alloc, class Grouped>
hash_node_constructor<Alloc, Grouped>::~hash_node_constructor()
{
if (node_) {
if (value_constructed_) {
BOOST_UNORDERED_DESTRUCT(&node_->value(), value_type);
}
if (node_constructed_)
manager_.node_alloc().destroy(node_);
manager_.node_alloc().deallocate(node_, 1);
}
}
template <class Alloc, class Grouped>
void hash_node_constructor<Alloc, Grouped>::construct_preamble()
{
if(!node_) {
node_constructed_ = false;
value_constructed_ = false;
node_ = manager_.node_alloc().allocate(1);
manager_.node_alloc().construct(node_, node());
node_constructed_ = true;
}
else {
BOOST_ASSERT(node_constructed_ && value_constructed_);
BOOST_UNORDERED_DESTRUCT(&node_->value(), value_type);
value_constructed_ = false;
}
}
}}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -15,7 +15,8 @@
#include <boost/unordered/unordered_set_fwd.hpp>
#include <boost/functional/hash.hpp>
#include <boost/unordered/detail/hash_table.hpp>
#include <boost/unordered/detail/allocator_helpers.hpp>
#include <boost/unordered/detail/insert.hpp>
#if !defined(BOOST_HAS_RVALUE_REFS)
#include <boost/unordered/detail/move.hpp>
@ -39,37 +40,56 @@ namespace boost
template <class Value, class Hash, class Pred, class Alloc>
class unordered_set
{
#if BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
public:
#endif
typedef boost::unordered_detail::hash_types_unique_keys<
Value, Value, Hash, Pred, Alloc
> implementation;
BOOST_DEDUCED_TYPENAME implementation::hash_table base;
public:
// types
typedef Value key_type;
typedef Value value_type;
typedef Hash hasher;
typedef Pred key_equal;
typedef Alloc allocator_type;
typedef BOOST_DEDUCED_TYPENAME allocator_type::pointer pointer;
typedef BOOST_DEDUCED_TYPENAME allocator_type::const_pointer const_pointer;
typedef BOOST_DEDUCED_TYPENAME allocator_type::reference reference;
typedef BOOST_DEDUCED_TYPENAME allocator_type::const_reference const_reference;
typedef BOOST_DEDUCED_TYPENAME implementation::size_type size_type;
typedef BOOST_DEDUCED_TYPENAME implementation::difference_type difference_type;
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
private:
#endif
typedef BOOST_DEDUCED_TYPENAME implementation::const_iterator iterator;
typedef BOOST_DEDUCED_TYPENAME implementation::const_iterator const_iterator;
typedef BOOST_DEDUCED_TYPENAME implementation::const_local_iterator local_iterator;
typedef BOOST_DEDUCED_TYPENAME implementation::const_local_iterator const_local_iterator;
typedef BOOST_DEDUCED_TYPENAME
boost::unordered_detail::rebind_wrap<allocator_type, value_type>::type
value_allocator;
typedef boost::unordered_detail::hash_unique_table<Hash, Pred, value_allocator,
boost::unordered_detail::set_extractor> table;
typedef BOOST_DEDUCED_TYPENAME table::iterator_base iterator_base;
public:
typedef BOOST_DEDUCED_TYPENAME value_allocator::pointer pointer;
typedef BOOST_DEDUCED_TYPENAME value_allocator::const_pointer const_pointer;
typedef BOOST_DEDUCED_TYPENAME value_allocator::reference reference;
typedef BOOST_DEDUCED_TYPENAME value_allocator::const_reference const_reference;
typedef BOOST_DEDUCED_TYPENAME std::size_t size_type;
typedef BOOST_DEDUCED_TYPENAME std::ptrdiff_t difference_type;
typedef boost::unordered_detail::hash_const_local_iterator<
value_allocator, boost::unordered_detail::ungrouped> const_local_iterator;
typedef boost::unordered_detail::hash_const_iterator<
value_allocator, boost::unordered_detail::ungrouped> const_iterator;
typedef const_local_iterator local_iterator;
typedef const_iterator iterator;
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
private:
#endif
table table_;
BOOST_DEDUCED_TYPENAME table::iterator_base const&
get(const_iterator const& it)
{
return boost::unordered_detail::iterator_access::get(it);
}
public:
// construct/destroy/copy
@ -78,34 +98,35 @@ namespace boost
const hasher &hf = hasher(),
const key_equal &eql = key_equal(),
const allocator_type &a = allocator_type())
: base(n, hf, eql, a)
: table_(n, hf, eql, a)
{
}
explicit unordered_set(allocator_type const& a)
: base(boost::unordered_detail::default_initial_bucket_count,
: table_(boost::unordered_detail::default_initial_bucket_count,
hasher(), key_equal(), a)
{
}
unordered_set(unordered_set const& other, allocator_type const& a)
: base(other.base, a)
: table_(other.table_, a)
{
}
template <class InputIterator>
unordered_set(InputIterator f, InputIterator l)
: base(f, l, boost::unordered_detail::default_initial_bucket_count,
hasher(), key_equal(), allocator_type())
: table_(boost::unordered_detail::initial_size(f, l), hasher(), key_equal(), allocator_type())
{
table_.insert_range(f, l);
}
template <class InputIterator>
unordered_set(InputIterator f, InputIterator l, size_type n,
const hasher &hf = hasher(),
const key_equal &eql = key_equal())
: base(f, l, n, hf, eql, allocator_type())
: table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, allocator_type())
{
table_.insert_range(f, l);
}
template <class InputIterator>
@ -113,38 +134,39 @@ namespace boost
const hasher &hf,
const key_equal &eql,
const allocator_type &a)
: base(f, l, n, hf, eql, a)
: table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, a)
{
table_.insert_range(f, l);
}
~unordered_set() {}
#if defined(BOOST_HAS_RVALUE_REFS)
unordered_set(unordered_set&& other)
: base(other.base, boost::unordered_detail::move_tag())
: table_(other.table_, boost::unordered_detail::move_tag())
{
}
unordered_set(unordered_set&& other, allocator_type const& a)
: base(other.base, a, boost::unordered_detail::move_tag())
: table_(other.table_, a, boost::unordered_detail::move_tag())
{
}
unordered_set& operator=(unordered_set&& x)
{
base.move(x.base);
table_.move(x.table_);
return *this;
}
#else
unordered_set(boost::unordered_detail::move_from<unordered_set<Value, Hash, Pred, Alloc> > other)
: base(other.source.base, boost::unordered_detail::move_tag())
: table_(other.source.table_, boost::unordered_detail::move_tag())
{
}
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593)
unordered_set& operator=(unordered_set x)
{
base.move(x.base);
table_.move(x.table_);
return *this;
}
#endif
@ -156,80 +178,71 @@ namespace boost
const hasher &hf = hasher(),
const key_equal &eql = key_equal(),
const allocator_type &a = allocator_type())
: base(list.begin(), list.end(), n, hf, eql, a)
: table_(boost::unordered_detail::initial_size(list.begin(), list.end(), n), hf, eql, allocator_type())
{
table_.insert_range(list.begin(), list.end());
}
unordered_set& operator=(std::initializer_list<value_type> list)
{
base.data_.clear();
base.insert_range(list.begin(), list.end());
table_.clear();
table_.insert_range(list.begin(), list.end());
return *this;
}
#endif
private:
BOOST_DEDUCED_TYPENAME implementation::iterator_base const&
get(const_iterator const& it)
{
return boost::unordered_detail::iterator_access::get(it);
}
public:
allocator_type get_allocator() const
{
return base.get_allocator();
return table_.node_alloc();
}
// size and capacity
bool empty() const
{
return base.empty();
return table_.size_ == 0;
}
size_type size() const
{
return base.size();
return table_.size_;
}
size_type max_size() const
{
return base.max_size();
return table_.max_size();
}
// iterators
iterator begin()
{
return iterator(base.data_.begin());
return iterator(table_.begin());
}
const_iterator begin() const
{
return const_iterator(base.data_.begin());
return const_iterator(table_.begin());
}
iterator end()
{
return iterator(base.data_.end());
return iterator(table_.end());
}
const_iterator end() const
{
return const_iterator(base.data_.end());
return const_iterator(table_.end());
}
const_iterator cbegin() const
{
return const_iterator(base.data_.begin());
return const_iterator(table_.begin());
}
const_iterator cend() const
{
return const_iterator(base.data_.end());
return const_iterator(table_.end());
}
// modifiers
@ -239,26 +252,26 @@ namespace boost
std::pair<iterator, bool> emplace(Args&&... args)
{
return boost::unordered_detail::pair_cast<iterator, bool>(
base.emplace(std::forward<Args>(args)...));
table_.emplace(std::forward<Args>(args)...));
}
template <class... Args>
iterator emplace_hint(const_iterator hint, Args&&... args)
{
return iterator(
base.emplace_hint(get(hint), std::forward<Args>(args)...));
table_.emplace_hint(get(hint), std::forward<Args>(args)...));
}
#else
std::pair<iterator, bool> emplace(value_type const& v = value_type())
{
return boost::unordered_detail::pair_cast<iterator, bool>(
base.emplace(v));
table_.emplace(v));
}
iterator emplace_hint(const_iterator hint, value_type const& v = value_type())
{
return iterator(base.emplace_hint(get(hint), v));
return iterator(table_.emplace_hint(get(hint), v));
}
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
@ -270,7 +283,7 @@ namespace boost
) \
{ \
return boost::unordered_detail::pair_cast<iterator, bool>( \
base.emplace( \
table_.emplace( \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
)); \
} \
@ -282,7 +295,7 @@ namespace boost
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return iterator(base.emplace_hint(get(hint), \
return iterator(table_.emplace_hint(get(hint), \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
)); \
}
@ -297,148 +310,148 @@ namespace boost
std::pair<iterator, bool> insert(const value_type& obj)
{
return boost::unordered_detail::pair_cast<iterator, bool>(
base.emplace(obj));
table_.emplace(obj));
}
iterator insert(const_iterator hint, const value_type& obj)
{
return iterator(base.emplace_hint(get(hint), obj));
return iterator(table_.emplace_hint(get(hint), obj));
}
template <class InputIterator>
void insert(InputIterator first, InputIterator last)
{
base.insert_range(first, last);
table_.insert_range(first, last);
}
iterator erase(const_iterator position)
{
return iterator(base.data_.erase(get(position)));
return iterator(table_.erase(get(position)));
}
size_type erase(const key_type& k)
{
return base.erase_key(k);
return table_.erase_key(k);
}
iterator erase(const_iterator first, const_iterator last)
{
return iterator(base.data_.erase_range(get(first), get(last)));
return iterator(table_.erase_range(get(first), get(last)));
}
void clear()
{
base.data_.clear();
table_.clear();
}
void swap(unordered_set& other)
{
base.swap(other.base);
table_.swap(other.table_);
}
// observers
hasher hash_function() const
{
return base.hash_function();
return table_.hash_function();
}
key_equal key_eq() const
{
return base.key_eq();
return table_.key_eq();
}
// lookup
const_iterator find(const key_type& k) const
{
return const_iterator(base.find(k));
return const_iterator(table_.find(k));
}
size_type count(const key_type& k) const
{
return base.count(k);
return table_.count(k);
}
std::pair<const_iterator, const_iterator>
equal_range(const key_type& k) const
{
return boost::unordered_detail::pair_cast<const_iterator, const_iterator>(
base.equal_range(k));
table_.equal_range(k));
}
// bucket interface
size_type bucket_count() const
{
return base.bucket_count();
return table_.bucket_count();
}
size_type max_bucket_count() const
{
return base.max_bucket_count();
return table_.max_bucket_count();
}
size_type bucket_size(size_type n) const
{
return base.data_.bucket_size(n);
return table_.bucket_size(n);
}
size_type bucket(const key_type& k) const
{
return base.bucket(k);
return table_.bucket_index(k);
}
local_iterator begin(size_type n)
{
return local_iterator(base.data_.begin(n));
return local_iterator(table_.bucket_begin(n));
}
const_local_iterator begin(size_type n) const
{
return const_local_iterator(base.data_.begin(n));
return const_local_iterator(table_.bucket_begin(n));
}
local_iterator end(size_type n)
{
return local_iterator(base.data_.end(n));
return local_iterator(table_.bucket_end(n));
}
const_local_iterator end(size_type n) const
{
return const_local_iterator(base.data_.end(n));
return const_local_iterator(table_.bucket_end(n));
}
const_local_iterator cbegin(size_type n) const
{
return const_local_iterator(base.data_.begin(n));
return const_local_iterator(table_.bucket_begin(n));
}
const_local_iterator cend(size_type n) const
{
return const_local_iterator(base.data_.end(n));
return const_local_iterator(table_.bucket_end(n));
}
// hash policy
float load_factor() const
{
return base.load_factor();
return table_.load_factor();
}
float max_load_factor() const
{
return base.max_load_factor();
return table_.mlf_;
}
void max_load_factor(float m)
{
base.max_load_factor(m);
table_.max_load_factor(m);
}
void rehash(size_type n)
{
base.rehash(n);
table_.rehash(n);
}
#if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
@ -454,14 +467,14 @@ namespace boost
inline bool operator==(unordered_set<T, H, P, A> const& m1,
unordered_set<T, H, P, A> const& m2)
{
return boost::unordered_detail::equals(m1.base, m2.base);
return m1.table_.equals(m2.table_);
}
template <class T, class H, class P, class A>
inline bool operator!=(unordered_set<T, H, P, A> const& m1,
unordered_set<T, H, P, A> const& m2)
{
return !boost::unordered_detail::equals(m1.base, m2.base);
return !m1.table_.equals(m2.table_);
}
template <class T, class H, class P, class A>
@ -474,37 +487,55 @@ namespace boost
template <class Value, class Hash, class Pred, class Alloc>
class unordered_multiset
{
#if BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
public:
#endif
typedef boost::unordered_detail::hash_types_equivalent_keys<
Value, Value, Hash, Pred, Alloc
> implementation;
BOOST_DEDUCED_TYPENAME implementation::hash_table base;
public:
//types
typedef Value key_type;
typedef Value value_type;
typedef Hash hasher;
typedef Pred key_equal;
typedef Alloc allocator_type;
typedef BOOST_DEDUCED_TYPENAME allocator_type::pointer pointer;
typedef BOOST_DEDUCED_TYPENAME allocator_type::const_pointer const_pointer;
typedef BOOST_DEDUCED_TYPENAME allocator_type::reference reference;
typedef BOOST_DEDUCED_TYPENAME allocator_type::const_reference const_reference;
typedef BOOST_DEDUCED_TYPENAME implementation::size_type size_type;
typedef BOOST_DEDUCED_TYPENAME implementation::difference_type difference_type;
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
private:
#endif
typedef BOOST_DEDUCED_TYPENAME
boost::unordered_detail::rebind_wrap<allocator_type, value_type>::type
value_allocator;
typedef BOOST_DEDUCED_TYPENAME implementation::const_iterator iterator;
typedef BOOST_DEDUCED_TYPENAME implementation::const_iterator const_iterator;
typedef BOOST_DEDUCED_TYPENAME implementation::const_local_iterator local_iterator;
typedef BOOST_DEDUCED_TYPENAME implementation::const_local_iterator const_local_iterator;
typedef boost::unordered_detail::hash_equivalent_table<Hash, Pred, value_allocator,
boost::unordered_detail::set_extractor> table;
typedef BOOST_DEDUCED_TYPENAME table::iterator_base iterator_base;
public:
typedef BOOST_DEDUCED_TYPENAME value_allocator::pointer pointer;
typedef BOOST_DEDUCED_TYPENAME value_allocator::const_pointer const_pointer;
typedef BOOST_DEDUCED_TYPENAME value_allocator::reference reference;
typedef BOOST_DEDUCED_TYPENAME value_allocator::const_reference const_reference;
typedef BOOST_DEDUCED_TYPENAME std::size_t size_type;
typedef BOOST_DEDUCED_TYPENAME std::ptrdiff_t difference_type;
typedef boost::unordered_detail::hash_const_local_iterator<
value_allocator, boost::unordered_detail::grouped> const_local_iterator;
typedef boost::unordered_detail::hash_const_iterator<
value_allocator, boost::unordered_detail::grouped> const_iterator;
typedef const_local_iterator local_iterator;
typedef const_iterator iterator;
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0582)
private:
#endif
table table_;
BOOST_DEDUCED_TYPENAME table::iterator_base const&
get(const_iterator const& it)
{
return boost::unordered_detail::iterator_access::get(it);
}
public:
// construct/destroy/copy
@ -513,34 +544,35 @@ namespace boost
const hasher &hf = hasher(),
const key_equal &eql = key_equal(),
const allocator_type &a = allocator_type())
: base(n, hf, eql, a)
: table_(n, hf, eql, a)
{
}
explicit unordered_multiset(allocator_type const& a)
: base(boost::unordered_detail::default_initial_bucket_count,
: table_(boost::unordered_detail::default_initial_bucket_count,
hasher(), key_equal(), a)
{
}
unordered_multiset(unordered_multiset const& other, allocator_type const& a)
: base(other.base, a)
: table_(other.table_, a)
{
}
template <class InputIterator>
unordered_multiset(InputIterator f, InputIterator l)
: base(f, l, boost::unordered_detail::default_initial_bucket_count,
hasher(), key_equal(), allocator_type())
: table_(boost::unordered_detail::initial_size(f, l), hasher(), key_equal(), allocator_type())
{
table_.insert_range(f, l);
}
template <class InputIterator>
unordered_multiset(InputIterator f, InputIterator l, size_type n,
const hasher &hf = hasher(),
const key_equal &eql = key_equal())
: base(f, l, n, hf, eql, allocator_type())
: table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, allocator_type())
{
table_.insert_range(f, l);
}
template <class InputIterator>
@ -548,38 +580,39 @@ namespace boost
const hasher &hf,
const key_equal &eql,
const allocator_type &a)
: base(f, l, n, hf, eql, a)
: table_(boost::unordered_detail::initial_size(f, l, n), hf, eql, a)
{
table_.insert_range(f, l);
}
~unordered_multiset() {}
#if defined(BOOST_HAS_RVALUE_REFS)
unordered_multiset(unordered_multiset&& other)
: base(other.base, boost::unordered_detail::move_tag())
: table_(other.table_, boost::unordered_detail::move_tag())
{
}
unordered_multiset(unordered_multiset&& other, allocator_type const& a)
: base(other.base, a, boost::unordered_detail::move_tag())
: table_(other.table_, a, boost::unordered_detail::move_tag())
{
}
unordered_multiset& operator=(unordered_multiset&& x)
{
base.move(x.base);
table_.move(x.table_);
return *this;
}
#else
unordered_multiset(boost::unordered_detail::move_from<unordered_multiset<Value, Hash, Pred, Alloc> > other)
: base(other.source.base, boost::unordered_detail::move_tag())
: table_(other.source.table_, boost::unordered_detail::move_tag())
{
}
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x0593)
unordered_multiset& operator=(unordered_multiset x)
{
base.move(x.base);
table_.move(x.table_);
return *this;
}
#endif
@ -591,80 +624,71 @@ namespace boost
const hasher &hf = hasher(),
const key_equal &eql = key_equal(),
const allocator_type &a = allocator_type())
: base(list.begin(), list.end(), n, hf, eql, a)
: table_(boost::unordered_detail::initial_size(list.begin(), list.end(), n), hf, eql, allocator_type())
{
table_.insert_range(list.begin(), list.end());
}
unordered_multiset& operator=(std::initializer_list<value_type> list)
{
base.data_.clear();
base.insert_range(list.begin(), list.end());
table_.clear();
table_.insert_range(list.begin(), list.end());
return *this;
}
#endif
private:
BOOST_DEDUCED_TYPENAME implementation::iterator_base const&
get(const_iterator const& it)
{
return boost::unordered_detail::iterator_access::get(it);
}
public:
allocator_type get_allocator() const
{
return base.get_allocator();
return table_.node_alloc();
}
// size and capacity
bool empty() const
{
return base.empty();
return table_.size_ == 0;
}
size_type size() const
{
return base.size();
return table_.size_;
}
size_type max_size() const
{
return base.max_size();
return table_.max_size();
}
// iterators
iterator begin()
{
return iterator(base.data_.begin());
return iterator(table_.begin());
}
const_iterator begin() const
{
return const_iterator(base.data_.begin());
return const_iterator(table_.begin());
}
iterator end()
{
return iterator(base.data_.end());
return iterator(table_.end());
}
const_iterator end() const
{
return const_iterator(base.data_.end());
return const_iterator(table_.end());
}
const_iterator cbegin() const
{
return const_iterator(base.data_.begin());
return const_iterator(table_.begin());
}
const_iterator cend() const
{
return const_iterator(base.data_.end());
return const_iterator(table_.end());
}
// modifiers
@ -673,24 +697,24 @@ namespace boost
template <class... Args>
iterator emplace(Args&&... args)
{
return iterator(base.emplace(std::forward<Args>(args)...));
return iterator(table_.emplace(std::forward<Args>(args)...));
}
template <class... Args>
iterator emplace_hint(const_iterator hint, Args&&... args)
{
return iterator(base.emplace_hint(get(hint), std::forward<Args>(args)...));
return iterator(table_.emplace_hint(get(hint), std::forward<Args>(args)...));
}
#else
iterator emplace(value_type const& v = value_type())
{
return iterator(base.emplace(v));
return iterator(table_.emplace(v));
}
iterator emplace_hint(const_iterator hint, value_type const& v = value_type())
{
return iterator(base.emplace_hint(get(hint), v));
return iterator(table_.emplace_hint(get(hint), v));
}
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
@ -702,9 +726,7 @@ namespace boost
) \
{ \
return iterator( \
base.emplace( \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
)); \
table_.emplace(BOOST_UNORDERED_CALL_PARAMS(z, n))); \
} \
\
template < \
@ -714,7 +736,7 @@ namespace boost
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return iterator(base.emplace_hint(get(hint), \
return iterator(table_.emplace_hint(get(hint), \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
)); \
}
@ -728,148 +750,148 @@ namespace boost
iterator insert(const value_type& obj)
{
return iterator(base.emplace(obj));
return iterator(table_.emplace(obj));
}
iterator insert(const_iterator hint, const value_type& obj)
{
return iterator(base.emplace_hint(get(hint), obj));
return iterator(table_.emplace_hint(get(hint), obj));
}
template <class InputIterator>
void insert(InputIterator first, InputIterator last)
{
base.insert_range(first, last);
table_.insert_range(first, last);
}
iterator erase(const_iterator position)
{
return iterator(base.data_.erase(get(position)));
return iterator(table_.erase(get(position)));
}
size_type erase(const key_type& k)
{
return base.erase_key(k);
return table_.erase_key(k);
}
iterator erase(const_iterator first, const_iterator last)
{
return iterator(base.data_.erase_range(get(first), get(last)));
return iterator(table_.erase_range(get(first), get(last)));
}
void clear()
{
base.data_.clear();
table_.clear();
}
void swap(unordered_multiset& other)
{
base.swap(other.base);
table_.swap(other.table_);
}
// observers
hasher hash_function() const
{
return base.hash_function();
return table_.hash_function();
}
key_equal key_eq() const
{
return base.key_eq();
return table_.key_eq();
}
// lookup
const_iterator find(const key_type& k) const
{
return const_iterator(base.find(k));
return const_iterator(table_.find(k));
}
size_type count(const key_type& k) const
{
return base.count(k);
return table_.count(k);
}
std::pair<const_iterator, const_iterator>
equal_range(const key_type& k) const
{
return boost::unordered_detail::pair_cast<const_iterator, const_iterator>(
base.equal_range(k));
table_.equal_range(k));
}
// bucket interface
size_type bucket_count() const
{
return base.bucket_count();
return table_.bucket_count();
}
size_type max_bucket_count() const
{
return base.max_bucket_count();
return table_.max_bucket_count();
}
size_type bucket_size(size_type n) const
{
return base.data_.bucket_size(n);
return table_.bucket_size(n);
}
size_type bucket(const key_type& k) const
{
return base.bucket(k);
return table_.bucket_index(k);
}
local_iterator begin(size_type n)
{
return local_iterator(base.data_.begin(n));
return local_iterator(table_.bucket_begin(n));
}
const_local_iterator begin(size_type n) const
{
return const_local_iterator(base.data_.begin(n));
return const_local_iterator(table_.bucket_begin(n));
}
local_iterator end(size_type n)
{
return local_iterator(base.data_.end(n));
return local_iterator(table_.bucket_end(n));
}
const_local_iterator end(size_type n) const
{
return const_local_iterator(base.data_.end(n));
return const_local_iterator(table_.bucket_end(n));
}
const_local_iterator cbegin(size_type n) const
{
return const_local_iterator(base.data_.begin(n));
return const_local_iterator(table_.bucket_begin(n));
}
const_local_iterator cend(size_type n) const
{
return const_local_iterator(base.data_.end(n));
return const_local_iterator(table_.bucket_end(n));
}
// hash policy
float load_factor() const
{
return base.load_factor();
return table_.load_factor();
}
float max_load_factor() const
{
return base.max_load_factor();
return table_.mlf_;
}
void max_load_factor(float m)
{
base.max_load_factor(m);
table_.max_load_factor(m);
}
void rehash(size_type n)
{
base.rehash(n);
table_.rehash(n);
}
#if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
@ -885,14 +907,14 @@ namespace boost
inline bool operator==(unordered_multiset<T, H, P, A> const& m1,
unordered_multiset<T, H, P, A> const& m2)
{
return boost::unordered_detail::equals(m1.base, m2.base);
return m1.table_.equals(m2.table_);
}
template <class T, class H, class P, class A>
inline bool operator!=(unordered_multiset<T, H, P, A> const& m1,
unordered_multiset<T, H, P, A> const& m2)
{
return !boost::unordered_detail::equals(m1.base, m2.base);
return !m1.table_.equals(m2.table_);
}
template <class T, class H, class P, class A>

View File

@ -3,5 +3,7 @@
# 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)
import testing ;
build-project unordered ;
build-project exception ;

View File

@ -41,7 +41,7 @@ void copy_construct_tests1(T*, test::random_generator const& generator = test::d
T x(v.begin(), v.end());
T y(x);
test::unordered_equivalence_tester<T> equivalent(x);
equivalent(y);
BOOST_TEST(equivalent(y));
test::check_equivalent_keys(y);
}
@ -55,7 +55,7 @@ void copy_construct_tests1(T*, test::random_generator const& generator = test::d
x.max_load_factor(x.load_factor() / 4);
T y(x);
test::unordered_equivalence_tester<T> equivalent(x);
equivalent(y);
BOOST_TEST(equivalent(y));
// This isn't guaranteed:
BOOST_TEST(y.load_factor() < y.max_load_factor());
test::check_equivalent_keys(y);
@ -100,7 +100,7 @@ void copy_construct_tests2(T* ptr, test::random_generator const& generator = tes
T x(v.begin(), v.end(), 0, hf, eq, al);
T y(x);
test::unordered_equivalence_tester<T> equivalent(x);
equivalent(y);
BOOST_TEST(equivalent(y));
test::check_equivalent_keys(y);
BOOST_TEST(test::equivalent(y.get_allocator(), al));
}
@ -111,7 +111,7 @@ void copy_construct_tests2(T* ptr, test::random_generator const& generator = tes
T x(v.begin(), v.end(), 0, hf, eq, al);
T y(x, al2);
test::unordered_equivalence_tester<T> equivalent(x);
equivalent(y);
BOOST_TEST(equivalent(y));
test::check_equivalent_keys(y);
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
}

View File

@ -119,7 +119,7 @@ namespace move_tests
BOOST_TEST(y.max_load_factor() == 2.0); // Not necessarily required.
test::check_equivalent_keys(y);
}
/*
{
test::random_values<T> v(25, generator);
T y(create(v, count, hf, eq, al, 1.0), al);
@ -137,7 +137,7 @@ namespace move_tests
BOOST_TEST(y.max_load_factor() == 1.0); // Not necessarily required.
test::check_equivalent_keys(y);
}
}
*/ }
boost::unordered_set<test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_set;
boost::unordered_multiset<test::object, test::hash, test::equal_to, test::allocator<test::object> >* test_multiset;

View File

@ -60,6 +60,7 @@ void simple_test(X const& a)
X u;
X& r = u;
BOOST_TEST(&(r = r) == &r);
BOOST_TEST(r.empty());
BOOST_TEST(&(r = a) == &r);
BOOST_TEST(equivalent(r));
@ -91,7 +92,7 @@ UNORDERED_AUTO_TEST(simple_tests)
std::cout<<"Test unordered_set.\n";
boost::unordered_set<int> set;
simple_test(set);
set.insert(1); set.insert(2); set.insert(1456);
simple_test(set);