Begin cleanup of node_handle implementation

This commit is contained in:
Christian Mazakas
2023-02-09 15:59:23 -08:00
parent b96dd2184f
commit 21e673c697
4 changed files with 75 additions and 79 deletions

View File

@ -92,32 +92,32 @@ struct insert_return_type
NodeType node;
};
template <class NodeTypes,class Allocator>
template <class TypePolicy,class Allocator>
struct node_handle_base
{
protected:
using type_policy=NodeTypes;
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:
alignas(element_type) unsigned char x_[sizeof(element_type)];
alignas(Allocator) unsigned char a_[sizeof(Allocator)];
bool empty_=true;
value_type* p_=nullptr;
alignas(Allocator) unsigned char a_[sizeof(Allocator)]={0};
protected:
element_type& element()noexcept
value_type& element()noexcept
{
BOOST_ASSERT(!empty());
return *reinterpret_cast<element_type*>(x_);
return *p_;
}
element_type const& element()const noexcept
value_type const& element()const noexcept
{
BOOST_ASSERT(!empty());
return *reinterpret_cast<element_type const*>(x_);
return *p_;
}
Allocator& al()noexcept
@ -132,13 +132,23 @@ struct node_handle_base
return *reinterpret_cast<Allocator const*>(a_);
}
void emplace(element_type x,Allocator a)
void emplace(value_type* p,Allocator a)
{
BOOST_ASSERT(empty());
new(x_)element_type(std::move(x));
p_=p;
new(a_)Allocator(a);
empty_=false;
}
void emplace(element_type&& x,Allocator a)
{
emplace(x.p,a);
x.p=nullptr;
}
void clear()
{
al().~Allocator();
p_=nullptr;
}
public:
@ -147,16 +157,8 @@ struct node_handle_base
node_handle_base(node_handle_base&& nh) noexcept
{
if (!nh.empty()){
// neither of these move constructors are allowed to throw exceptions
// so we can get away with rote placement new
//
new(a_)Allocator(std::move(nh.al()));
new(x_)element_type(std::move(nh.element()));
empty_=false;
reinterpret_cast<element_type*>(nh.x_)->~element_type();
reinterpret_cast<Allocator*>(nh.a_)->~Allocator();
nh.empty_ = true;
emplace(nh.p_,nh.al());
nh.clear();
}
}
@ -167,22 +169,19 @@ struct node_handle_base
Allocator>::type::value;
if(!empty()){
type_policy::destroy(al(),reinterpret_cast<element_type*>(x_));
reinterpret_cast<element_type*>(x_)->~element_type();
type_policy::destroy(al(),p_);
if (pocma&&!nh.empty()){al()=std::move(nh.al());}
}
if(!nh.empty()){
new(x_)element_type(std::move(nh.element()));
if(empty()){new(a_)Allocator(std::move(nh.al()));}
empty_=false;
p_=nh.p_;
reinterpret_cast<element_type*>(nh.x_)->~element_type();
nh.p_=nullptr;
reinterpret_cast<Allocator*>(nh.a_)->~Allocator();
nh.empty_=true;
}else if (!empty()){
reinterpret_cast<Allocator*>(a_)->~Allocator();
empty_=true;
p_=nullptr;
}
return *this;
@ -191,16 +190,14 @@ struct node_handle_base
~node_handle_base()
{
if(!empty()){
type_policy::destroy(al(),reinterpret_cast<element_type*>(x_));
reinterpret_cast<element_type*>(x_)->~element_type();
type_policy::destroy(al(),p_);
reinterpret_cast<Allocator*>(a_)->~Allocator();
empty_=true;
}
}
allocator_type get_allocator()const noexcept{return al();}
explicit operator bool()const noexcept{ return !empty();}
BOOST_ATTRIBUTE_NODISCARD bool empty()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||
@ -214,7 +211,9 @@ struct node_handle_base
if (!empty()&&!nh.empty()){
BOOST_ASSERT(pocs || al()==nh.al());
element().swap(nh.element());
value_type *p=p_;
p_=nh.p_;
nh.p_=p;
if(pocs){
swap(al(),nh.al());
@ -226,21 +225,11 @@ struct node_handle_base
if (empty()&&nh.empty()){return;}
if (empty()){
new(x_)element_type(std::move(nh.element()));
new(a_)Allocator(nh.al());
empty_=false;
reinterpret_cast<element_type*>(nh.x_)->~element_type();
reinterpret_cast<Allocator*>(nh.a_)->~Allocator();
nh.empty_=true;
emplace(nh.p_,nh.al());
nh.clear();
}else{
new(nh.x_)element_type(std::move(element()));
new(nh.a_)Allocator(al());
nh.empty_=false;
reinterpret_cast<element_type*>(x_)->~element_type();
reinterpret_cast<Allocator*>(a_)->~Allocator();
empty_=true;
nh.emplace(p_,al());
clear();
}
}
@ -1668,13 +1657,12 @@ public:
}
}
element_type extract(const_iterator pos)noexcept
element_type extract(const_iterator pos)
{
BOOST_ASSERT(pos!=end());
element_type x=std::move(*pos.p);
destroy_element(pos.p);
recover_slot(pos.pc);
return x;
erase_on_exit e{*this,iterator{const_iterator_cast_tag{},pos}};
(void)e;
return std::move(*pos.p);
}
// TODO: should we accept different allocator too?

