Clean up impl of node_handle

This commit is contained in:
Christian Mazakas
2023-02-10 14:19:01 -08:00
parent 21e673c697
commit f9c32e7f8c
4 changed files with 222 additions and 201 deletions

View File

@ -84,163 +84,6 @@ namespace unordered{
namespace detail{
namespace foa{
template <class Iterator,class NodeType>
struct insert_return_type
{
Iterator position;
bool inserted;
NodeType node;
};
template <class TypePolicy,class Allocator>
struct node_handle_base
{
protected:
using type_policy=TypePolicy;
using value_type=typename type_policy::value_type;
using element_type=typename type_policy::element_type;
public:
using allocator_type = Allocator;
private:
value_type* p_=nullptr;
alignas(Allocator) unsigned char a_[sizeof(Allocator)]={0};
protected:
value_type& element()noexcept
{
BOOST_ASSERT(!empty());
return *p_;
}
value_type const& element()const noexcept
{
BOOST_ASSERT(!empty());
return *p_;
}
Allocator& al()noexcept
{
BOOST_ASSERT(!empty());
return *reinterpret_cast<Allocator*>(a_);
}
Allocator const& al()const noexcept
{
BOOST_ASSERT(!empty());
return *reinterpret_cast<Allocator const*>(a_);
}
void emplace(value_type* p,Allocator a)
{
BOOST_ASSERT(empty());
p_=p;
new(a_)Allocator(a);
}
void emplace(element_type&& x,Allocator a)
{
emplace(x.p,a);
x.p=nullptr;
}
void clear()
{
al().~Allocator();
p_=nullptr;
}
public:
constexpr node_handle_base()noexcept=default;
node_handle_base(node_handle_base&& nh) noexcept
{
if (!nh.empty()){
emplace(nh.p_,nh.al());
nh.clear();
}
}
node_handle_base& operator=(node_handle_base&& nh)noexcept
{
bool const pocma=
boost::allocator_propagate_on_container_move_assignment<
Allocator>::type::value;
if(!empty()){
type_policy::destroy(al(),p_);
if (pocma&&!nh.empty()){al()=std::move(nh.al());}
}
if(!nh.empty()){
if(empty()){new(a_)Allocator(std::move(nh.al()));}
p_=nh.p_;
nh.p_=nullptr;
reinterpret_cast<Allocator*>(nh.a_)->~Allocator();
}else if (!empty()){
reinterpret_cast<Allocator*>(a_)->~Allocator();
p_=nullptr;
}
return *this;
}
~node_handle_base()
{
if(!empty()){
type_policy::destroy(al(),p_);
reinterpret_cast<Allocator*>(a_)->~Allocator();
}
}
allocator_type get_allocator()const noexcept{return al();}
explicit operator bool()const noexcept{ return !empty();}
BOOST_ATTRIBUTE_NODISCARD bool empty()const noexcept{return p_==nullptr;}
void swap(node_handle_base& nh) noexcept(
boost::allocator_is_always_equal<Allocator>::type::value||
boost::allocator_propagate_on_container_swap<Allocator>::type::value)
{
using std::swap;
bool const pocs=
boost::allocator_propagate_on_container_swap<Allocator>::type::value;
if (!empty()&&!nh.empty()){
BOOST_ASSERT(pocs || al()==nh.al());
value_type *p=p_;
p_=nh.p_;
nh.p_=p;
if(pocs){
swap(al(),nh.al());
}
return;
}
if (empty()&&nh.empty()){return;}
if (empty()){
emplace(nh.p_,nh.al());
nh.clear();
}else{
nh.emplace(p_,al());
clear();
}
}
friend
void swap(node_handle_base& lhs,node_handle_base& rhs)
noexcept(noexcept(lhs.swap(rhs)))
{
return lhs.swap(rhs);
}
};
static const std::size_t default_bucket_count = 0;
/* foa::table is an open-addressing hash table serving as the foundational core
@ -1583,6 +1426,14 @@ public:
BOOST_FORCEINLINE std::pair<iterator,bool>
insert(value_type&& x){return emplace_impl(std::move(x));}
template<typename T=element_type>
BOOST_FORCEINLINE
typename std::enable_if<
!std::is_same<T,value_type>::value,
std::pair<iterator,bool>
>::type
insert(element_type&& x){return emplace_impl(std::move(x));}
template<
bool dependent_value=false,
typename std::enable_if<
@ -2045,7 +1896,7 @@ private:
return emplace_impl(type_policy::move(*p));
}
public:
template<typename... Args>
BOOST_FORCEINLINE std::pair<iterator,bool> emplace_impl(Args&&... args)
{
@ -2070,7 +1921,7 @@ public:
};
}
}
private:
static std::size_t capacity_for(std::size_t n)
{
return size_policy::size(size_index_for<group_type,size_policy>(n))*N-1;

View File

@ -0,0 +1,196 @@
/* Copyright 2023 Christian Mazakas.
* 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)
*
* See https://www.boost.org/libs/unordered for library home page.
*/
#ifndef BOOST_UNORDERED_DETAIL_FOA_NODE_HANDLE_HPP
#define BOOST_UNORDERED_DETAIL_FOA_NODE_HANDLE_HPP
#include <boost/config.hpp>
#include <boost/core/allocator_access.hpp>
namespace boost{
namespace unordered{
namespace detail{
namespace foa{
template <class Iterator,class NodeType>
struct insert_return_type
{
Iterator position;
bool inserted;
NodeType node;
};
template <class T>
union opt_storage {
BOOST_ATTRIBUTE_NO_UNIQUE_ADDRESS T t_;
opt_storage(){}
~opt_storage(){}
};
template <class TypePolicy,class Allocator>
struct node_handle_base
{
protected:
using type_policy=TypePolicy;
using value_type=typename type_policy::value_type;
using element_type=typename type_policy::element_type;
public:
using allocator_type = Allocator;
private:
value_type* p_=nullptr;
BOOST_ATTRIBUTE_NO_UNIQUE_ADDRESS opt_storage<Allocator> a_;
protected:
value_type& element()noexcept
{
BOOST_ASSERT(!empty());
return *p_;
}
value_type const& element()const noexcept
{
BOOST_ASSERT(!empty());
return *p_;
}
Allocator& al()noexcept
{
BOOST_ASSERT(!empty());
return a_.t_;
}
Allocator const& al()const noexcept
{
BOOST_ASSERT(!empty());
return a_.t_;
}
void emplace(value_type* p,Allocator a)
{
BOOST_ASSERT(empty());
p_=p;
new(&a_.t_)Allocator(a);
}
void emplace(element_type&& x,Allocator a)
{
emplace(x.p,a);
x.p=nullptr;
}
void clear()
{
al().~Allocator();
p_=nullptr;
}
public:
constexpr node_handle_base()noexcept=default;
node_handle_base(node_handle_base&& nh) noexcept
{
if (!nh.empty()){
emplace(nh.p_,nh.al());
nh.clear();
}
}
node_handle_base& operator=(node_handle_base&& nh)noexcept
{
bool const pocma=
boost::allocator_propagate_on_container_move_assignment<
Allocator>::type::value;
BOOST_ASSERT(
pocma
||empty()
||nh.empty()
||(al()==nh.al()));
if(!empty()){
type_policy::destroy(al(),p_);
if (pocma&&!nh.empty()){al()=std::move(nh.al());}
}
if(!nh.empty()){
if(empty()){new(&a_.t_)Allocator(std::move(nh.al()));}
p_=nh.p_;
nh.p_=nullptr;
nh.a_.t_.~Allocator();
}else if (!empty()){
a_.t_.~Allocator();
p_=nullptr;
}
return *this;
}
~node_handle_base()
{
if(!empty()){
type_policy::destroy(al(),p_);
a_.t_.~Allocator();
}
}
allocator_type get_allocator()const noexcept{return al();}
explicit operator bool()const noexcept{ return !empty();}
BOOST_ATTRIBUTE_NODISCARD bool empty()const noexcept{return p_==nullptr;}
void swap(node_handle_base& nh) noexcept(
boost::allocator_is_always_equal<Allocator>::type::value||
boost::allocator_propagate_on_container_swap<Allocator>::type::value)
{
using std::swap;
bool const pocs=
boost::allocator_propagate_on_container_swap<Allocator>::type::value;
if (!empty()&&!nh.empty()){
BOOST_ASSERT(pocs || al()==nh.al());
value_type *p=p_;
p_=nh.p_;
nh.p_=p;
if(pocs){
swap(al(),nh.al());
}
return;
}
if (empty()&&nh.empty()){return;}
if (empty()){
emplace(nh.p_,nh.al());
nh.clear();
}else{
nh.emplace(p_,al());
clear();
}
}
friend
void swap(node_handle_base& lhs,node_handle_base& rhs)
noexcept(noexcept(lhs.swap(rhs)))
{
return lhs.swap(rhs);
}
};
}
}
}
}
#endif // BOOST_UNORDERED_DETAIL_FOA_NODE_HANDLE_HPP

View File

@ -11,6 +11,7 @@
#endif
#include <boost/unordered/detail/foa.hpp>
#include <boost/unordered/detail/foa/node_handle.hpp>
#include <boost/unordered/detail/type_traits.hpp>
#include <boost/unordered/unordered_node_map_fwd.hpp>
@ -139,16 +140,12 @@ namespace boost {
using base_type =
detail::foa::node_handle_base<NodeMapTypes, Allocator>;
using base_type::element;
using typename base_type::type_policy;
template <class Key, class T, class Hash, class Pred, class Alloc>
friend class boost::unordered::unordered_node_map;
public:
using base_type::empty;
using base_type::swap;
using key_type = typename NodeMapTypes::key_type;
using mapped_type = typename NodeMapTypes::mapped_type;
@ -159,14 +156,14 @@ namespace boost {
key_type& key() const
{
BOOST_ASSERT(!empty());
return const_cast<key_type&>(element().first);
BOOST_ASSERT(!this->empty());
return const_cast<key_type&>(this->element().first);
}
mapped_type& mapped() const
{
BOOST_ASSERT(!empty());
return const_cast<mapped_type&>(element().second);
BOOST_ASSERT(!this->empty());
return const_cast<mapped_type&>(this->element().second);
}
};
} // namespace detail
@ -408,7 +405,7 @@ namespace boost {
typename map_types::element_type x;
x.p=std::addressof(nh.element());
auto itp = table_.emplace_impl(std::move(x));
auto itp = table_.insert(std::move(x));
if (itp.second) {
nh.clear();
return {itp.first, true, node_type{}};
@ -425,7 +422,7 @@ namespace boost {
BOOST_ASSERT(get_allocator() == nh.get_allocator());
auto itp = table_.emplace_impl(map_types::move(nh.element()));
auto itp = table_.insert(map_types::move(nh.element()));
return itp.first;
}
@ -597,12 +594,7 @@ namespace boost {
node_type extract(key_type const& key)
{
auto pos = find(key);
node_type nh;
if (pos != end()) {
auto elem = table_.extract(pos);
nh.emplace(std::move(elem), get_allocator());
}
return nh;
return pos!=end()?extract(pos):node_type();
}
template <class K>
@ -613,12 +605,7 @@ namespace boost {
extract(K const& key)
{
auto pos = find(key);
node_type nh;
if (pos != end()) {
auto elem = table_.extract(pos);
nh.emplace(std::move(elem), get_allocator());
}
return nh;
return pos!=end()?extract(pos):node_type();
}
template <class H2, class P2>

View File

@ -11,6 +11,7 @@
#endif
#include <boost/unordered/detail/foa.hpp>
#include <boost/unordered/detail/foa/node_handle.hpp>
#include <boost/unordered/detail/type_traits.hpp>
#include <boost/unordered/unordered_node_set_fwd.hpp>
@ -121,16 +122,12 @@ namespace boost {
using base_type =
detail::foa::node_handle_base<NodeSetTypes, Allocator>;
using base_type::element;
using typename base_type::type_policy;
template <class Key, class Hash, class Pred, class Alloc>
friend class boost::unordered::unordered_node_set;
public:
using base_type::empty;
using base_type::swap;
using value_type = typename NodeSetTypes::value_type;
constexpr node_set_handle() noexcept = default;
@ -139,8 +136,8 @@ namespace boost {
value_type& value() const
{
BOOST_ASSERT(!empty());
return const_cast<value_type&>(element());
BOOST_ASSERT(!this->empty());
return const_cast<value_type&>(this->element());
}
};
} // namespace detail
@ -396,7 +393,7 @@ namespace boost {
typename set_types::element_type x;
x.p=std::addressof(nh.element());
auto itp = table_.emplace_impl(std::move(x));
auto itp = table_.insert(std::move(x));
if (itp.second) {
nh.clear();
return {itp.first, true, node_type{}};
@ -413,7 +410,7 @@ namespace boost {
BOOST_ASSERT(get_allocator() == nh.get_allocator());
auto itp = table_.emplace_impl(set_types::move(nh.element()));
auto itp = table_.insert(set_types::move(nh.element()));
return itp.first;
}
@ -473,12 +470,7 @@ namespace boost {
node_type extract(key_type const& key)
{
auto pos = find(key);
node_type nh;
if (pos != end()) {
auto elem = table_.extract(pos);
nh.emplace(std::move(elem), get_allocator());
}
return nh;
return pos!=end()?extract(pos):node_type();
}
template <class K>
@ -489,12 +481,7 @@ namespace boost {
extract(K const& key)
{
auto pos = find(key);
node_type nh;
if (pos != end()) {
auto elem = table_.extract(pos);
nh.emplace(std::move(elem), get_allocator());
}
return nh;
return pos!=end()?extract(pos):node_type();
}
template <class H2, class P2>