forked from boostorg/unordered
Support node_handle
This commit is contained in:
@@ -3800,6 +3800,46 @@ struct table_impl : boost::unordered::detail::table<Types>
|
||||
}
|
||||
}
|
||||
|
||||
template <typename NodeType, typename InsertReturnType>
|
||||
void move_insert_node_type(NodeType& np, InsertReturnType& result)
|
||||
{
|
||||
if (np) {
|
||||
const_key_type& k = this->get_key(np.ptr_->value());
|
||||
std::size_t key_hash = this->hash(k);
|
||||
node_pointer pos = this->find_node(key_hash, k);
|
||||
|
||||
if (pos) {
|
||||
result.node = boost::move(np);
|
||||
result.position = iterator(pos);
|
||||
} else {
|
||||
this->reserve_for_insert(this->size_ + 1);
|
||||
result.position = iterator(this->add_node(np.ptr_, key_hash));
|
||||
result.inserted = true;
|
||||
np.ptr_ = node_pointer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename NodeType>
|
||||
iterator move_insert_node_type_with_hint(c_iterator hint, NodeType& np)
|
||||
{
|
||||
if (!np) {
|
||||
return iterator();
|
||||
}
|
||||
const_key_type& k = this->get_key(np.ptr_->value());
|
||||
if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) {
|
||||
return iterator(hint.node_);
|
||||
}
|
||||
std::size_t key_hash = this->hash(k);
|
||||
node_pointer pos = this->find_node(key_hash, k);
|
||||
if (!pos) {
|
||||
this->reserve_for_insert(this->size_ + 1);
|
||||
pos = this->add_node(np.ptr_, key_hash);
|
||||
np.ptr_ = node_pointer();
|
||||
}
|
||||
return iterator(pos);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Insert range methods
|
||||
//
|
||||
@@ -3876,39 +3916,87 @@ struct table_impl : boost::unordered::detail::table<Types>
|
||||
} while (++i != j);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Extract
|
||||
|
||||
inline node_pointer extract_by_key(const_key_type& k)
|
||||
{
|
||||
if (!this->size_) {
|
||||
return node_pointer();
|
||||
}
|
||||
std::size_t key_hash = this->hash(k);
|
||||
std::size_t bucket_index = this->hash_to_bucket(key_hash);
|
||||
link_pointer prev = find_previous_node(k, key_hash, bucket_index);
|
||||
if (!prev) {
|
||||
return node_pointer();
|
||||
}
|
||||
node_pointer n = next_node(prev);
|
||||
prev->next_ = n->next_;
|
||||
--this->size_;
|
||||
this->fix_bucket(bucket_index, prev);
|
||||
n->next_ = link_pointer();
|
||||
return n;
|
||||
}
|
||||
|
||||
inline node_pointer extract_by_iterator(c_iterator i)
|
||||
{
|
||||
node_pointer n = i.node_;
|
||||
BOOST_ASSERT(n);
|
||||
std::size_t key_hash = n->hash_;
|
||||
std::size_t bucket_index = this->hash_to_bucket(key_hash);
|
||||
link_pointer prev = this->get_previous_start(bucket_index);
|
||||
while (prev->next_ != n) {
|
||||
prev = prev->next_;
|
||||
}
|
||||
prev->next_ = n->next_;
|
||||
--this->size_;
|
||||
this->fix_bucket(bucket_index, prev);
|
||||
n->next_ = link_pointer();
|
||||
return n;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Erase
|
||||
//
|
||||
// no throw
|
||||
|
||||
link_pointer find_previous_node(
|
||||
const_key_type& k, std::size_t key_hash, std::size_t bucket_index)
|
||||
{
|
||||
link_pointer prev = this->get_previous_start(bucket_index);
|
||||
if (!prev) {
|
||||
return prev;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (!prev->next_) {
|
||||
return link_pointer();
|
||||
}
|
||||
std::size_t node_hash = next_node(prev)->hash_;
|
||||
if (this->hash_to_bucket(node_hash) != bucket_index) {
|
||||
return link_pointer();
|
||||
}
|
||||
if (node_hash == key_hash &&
|
||||
this->key_eq()(k, this->get_key(next_node(prev)->value()))) {
|
||||
return prev;
|
||||
}
|
||||
prev = prev->next_;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t erase_key(const_key_type& k)
|
||||
{
|
||||
if (!this->size_)
|
||||
return 0;
|
||||
|
||||
std::size_t key_hash = this->hash(k);
|
||||
std::size_t bucket_index = this->hash_to_bucket(key_hash);
|
||||
link_pointer prev = this->get_previous_start(bucket_index);
|
||||
link_pointer prev = find_previous_node(k, key_hash, bucket_index);
|
||||
if (!prev)
|
||||
return 0;
|
||||
|
||||
for (;;) {
|
||||
if (!prev->next_)
|
||||
return 0;
|
||||
std::size_t node_hash = next_node(prev)->hash_;
|
||||
if (this->hash_to_bucket(node_hash) != bucket_index)
|
||||
return 0;
|
||||
if (node_hash == key_hash &&
|
||||
this->key_eq()(k, this->get_key(next_node(prev)->value())))
|
||||
break;
|
||||
prev = prev->next_;
|
||||
}
|
||||
|
||||
link_pointer end = next_node(prev)->next_;
|
||||
|
||||
std::size_t deleted_count = this->delete_nodes(prev, end);
|
||||
this->delete_nodes(prev, end);
|
||||
this->fix_bucket(bucket_index, prev);
|
||||
return deleted_count;
|
||||
return 1;
|
||||
}
|
||||
|
||||
iterator erase(c_iterator r)
|
||||
@@ -4459,6 +4547,45 @@ struct grouped_table_impl : boost::unordered::detail::table<Types>
|
||||
this->add_node(a.release(), key_hash, position);
|
||||
}
|
||||
|
||||
template <typename NodeType> iterator move_insert_node_type(NodeType& np)
|
||||
{
|
||||
iterator result;
|
||||
|
||||
if (np) {
|
||||
const_key_type& k = this->get_key(np.ptr_->value());
|
||||
std::size_t key_hash = this->hash(k);
|
||||
node_pointer pos = this->find_node(key_hash, k);
|
||||
this->reserve_for_insert(this->size_ + 1);
|
||||
result = iterator(this->add_node(np.ptr_, key_hash, pos));
|
||||
np.ptr_ = node_pointer();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename NodeType>
|
||||
iterator move_insert_node_type_with_hint(c_iterator hint, NodeType& np)
|
||||
{
|
||||
iterator result;
|
||||
|
||||
if (np) {
|
||||
const_key_type& k = this->get_key(np.ptr_->value());
|
||||
|
||||
if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) {
|
||||
this->reserve_for_insert(this->size_ + 1);
|
||||
result = iterator(this->add_using_hint(np.ptr_, hint.node_));
|
||||
} else {
|
||||
std::size_t key_hash = this->hash(k);
|
||||
node_pointer pos = this->find_node(key_hash, k);
|
||||
this->reserve_for_insert(this->size_ + 1);
|
||||
result = iterator(this->add_node(np.ptr_, key_hash, pos));
|
||||
}
|
||||
np.ptr_ = node_pointer();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Insert range methods
|
||||
|
||||
@@ -4499,11 +4626,95 @@ struct grouped_table_impl : boost::unordered::detail::table<Types>
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Extract
|
||||
|
||||
inline node_pointer extract_by_key(const_key_type& k)
|
||||
{
|
||||
if (!this->size_) {
|
||||
return node_pointer();
|
||||
}
|
||||
std::size_t key_hash = this->hash(k);
|
||||
std::size_t bucket_index = this->hash_to_bucket(key_hash);
|
||||
link_pointer prev = find_previous_node(k, key_hash, bucket_index);
|
||||
if (!prev) {
|
||||
return node_pointer();
|
||||
}
|
||||
node_pointer n = next_node(prev);
|
||||
|
||||
if (n->group_prev_ != n) {
|
||||
node_pointer next = next_node(n);
|
||||
next->group_prev_ = n->group_prev_;
|
||||
n->group_prev_ = n;
|
||||
}
|
||||
|
||||
prev->next_ = n->next_;
|
||||
--this->size_;
|
||||
this->fix_bucket(bucket_index, prev);
|
||||
n->next_ = link_pointer();
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
inline node_pointer extract_by_iterator(c_iterator n)
|
||||
{
|
||||
node_pointer i = n.node_;
|
||||
BOOST_ASSERT(i);
|
||||
node_pointer j(next_node(i));
|
||||
std::size_t bucket_index = this->hash_to_bucket(i->hash_);
|
||||
// Split the groups containing 'i' and 'j'.
|
||||
// And get the pointer to the node before i while
|
||||
// we're at it.
|
||||
link_pointer prev = split_groups(i, j);
|
||||
|
||||
// If we don't have a 'prev' it means that i is at the
|
||||
// beginning of a block, so search through the blocks in the
|
||||
// same bucket.
|
||||
if (!prev) {
|
||||
prev = this->get_previous_start(bucket_index);
|
||||
while (prev->next_ != i) {
|
||||
prev = next_node(prev)->group_prev_;
|
||||
}
|
||||
}
|
||||
|
||||
prev->next_ = i->next_;
|
||||
--this->size_;
|
||||
this->fix_bucket(bucket_index, prev);
|
||||
i->next_ = link_pointer();
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Erase
|
||||
//
|
||||
// no throw
|
||||
|
||||
link_pointer find_previous_node(
|
||||
const_key_type& k, std::size_t key_hash, std::size_t bucket_index)
|
||||
{
|
||||
link_pointer prev = this->get_previous_start(bucket_index);
|
||||
if (!prev) {
|
||||
return prev;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (!prev->next_) {
|
||||
return link_pointer();
|
||||
}
|
||||
node_pointer first_node = next_node(prev);
|
||||
std::size_t node_hash = first_node->hash_;
|
||||
if (this->hash_to_bucket(node_hash) != bucket_index) {
|
||||
return link_pointer();
|
||||
}
|
||||
if (node_hash == key_hash &&
|
||||
this->key_eq()(k, this->get_key(first_node->value()))) {
|
||||
return prev;
|
||||
}
|
||||
prev = first_node->group_prev_;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t erase_key(const_key_type& k)
|
||||
{
|
||||
if (!this->size_)
|
||||
@@ -4511,25 +4722,11 @@ struct grouped_table_impl : boost::unordered::detail::table<Types>
|
||||
|
||||
std::size_t key_hash = this->hash(k);
|
||||
std::size_t bucket_index = this->hash_to_bucket(key_hash);
|
||||
link_pointer prev = this->get_previous_start(bucket_index);
|
||||
link_pointer prev = find_previous_node(k, key_hash, bucket_index);
|
||||
if (!prev)
|
||||
return 0;
|
||||
|
||||
node_pointer first_node;
|
||||
|
||||
for (;;) {
|
||||
if (!prev->next_)
|
||||
return 0;
|
||||
first_node = next_node(prev);
|
||||
std::size_t node_hash = first_node->hash_;
|
||||
if (this->hash_to_bucket(node_hash) != bucket_index)
|
||||
return 0;
|
||||
if (node_hash == key_hash &&
|
||||
this->key_eq()(k, this->get_key(first_node->value())))
|
||||
break;
|
||||
prev = first_node->group_prev_;
|
||||
}
|
||||
|
||||
node_pointer first_node = next_node(prev);
|
||||
link_pointer end = first_node->group_prev_->next_;
|
||||
|
||||
std::size_t deleted_count = this->delete_nodes(prev, end);
|
||||
|
||||
@@ -39,6 +39,10 @@ template <typename A, typename K, typename M, typename H, typename P> struct map
|
||||
l_iterator;
|
||||
typedef boost::unordered::iterator_detail::cl_iterator<node, policy>
|
||||
cl_iterator;
|
||||
|
||||
typedef boost::unordered::node_handle_map<node, K, M, A> node_type;
|
||||
typedef boost::unordered::insert_return_type_map<node, K, M, A>
|
||||
insert_return_type;
|
||||
};
|
||||
|
||||
template <typename A, typename K, typename M, typename H, typename P>
|
||||
@@ -72,6 +76,25 @@ struct multimap
|
||||
l_iterator;
|
||||
typedef boost::unordered::iterator_detail::cl_iterator<node, policy>
|
||||
cl_iterator;
|
||||
|
||||
typedef boost::unordered::node_handle_map<node, K, M, A> node_type;
|
||||
};
|
||||
|
||||
template <typename K, typename M, typename H, typename P, typename A>
|
||||
class instantiate_map
|
||||
{
|
||||
typedef boost::unordered_map<K, M, H, P, A> container;
|
||||
container x;
|
||||
typename container::node_type node_type;
|
||||
typename container::insert_return_type insert_return_type;
|
||||
};
|
||||
|
||||
template <typename K, typename M, typename H, typename P, typename A>
|
||||
class instantiate_multimap
|
||||
{
|
||||
typedef boost::unordered_multimap<K, M, H, P, A> container;
|
||||
container x;
|
||||
typename container::node_type node_type;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,10 @@ template <typename A, typename T, typename H, typename P> struct set
|
||||
l_iterator;
|
||||
typedef boost::unordered::iterator_detail::cl_iterator<node, policy>
|
||||
cl_iterator;
|
||||
|
||||
typedef boost::unordered::node_handle_set<node, T, A> node_type;
|
||||
typedef boost::unordered::insert_return_type_set<node, T, A>
|
||||
insert_return_type;
|
||||
};
|
||||
|
||||
template <typename A, typename T, typename H, typename P> struct multiset
|
||||
@@ -71,6 +75,24 @@ template <typename A, typename T, typename H, typename P> struct multiset
|
||||
l_iterator;
|
||||
typedef boost::unordered::iterator_detail::cl_iterator<node, policy>
|
||||
cl_iterator;
|
||||
|
||||
typedef boost::unordered::node_handle_set<node, T, A> node_type;
|
||||
};
|
||||
|
||||
template <typename T, typename H, typename P, typename A> class instantiate_set
|
||||
{
|
||||
typedef boost::unordered_set<T, H, P, A> container;
|
||||
container x;
|
||||
typename container::node_type node_type;
|
||||
typename container::insert_return_type insert_return_type;
|
||||
};
|
||||
|
||||
template <typename T, typename H, typename P, typename A>
|
||||
class instantiate_multiset
|
||||
{
|
||||
typedef boost::unordered_multiset<T, H, P, A> container;
|
||||
container x;
|
||||
typename container::node_type node_type;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/core/explicit_operator_bool.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/move/move.hpp>
|
||||
#include <boost/unordered/detail/map.hpp>
|
||||
#include <boost/unordered/unordered_map_fwd.hpp>
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#include <initializer_list>
|
||||
@@ -67,6 +67,8 @@ template <class K, class T, class H, class P, class A> class unordered_map
|
||||
typedef typename table::l_iterator local_iterator;
|
||||
typedef typename table::c_iterator const_iterator;
|
||||
typedef typename table::iterator iterator;
|
||||
typedef typename types::node_type node_type;
|
||||
typedef typename types::insert_return_type insert_return_type;
|
||||
|
||||
private:
|
||||
table table_;
|
||||
@@ -206,6 +208,19 @@ template <class K, class T, class H, class P, class A> class unordered_map
|
||||
|
||||
const_iterator cend() const BOOST_NOEXCEPT { return const_iterator(); }
|
||||
|
||||
// extract
|
||||
|
||||
node_type extract(const_iterator position)
|
||||
{
|
||||
return node_type(
|
||||
table_.extract_by_iterator(position), table_.node_alloc());
|
||||
}
|
||||
|
||||
node_type extract(const key_type& k)
|
||||
{
|
||||
return node_type(table_.extract_by_key(k), table_.node_alloc());
|
||||
}
|
||||
|
||||
// emplace
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
@@ -572,6 +587,27 @@ template <class K, class T, class H, class P, class A> class unordered_map
|
||||
void insert(std::initializer_list<value_type>);
|
||||
#endif
|
||||
|
||||
insert_return_type insert(BOOST_RV_REF(node_type) np)
|
||||
{
|
||||
insert_return_type result;
|
||||
table_.move_insert_node_type(np, result);
|
||||
return boost::move(result);
|
||||
}
|
||||
|
||||
iterator insert(const_iterator hint, BOOST_RV_REF(node_type) np)
|
||||
{
|
||||
return table_.move_insert_node_type_with_hint(hint, np);
|
||||
}
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
private:
|
||||
// Note: Use r-value node_type to insert.
|
||||
insert_return_type insert(node_type&);
|
||||
iterator insert(const_iterator, node_type& np);
|
||||
|
||||
public:
|
||||
#endif
|
||||
|
||||
iterator erase(const_iterator);
|
||||
size_type erase(const key_type&);
|
||||
iterator erase(const_iterator, const_iterator);
|
||||
@@ -703,6 +739,7 @@ template <class K, class T, class H, class P, class A> class unordered_multimap
|
||||
typedef typename table::l_iterator local_iterator;
|
||||
typedef typename table::c_iterator const_iterator;
|
||||
typedef typename table::iterator iterator;
|
||||
typedef typename types::node_type node_type;
|
||||
|
||||
private:
|
||||
table table_;
|
||||
@@ -843,6 +880,19 @@ template <class K, class T, class H, class P, class A> class unordered_multimap
|
||||
|
||||
const_iterator cend() const BOOST_NOEXCEPT { return const_iterator(); }
|
||||
|
||||
// extract
|
||||
|
||||
node_type extract(const_iterator position)
|
||||
{
|
||||
return node_type(
|
||||
table_.extract_by_iterator(position), table_.node_alloc());
|
||||
}
|
||||
|
||||
node_type extract(const key_type& k)
|
||||
{
|
||||
return node_type(table_.extract_by_key(k), table_.node_alloc());
|
||||
}
|
||||
|
||||
// emplace
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
@@ -977,6 +1027,25 @@ template <class K, class T, class H, class P, class A> class unordered_multimap
|
||||
void insert(std::initializer_list<value_type>);
|
||||
#endif
|
||||
|
||||
iterator insert(BOOST_RV_REF(node_type) np)
|
||||
{
|
||||
return table_.move_insert_node_type(np);
|
||||
}
|
||||
|
||||
iterator insert(const_iterator hint, BOOST_RV_REF(node_type) np)
|
||||
{
|
||||
return table_.move_insert_node_type_with_hint(hint, np);
|
||||
}
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
private:
|
||||
// Note: Use r-value node_type to insert.
|
||||
iterator insert(node_type&);
|
||||
iterator insert(const_iterator, node_type& np);
|
||||
|
||||
public:
|
||||
#endif
|
||||
|
||||
iterator erase(const_iterator);
|
||||
size_type erase(const key_type&);
|
||||
iterator erase(const_iterator, const_iterator);
|
||||
@@ -1816,6 +1885,199 @@ inline void swap(unordered_multimap<K, T, H, P, A>& m1,
|
||||
m1.swap(m2);
|
||||
}
|
||||
|
||||
template <typename N, class K, class T, class A> class node_handle_map
|
||||
{
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(node_handle_map)
|
||||
|
||||
template <typename Types>
|
||||
friend struct ::boost::unordered::detail::table_impl;
|
||||
template <typename Types>
|
||||
friend struct ::boost::unordered::detail::grouped_table_impl;
|
||||
|
||||
typedef typename boost::unordered::detail::rebind_wrap<A,
|
||||
std::pair<K const, T> >::type value_allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<value_allocator>
|
||||
value_allocator_traits;
|
||||
typedef N node;
|
||||
typedef typename boost::unordered::detail::rebind_wrap<A, node>::type
|
||||
node_allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<node_allocator>
|
||||
node_allocator_traits;
|
||||
typedef typename node_allocator_traits::pointer node_pointer;
|
||||
|
||||
public:
|
||||
typedef K key_type;
|
||||
typedef T mapped_type;
|
||||
typedef A allocator_type;
|
||||
|
||||
private:
|
||||
node_pointer ptr_;
|
||||
bool has_alloc_;
|
||||
boost::unordered::detail::value_base<value_allocator> alloc_;
|
||||
|
||||
public:
|
||||
BOOST_CONSTEXPR node_handle_map() BOOST_NOEXCEPT : ptr_(), has_alloc_(false)
|
||||
{
|
||||
}
|
||||
|
||||
/*BOOST_CONSTEXPR */ node_handle_map(
|
||||
node_pointer ptr, allocator_type const& a)
|
||||
: ptr_(ptr), has_alloc_(false)
|
||||
{
|
||||
if (ptr_) {
|
||||
new ((void*)&alloc_) value_allocator(a);
|
||||
has_alloc_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
~node_handle_map()
|
||||
{
|
||||
if (has_alloc_ && ptr_) {
|
||||
node_allocator node_alloc(alloc_.value());
|
||||
boost::unordered::detail::node_tmp<node_allocator> tmp(
|
||||
ptr_, node_alloc);
|
||||
}
|
||||
if (has_alloc_) {
|
||||
alloc_.value_ptr()->~value_allocator();
|
||||
}
|
||||
}
|
||||
|
||||
node_handle_map(BOOST_RV_REF(node_handle_map) n) BOOST_NOEXCEPT
|
||||
: ptr_(n.ptr_),
|
||||
has_alloc_(false)
|
||||
{
|
||||
if (n.has_alloc_) {
|
||||
new ((void*)&alloc_) value_allocator(boost::move(n.alloc_.value()));
|
||||
has_alloc_ = true;
|
||||
n.ptr_ = node_pointer();
|
||||
n.alloc_.value_ptr()->~value_allocator();
|
||||
n.has_alloc_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
node_handle_map& operator=(BOOST_RV_REF(node_handle_map) n)
|
||||
{
|
||||
BOOST_ASSERT(!has_alloc_ ||
|
||||
value_allocator_traits::
|
||||
propagate_on_container_move_assignment::value ||
|
||||
(n.has_alloc_ && alloc_.value() == n.alloc_.value()));
|
||||
|
||||
if (ptr_) {
|
||||
node_allocator node_alloc(alloc_.value());
|
||||
boost::unordered::detail::node_tmp<node_allocator> tmp(
|
||||
ptr_, node_alloc);
|
||||
ptr_ = node_pointer();
|
||||
}
|
||||
|
||||
if (has_alloc_) {
|
||||
alloc_.value_ptr()->~value_allocator();
|
||||
has_alloc_ = false;
|
||||
}
|
||||
|
||||
if (!has_alloc_ && n.has_alloc_) {
|
||||
move_allocator(n);
|
||||
}
|
||||
|
||||
ptr_ = n.ptr_;
|
||||
n.ptr_ = node_pointer();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
key_type& key() const { return const_cast<key_type&>(ptr_->value().first); }
|
||||
|
||||
mapped_type& mapped() const { return ptr_->value().second; }
|
||||
|
||||
allocator_type get_allocator() const { return alloc_.value(); }
|
||||
|
||||
BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
|
||||
|
||||
bool operator!() const BOOST_NOEXCEPT { return ptr_ ? 0 : 1; }
|
||||
|
||||
bool empty() const BOOST_NOEXCEPT { return ptr_ ? 0 : 1; }
|
||||
|
||||
void swap(node_handle_map& n) BOOST_NOEXCEPT_IF(
|
||||
value_allocator_traits::propagate_on_container_swap::value
|
||||
/* || value_allocator_traits::is_always_equal::value */)
|
||||
{
|
||||
if (!has_alloc_) {
|
||||
if (n.has_alloc_) {
|
||||
move_allocator(n);
|
||||
}
|
||||
} else if (!n.has_alloc_) {
|
||||
n.move_allocator(*this);
|
||||
} else {
|
||||
swap_impl(n, boost::unordered::detail::integral_constant<bool,
|
||||
value_allocator_traits::
|
||||
propagate_on_container_swap::value>());
|
||||
}
|
||||
boost::swap(ptr_, n.ptr_);
|
||||
}
|
||||
|
||||
private:
|
||||
void move_allocator(node_handle_map& n)
|
||||
{
|
||||
new ((void*)&alloc_) value_allocator(boost::move(n.alloc_.value()));
|
||||
n.alloc_.value_ptr()->~value_allocator();
|
||||
has_alloc_ = true;
|
||||
n.has_alloc_ = false;
|
||||
}
|
||||
|
||||
void swap_impl(node_handle_map&, boost::unordered::detail::false_type) {}
|
||||
|
||||
void swap_impl(node_handle_map& n, boost::unordered::detail::true_type)
|
||||
{
|
||||
boost::swap(alloc_, n.alloc_);
|
||||
}
|
||||
};
|
||||
|
||||
template <class N, class K, class T, class A>
|
||||
void swap(node_handle_map<N, K, T, A>& x, node_handle_map<N, K, T, A>& y)
|
||||
BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(x.swap(y)))
|
||||
{
|
||||
x.swap(y);
|
||||
}
|
||||
|
||||
template <class N, class K, class T, class A> struct insert_return_type_map
|
||||
{
|
||||
private:
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(insert_return_type_map)
|
||||
|
||||
typedef typename boost::unordered::detail::rebind_wrap<A,
|
||||
std::pair<K const, T> >::type value_allocator;
|
||||
typedef N node_;
|
||||
|
||||
public:
|
||||
bool inserted;
|
||||
boost::unordered::iterator_detail::iterator<node_> position;
|
||||
boost::unordered::node_handle_map<N, K, T, A> node;
|
||||
|
||||
insert_return_type_map() : inserted(false), position(), node() {}
|
||||
|
||||
insert_return_type_map(BOOST_RV_REF(insert_return_type_map)
|
||||
x) BOOST_NOEXCEPT : inserted(x.inserted),
|
||||
position(x.position),
|
||||
node(boost::move(x.node))
|
||||
{
|
||||
}
|
||||
|
||||
insert_return_type_map& operator=(BOOST_RV_REF(insert_return_type_map) x)
|
||||
{
|
||||
inserted = x.inserted;
|
||||
position = x.position;
|
||||
node = boost::move(x.node);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <class N, class K, class T, class A>
|
||||
void swap(insert_return_type_map<N, K, T, A>& x,
|
||||
insert_return_type_map<N, K, T, A>& y)
|
||||
{
|
||||
boost::swap(x.node, y.node);
|
||||
boost::swap(x.inserted, y.inserted);
|
||||
boost::swap(x.position, y.position);
|
||||
}
|
||||
} // namespace unordered
|
||||
} // namespace boost
|
||||
|
||||
|
||||
@@ -46,6 +46,9 @@ inline bool operator!=(unordered_multimap<K, T, H, P, A> const&,
|
||||
template <class K, class T, class H, class P, class A>
|
||||
inline void swap(
|
||||
unordered_multimap<K, T, H, P, A>&, unordered_multimap<K, T, H, P, A>&);
|
||||
|
||||
template <class N, class K, class T, class A> class node_handle_map;
|
||||
template <class N, class K, class T, class A> struct insert_return_type_map;
|
||||
}
|
||||
|
||||
using boost::unordered::unordered_map;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/core/explicit_operator_bool.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/move/move.hpp>
|
||||
#include <boost/unordered/detail/set.hpp>
|
||||
@@ -64,6 +65,8 @@ template <class T, class H, class P, class A> class unordered_set
|
||||
typedef typename table::l_iterator local_iterator;
|
||||
typedef typename table::c_iterator const_iterator;
|
||||
typedef typename table::iterator iterator;
|
||||
typedef typename types::node_type node_type;
|
||||
typedef typename types::insert_return_type insert_return_type;
|
||||
|
||||
private:
|
||||
table table_;
|
||||
@@ -203,6 +206,19 @@ template <class T, class H, class P, class A> class unordered_set
|
||||
|
||||
const_iterator cend() const BOOST_NOEXCEPT { return const_iterator(); }
|
||||
|
||||
// extract
|
||||
|
||||
node_type extract(const_iterator position)
|
||||
{
|
||||
return node_type(
|
||||
table_.extract_by_iterator(position), table_.node_alloc());
|
||||
}
|
||||
|
||||
node_type extract(const key_type& k)
|
||||
{
|
||||
return node_type(table_.extract_by_key(k), table_.node_alloc());
|
||||
}
|
||||
|
||||
// emplace
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
@@ -345,6 +361,27 @@ template <class T, class H, class P, class A> class unordered_set
|
||||
void insert(std::initializer_list<value_type>);
|
||||
#endif
|
||||
|
||||
insert_return_type insert(BOOST_RV_REF(node_type) np)
|
||||
{
|
||||
insert_return_type result;
|
||||
table_.move_insert_node_type(np, result);
|
||||
return boost::move(result);
|
||||
}
|
||||
|
||||
iterator insert(const_iterator hint, BOOST_RV_REF(node_type) np)
|
||||
{
|
||||
return table_.move_insert_node_type_with_hint(hint, np);
|
||||
}
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
private:
|
||||
// Note: Use r-value node_type to insert.
|
||||
insert_return_type insert(node_type&);
|
||||
iterator insert(const_iterator, node_type& np);
|
||||
|
||||
public:
|
||||
#endif
|
||||
|
||||
iterator erase(const_iterator);
|
||||
size_type erase(const key_type&);
|
||||
iterator erase(const_iterator, const_iterator);
|
||||
@@ -464,6 +501,7 @@ template <class T, class H, class P, class A> class unordered_multiset
|
||||
typedef typename table::l_iterator local_iterator;
|
||||
typedef typename table::c_iterator const_iterator;
|
||||
typedef typename table::iterator iterator;
|
||||
typedef typename types::node_type node_type;
|
||||
|
||||
private:
|
||||
table table_;
|
||||
@@ -604,6 +642,19 @@ template <class T, class H, class P, class A> class unordered_multiset
|
||||
|
||||
const_iterator cend() const BOOST_NOEXCEPT { return const_iterator(); }
|
||||
|
||||
// extract
|
||||
|
||||
node_type extract(const_iterator position)
|
||||
{
|
||||
return node_type(
|
||||
table_.extract_by_iterator(position), table_.node_alloc());
|
||||
}
|
||||
|
||||
node_type extract(const key_type& k)
|
||||
{
|
||||
return node_type(table_.extract_by_key(k), table_.node_alloc());
|
||||
}
|
||||
|
||||
// emplace
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
@@ -738,6 +789,25 @@ template <class T, class H, class P, class A> class unordered_multiset
|
||||
void insert(std::initializer_list<value_type>);
|
||||
#endif
|
||||
|
||||
iterator insert(BOOST_RV_REF(node_type) np)
|
||||
{
|
||||
return table_.move_insert_node_type(np);
|
||||
}
|
||||
|
||||
iterator insert(const_iterator hint, BOOST_RV_REF(node_type) np)
|
||||
{
|
||||
return table_.move_insert_node_type_with_hint(hint, np);
|
||||
}
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
private:
|
||||
// Note: Use r-value node_type to insert.
|
||||
iterator insert(node_type&);
|
||||
iterator insert(const_iterator, node_type& np);
|
||||
|
||||
public:
|
||||
#endif
|
||||
|
||||
iterator erase(const_iterator);
|
||||
size_type erase(const key_type&);
|
||||
iterator erase(const_iterator, const_iterator);
|
||||
@@ -1494,6 +1564,197 @@ inline void swap(
|
||||
#endif
|
||||
m1.swap(m2);
|
||||
}
|
||||
|
||||
template <typename N, typename T, typename A> class node_handle_set
|
||||
{
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(node_handle_set)
|
||||
|
||||
template <typename Types>
|
||||
friend struct ::boost::unordered::detail::table_impl;
|
||||
template <typename Types>
|
||||
friend struct ::boost::unordered::detail::grouped_table_impl;
|
||||
|
||||
typedef typename boost::unordered::detail::rebind_wrap<A, T>::type
|
||||
value_allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<value_allocator>
|
||||
value_allocator_traits;
|
||||
typedef N node;
|
||||
typedef typename boost::unordered::detail::rebind_wrap<A, node>::type
|
||||
node_allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<node_allocator>
|
||||
node_allocator_traits;
|
||||
typedef typename node_allocator_traits::pointer node_pointer;
|
||||
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef A allocator_type;
|
||||
|
||||
private:
|
||||
node_pointer ptr_;
|
||||
bool has_alloc_;
|
||||
boost::unordered::detail::value_base<value_allocator> alloc_;
|
||||
|
||||
public:
|
||||
BOOST_CONSTEXPR node_handle_set() BOOST_NOEXCEPT : ptr_(), has_alloc_(false)
|
||||
{
|
||||
}
|
||||
|
||||
/*BOOST_CONSTEXPR */ node_handle_set(
|
||||
node_pointer ptr, allocator_type const& a)
|
||||
: ptr_(ptr), has_alloc_(false)
|
||||
{
|
||||
if (ptr_) {
|
||||
new ((void*)&alloc_) value_allocator(a);
|
||||
has_alloc_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
~node_handle_set()
|
||||
{
|
||||
if (has_alloc_ && ptr_) {
|
||||
node_allocator node_alloc(alloc_.value());
|
||||
boost::unordered::detail::node_tmp<node_allocator> tmp(
|
||||
ptr_, node_alloc);
|
||||
}
|
||||
if (has_alloc_) {
|
||||
alloc_.value_ptr()->~value_allocator();
|
||||
}
|
||||
}
|
||||
|
||||
node_handle_set(BOOST_RV_REF(node_handle_set) n) BOOST_NOEXCEPT
|
||||
: ptr_(n.ptr_),
|
||||
has_alloc_(false)
|
||||
{
|
||||
if (n.has_alloc_) {
|
||||
new ((void*)&alloc_) value_allocator(boost::move(n.alloc_.value()));
|
||||
has_alloc_ = true;
|
||||
n.ptr_ = node_pointer();
|
||||
n.alloc_.value_ptr()->~value_allocator();
|
||||
n.has_alloc_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
node_handle_set& operator=(BOOST_RV_REF(node_handle_set) n)
|
||||
{
|
||||
BOOST_ASSERT(!has_alloc_ ||
|
||||
value_allocator_traits::
|
||||
propagate_on_container_move_assignment::value ||
|
||||
(n.has_alloc_ && alloc_.value() == n.alloc_.value()));
|
||||
|
||||
if (ptr_) {
|
||||
node_allocator node_alloc(alloc_.value());
|
||||
boost::unordered::detail::node_tmp<node_allocator> tmp(
|
||||
ptr_, node_alloc);
|
||||
ptr_ = node_pointer();
|
||||
}
|
||||
|
||||
if (has_alloc_) {
|
||||
alloc_.value_ptr()->~value_allocator();
|
||||
has_alloc_ = false;
|
||||
}
|
||||
|
||||
if (!has_alloc_ && n.has_alloc_) {
|
||||
move_allocator(n);
|
||||
}
|
||||
|
||||
ptr_ = n.ptr_;
|
||||
n.ptr_ = node_pointer();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
value_type& value() const { return ptr_->value(); }
|
||||
|
||||
allocator_type get_allocator() const { return alloc_.value(); }
|
||||
|
||||
BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
|
||||
|
||||
bool operator!() const BOOST_NOEXCEPT { return ptr_ ? 0 : 1; }
|
||||
|
||||
bool empty() const BOOST_NOEXCEPT { return ptr_ ? 0 : 1; }
|
||||
|
||||
void swap(node_handle_set& n) BOOST_NOEXCEPT_IF(
|
||||
value_allocator_traits::propagate_on_container_swap::value
|
||||
/* || value_allocator_traits::is_always_equal::value */)
|
||||
{
|
||||
if (!has_alloc_) {
|
||||
if (n.has_alloc_) {
|
||||
move_allocator(n);
|
||||
}
|
||||
} else if (!n.has_alloc_) {
|
||||
n.move_allocator(*this);
|
||||
} else {
|
||||
swap_impl(n, boost::unordered::detail::integral_constant<bool,
|
||||
value_allocator_traits::
|
||||
propagate_on_container_swap::value>());
|
||||
}
|
||||
boost::swap(ptr_, n.ptr_);
|
||||
}
|
||||
|
||||
private:
|
||||
void move_allocator(node_handle_set& n)
|
||||
{
|
||||
new ((void*)&alloc_) value_allocator(boost::move(n.alloc_.value()));
|
||||
n.alloc_.value_ptr()->~value_allocator();
|
||||
has_alloc_ = true;
|
||||
n.has_alloc_ = false;
|
||||
}
|
||||
|
||||
void swap_impl(node_handle_set&, boost::unordered::detail::false_type) {}
|
||||
|
||||
void swap_impl(node_handle_set& n, boost::unordered::detail::true_type)
|
||||
{
|
||||
boost::swap(alloc_, n.alloc_);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename N, typename T, typename A>
|
||||
void swap(node_handle_set<N, T, A>& x, node_handle_set<N, T, A>& y)
|
||||
BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(x.swap(y)))
|
||||
{
|
||||
x.swap(y);
|
||||
}
|
||||
|
||||
template <typename N, typename T, typename A> struct insert_return_type_set
|
||||
{
|
||||
private:
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(insert_return_type_set)
|
||||
|
||||
typedef typename boost::unordered::detail::rebind_wrap<A, T>::type
|
||||
value_allocator;
|
||||
typedef N node_;
|
||||
|
||||
public:
|
||||
bool inserted;
|
||||
boost::unordered::iterator_detail::c_iterator<node_> position;
|
||||
boost::unordered::node_handle_set<N, T, A> node;
|
||||
|
||||
insert_return_type_set() : inserted(false), position(), node() {}
|
||||
|
||||
insert_return_type_set(BOOST_RV_REF(insert_return_type_set)
|
||||
x) BOOST_NOEXCEPT : inserted(x.inserted),
|
||||
position(x.position),
|
||||
node(boost::move(x.node))
|
||||
{
|
||||
}
|
||||
|
||||
insert_return_type_set& operator=(BOOST_RV_REF(insert_return_type_set) x)
|
||||
{
|
||||
inserted = x.inserted;
|
||||
position = x.position;
|
||||
node = boost::move(x.node);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename N, typename T, typename A>
|
||||
void swap(
|
||||
insert_return_type_set<N, T, A>& x, insert_return_type_set<N, T, A>& y)
|
||||
{
|
||||
boost::swap(x.node, y.node);
|
||||
boost::swap(x.inserted, y.inserted);
|
||||
boost::swap(x.position, y.position);
|
||||
}
|
||||
} // namespace unordered
|
||||
} // namespace boost
|
||||
|
||||
|
||||
@@ -44,6 +44,9 @@ inline bool operator!=(unordered_multiset<T, H, P, A> const&,
|
||||
template <class T, class H, class P, class A>
|
||||
inline void swap(
|
||||
unordered_multiset<T, H, P, A>& m1, unordered_multiset<T, H, P, A>& m2);
|
||||
|
||||
template <class N, class T, class A> class node_handle_set;
|
||||
template <class N, class T, class A> struct insert_return_type_set;
|
||||
}
|
||||
|
||||
using boost::unordered::unordered_set;
|
||||
|
||||
Reference in New Issue
Block a user