mirror of
https://github.com/boostorg/unordered.git
synced 2025-07-30 11:27:15 +02:00
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:
@ -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,10 +23,12 @@
|
||||
# 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>
|
||||
@ -39,89 +43,16 @@ namespace boost {
|
||||
};
|
||||
#endif
|
||||
|
||||
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1300)
|
||||
template <class T>
|
||||
inline void reset(T& x) { x = T(); }
|
||||
|
||||
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 Ptr>
|
||||
inline Ptr null_ptr() { Ptr x; reset(x); return x; }
|
||||
#endif
|
||||
|
||||
// Work around for Microsoft's ETI bug.
|
||||
|
||||
template <class Allocator> struct allocator_value_type
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME Allocator::value_type type;
|
||||
};
|
||||
|
||||
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)
|
||||
|
||||
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
|
||||
// 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 Allocator>
|
||||
struct allocator_array_constructor
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME allocator_pointer<Allocator>::type pointer;
|
||||
typedef BOOST_DEDUCED_TYPENAME Allocator::pointer pointer;
|
||||
|
||||
Allocator& alloc_;
|
||||
pointer ptr_;
|
||||
@ -131,10 +62,8 @@ namespace boost {
|
||||
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
|
||||
constructed_ = pointer();
|
||||
ptr_ = pointer();
|
||||
}
|
||||
|
||||
~allocator_array_constructor() {
|
||||
@ -165,15 +94,14 @@ namespace boost {
|
||||
pointer release()
|
||||
{
|
||||
pointer p(ptr_);
|
||||
unordered_detail::reset(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
|
||||
|
@ -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
|
156
include/boost/unordered/detail/extract_key.hpp
Normal file
156
include/boost/unordered/detail/extract_key.hpp
Normal 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
|
625
include/boost/unordered/detail/fwd.hpp
Normal file
625
include/boost/unordered/detail/fwd.hpp
Normal 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
|
@ -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
672
include/boost/unordered/detail/insert.hpp
Normal file
672
include/boost/unordered/detail/insert.hpp
Normal 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
|
270
include/boost/unordered/detail/manager.hpp
Normal file
270
include/boost/unordered/detail/manager.hpp
Normal 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
|
@ -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
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
|
265
include/boost/unordered/detail/node.hpp
Normal file
265
include/boost/unordered/detail/node.hpp
Normal 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
|
220
include/boost/unordered/detail/structure.hpp
Normal file
220
include/boost/unordered/detail/structure.hpp
Normal 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
|
561
include/boost/unordered/detail/table.hpp
Normal file
561
include/boost/unordered/detail/table.hpp
Normal 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
|
333
include/boost/unordered/detail/util.hpp
Normal file
333
include/boost/unordered/detail/util.hpp
Normal 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
@ -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>
|
||||
|
@ -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 ;
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
|
Reference in New Issue
Block a user