View File

@ -60,10 +60,6 @@ namespace boost {
p = rhs.p;
rhs.p = nullptr;
}
void swap(element_type& rhs) noexcept {
std::swap(p, rhs.p);
}
};
static value_type& value_from(element_type const& x) { return *(x.p); }
@ -118,14 +114,19 @@ namespace boost {
BOOST_CATCH_END
}
template <class A> static void destroy(A& al, value_type* p) noexcept
{
boost::allocator_destroy(al, p);
boost::allocator_deallocate(al,
boost::pointer_traits<
typename boost::allocator_pointer<A>::type>::pointer_to(*p),
1);
}
template <class A> static void destroy(A& al, element_type* p) noexcept
{
if (p->p) {
boost::allocator_destroy(al, p->p);
boost::allocator_deallocate(al,
boost::pointer_traits<
typename boost::allocator_pointer<A>::type>::pointer_to(*p->p),
1);
destroy(al,p->p);
}
}
};
@ -159,14 +160,13 @@ namespace boost {
key_type& key() const
{
BOOST_ASSERT(!empty());
return const_cast<key_type&>(type_policy::extract(element()));
return const_cast<key_type&>(element().first);
}
mapped_type& mapped() const
{
BOOST_ASSERT(!empty());
return const_cast<mapped_type&>(
type_policy::value_from(element()).second);
return const_cast<mapped_type&>(element().second);
}
};
} // namespace detail
@ -405,8 +405,12 @@ namespace boost {
BOOST_ASSERT(get_allocator() == nh.get_allocator());
auto itp = table_.emplace_impl(map_types::move(nh.element()));
typename map_types::element_type x;
x.p=std::addressof(nh.element());
auto itp = table_.emplace_impl(std::move(x));
if (itp.second) {
nh.clear();
return {itp.first, true, node_type{}};
} else {
return {itp.first, false, std::move(nh)};

View File

@ -56,10 +56,6 @@ namespace boost {
p = rhs.p;
rhs.p = nullptr;
}
void swap(element_type& rhs) noexcept {
std::swap(p, rhs.p);
}
};
static value_type& value_from(element_type const& x) { return *x.p; }
@ -100,14 +96,19 @@ namespace boost {
BOOST_CATCH_END
}
template <class A> static void destroy(A& al, value_type* p) noexcept
{
boost::allocator_destroy(al, p);
boost::allocator_deallocate(al,
boost::pointer_traits<
typename boost::allocator_pointer<A>::type>::pointer_to(*p),
1);
}
template <class A> static void destroy(A& al, element_type* p) noexcept
{
if (p->p) {
boost::allocator_destroy(al, p->p);
boost::allocator_deallocate(al,
boost::pointer_traits<
typename boost::allocator_pointer<A>::type>::pointer_to(*p->p),
1);
destroy(al, p->p);
}
}
};
@ -139,7 +140,7 @@ namespace boost {
value_type& value() const
{
BOOST_ASSERT(!empty());
return const_cast<value_type&>(type_policy::extract(element()));
return const_cast<value_type&>(element());
}
};
} // namespace detail
@ -392,8 +393,12 @@ namespace boost {
BOOST_ASSERT(get_allocator() == nh.get_allocator());
auto itp = table_.emplace_impl(set_types::move(nh.element()));
typename set_types::element_type x;
x.p=std::addressof(nh.element());
auto itp = table_.emplace_impl(std::move(x));
if (itp.second) {
nh.clear();
return {itp.first, true, node_type{}};
} else {
return {itp.first, false, std::move(nh)};

View File

@ -119,7 +119,6 @@ static void failed_insertion_with_hint()
typename Set<int>::node_type nh = src.extract(10);
std::cout << "performing relevant test now" << std::endl;
BOOST_TEST(dst.insert(dst.find(10), boost::move(nh)) == dst.find(10));
BOOST_TEST(nh);
BOOST_TEST(!nh.empty());