Refactor node implemenations from 3 (slist_node, list_node and tree_node) to a single base_node:

- To avoid unneeded includes, is_pair is factored out from pair.hpp implementation
- Fixed bug where value_types inside nodes were not allocator-ware destructed.
- Changed scoped utilities to handle new clases
This commit is contained in:
Ion Gaztañaga
2022-01-04 00:41:34 +01:00
parent 30a4508371
commit 15d61d6d26
13 changed files with 358 additions and 388 deletions
@@ -36,6 +36,7 @@
#include <boost/move/detail/to_raw_pointer.hpp>
#include <boost/container/detail/type_traits.hpp>
#include <boost/container/detail/version_type.hpp>
#include <boost/container/detail/is_pair.hpp>
// intrusive
#include <boost/intrusive/detail/mpl.hpp>
#include <boost/intrusive/options.hpp>
@@ -50,6 +51,140 @@
namespace boost {
namespace container {
//This trait is used to type-pun std::pair because in C++03
//compilers std::pair is useless for C++11 features
template<class T, bool = dtl::is_pair<T>::value >
struct node_internal_data_type
{
typedef T type;
};
template<class T>
struct node_internal_data_type< T, true>
{
typedef dtl::pair< typename dtl::remove_const<typename T::first_type>::type
, typename T::second_type>
type;
};
template <class T, class HookDefiner>
struct base_node
: public HookDefiner::type
{
public:
typedef T value_type;
typedef typename node_internal_data_type<T>::type internal_type;
typedef typename HookDefiner::type hook_type;
typedef typename dtl::aligned_storage<sizeof(T), dtl::alignment_of<T>::value>::type storage_t;
storage_t m_storage;
#if defined(BOOST_GCC) && (BOOST_GCC >= 40600) && (BOOST_GCC < 80000)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#define BOOST_CONTAINER_DISABLE_ALIASING_WARNING
# endif
public:
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template<class Alloc, class ...Args>
explicit base_node(Alloc &a, Args &&...args)
: hook_type()
{
::boost::container::allocator_traits<Alloc>::construct
(a, &this->get_real_data(), ::boost::forward<Args>(args)...);
}
#else //defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
#define BOOST_CONTAINER_BASE_NODE_CONSTRUCT_IMPL(N) \
template< class Alloc BOOST_MOVE_I##N BOOST_MOVE_CLASS##N > \
explicit base_node(Alloc &a BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\
: hook_type()\
{\
::boost::container::allocator_traits<Alloc>::construct\
(a, &this->get_real_data() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\
}\
//
BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_BASE_NODE_CONSTRUCT_IMPL)
#undef BOOST_CONTAINER_BASE_NODE_CONSTRUCT_IMPL
#endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template<class Alloc, class It>
explicit base_node(iterator_arg_t, Alloc &a, It it)
: hook_type()
{
::boost::container::construct_in_place(a, &this->get_real_data(), it);
}
BOOST_CONTAINER_FORCEINLINE T &get_data()
{ return *move_detail::force_ptr<T*>(this->m_storage.data); }
BOOST_CONTAINER_FORCEINLINE const T &get_data() const
{ return *move_detail::force_ptr<const T*>(this->m_storage.data); }
BOOST_CONTAINER_FORCEINLINE internal_type &get_real_data()
{ return *move_detail::force_ptr<internal_type*>(this->m_storage.data); }
BOOST_CONTAINER_FORCEINLINE const internal_type &get_real_data() const
{ return *move_detail::force_ptr<const internal_type*>(this->m_storage.data); }
#if defined(BOOST_CONTAINER_DISABLE_ALIASING_WARNING)
#pragma GCC diagnostic pop
#undef BOOST_CONTAINER_DISABLE_ALIASING_WARNING
# endif
template<class Alloc>
void destructor(Alloc &a) BOOST_NOEXCEPT
{
allocator_traits<Alloc>::destroy
(a, &this->get_real_data());
this->~base_node();
}
template<class Pair>
BOOST_CONTAINER_FORCEINLINE
typename dtl::enable_if< dtl::is_pair<Pair>, void >::type
do_assign(const Pair &p)
{
typedef typename Pair::first_type first_type;
const_cast<typename dtl::remove_const<first_type>::type &>(this->get_real_data().first) = p.first;
this->get_real_data().second = p.second;
}
template<class V>
BOOST_CONTAINER_FORCEINLINE
typename dtl::disable_if< dtl::is_pair<V>, void >::type
do_assign(const V &v)
{ this->get_real_data() = v; }
template<class Pair>
BOOST_CONTAINER_FORCEINLINE
typename dtl::enable_if< dtl::is_pair<Pair>, void >::type
do_move_assign(Pair &p)
{
typedef typename Pair::first_type first_type;
const_cast<first_type&>(this->get_real_data().first) = ::boost::move(p.first);
this->get_real_data().second = ::boost::move(p.second);
}
template<class V>
BOOST_CONTAINER_FORCEINLINE
typename dtl::disable_if< dtl::is_pair<V>, void >::type
do_move_assign(V &v)
{ this->get_real_data() = ::boost::move(v); }
private:
base_node();
BOOST_CONTAINER_FORCEINLINE ~base_node()
{ }
};
namespace dtl {
BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(key_compare)
@@ -111,7 +246,7 @@ struct node_alloc_holder
version<NodeAlloc>::value> alloc_version;
typedef typename ICont::iterator icont_iterator;
typedef typename ICont::const_iterator icont_citerator;
typedef allocator_destroyer<NodeAlloc> Destroyer;
typedef allocator_node_destroyer<NodeAlloc> Destroyer;
typedef allocator_traits<NodeAlloc> NodeAllocTraits;
typedef allocator_version_traits<NodeAlloc> AllocVersionTraits;
@@ -176,7 +311,7 @@ struct node_alloc_holder
{}
explicit node_alloc_holder(BOOST_RV_REF(node_alloc_holder) x)
: NodeAlloc(boost::move(x.node_alloc()))
: NodeAlloc(boost::move(BOOST_MOVE_TO_LV(x).node_alloc()))
{ this->icont().swap(x.icont()); }
explicit node_alloc_holder(const val_compare &c)
@@ -185,15 +320,15 @@ struct node_alloc_holder
//helpers for move assignments
explicit node_alloc_holder(BOOST_RV_REF(node_alloc_holder) x, const val_compare &c)
: NodeAlloc(boost::move(x.node_alloc())), m_icont(typename ICont::key_compare(c))
: NodeAlloc(boost::move(BOOST_MOVE_TO_LV(x).node_alloc())), m_icont(typename ICont::key_compare(c))
{ this->icont().swap(x.icont()); }
explicit node_alloc_holder(BOOST_RV_REF(node_alloc_holder) x, const val_hasher &hf, const val_equal &eql)
: NodeAlloc(boost::move(x.node_alloc()))
: NodeAlloc(boost::move(BOOST_MOVE_TO_LV(x).node_alloc()))
, m_icont( typename ICont::bucket_traits()
, typename ICont::hasher(hf)
, typename ICont::key_equal(eql))
{ this->icont().swap(x.icont()); }
{ this->icont().swap(BOOST_MOVE_TO_LV(x).icont()); }
void copy_assign_alloc(const node_alloc_holder &x)
{
@@ -227,18 +362,11 @@ struct node_alloc_holder
NodePtr create_node(Args &&...args)
{
NodePtr p = this->allocate_one();
BOOST_TRY{
::new(boost::movelib::iterator_to_raw_pointer(p), boost_container_new_t()) Node;
allocator_traits<NodeAlloc>::construct
(this->node_alloc()
, p->get_real_data_ptr(), boost::forward<Args>(args)...);
}
BOOST_CATCH(...) {
p->destroy_header();
this->node_alloc().deallocate(p, 1);
BOOST_RETHROW
}
BOOST_CATCH_END
NodeAlloc &nalloc = this->node_alloc();
Deallocator node_deallocator(p, nalloc);
::new(boost::movelib::iterator_to_raw_pointer(p), boost_container_new_t())
Node(nalloc, boost::forward<Args>(args)...);
node_deallocator.release();
return (p);
}
@@ -249,19 +377,11 @@ struct node_alloc_holder
NodePtr create_node(BOOST_MOVE_UREF##N)\
{\
NodePtr p = this->allocate_one();\
BOOST_TRY{\
::new(boost::movelib::iterator_to_raw_pointer(p), boost_container_new_t()) Node;\
allocator_traits<NodeAlloc>::construct\
( this->node_alloc()\
, p->get_real_data_ptr()\
BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\
}\
BOOST_CATCH(...) {\
p->destroy_header();\
this->node_alloc().deallocate(p, 1);\
BOOST_RETHROW\
}\
BOOST_CATCH_END\
NodeAlloc &nalloc = this->node_alloc();\
Deallocator node_deallocator(p, nalloc);\
::new(boost::movelib::iterator_to_raw_pointer(p), boost_container_new_t())\
Node(nalloc BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\
node_deallocator.release();\
return (p);\
}\
//
@@ -274,16 +394,11 @@ struct node_alloc_holder
NodePtr create_node_from_it(const It &it)
{
NodePtr p = this->allocate_one();
BOOST_TRY{
::new(boost::movelib::iterator_to_raw_pointer(p), boost_container_new_t()) Node;
::boost::container::construct_in_place(this->node_alloc(), p->get_real_data_ptr(), it);
}
BOOST_CATCH(...) {
p->destroy_header();
this->node_alloc().deallocate(p, 1);
BOOST_RETHROW
}
BOOST_CATCH_END
NodeAlloc &nalloc = this->node_alloc();
Deallocator node_deallocator(p, nalloc);
::new(boost::movelib::iterator_to_raw_pointer(p), boost_container_new_t())
Node(iterator_arg_t(), nalloc, it);
node_deallocator.release();
return (p);
}
@@ -316,7 +431,7 @@ struct node_alloc_holder
void destroy_node(const NodePtr &nodep)
{
allocator_traits<NodeAlloc>::destroy(this->node_alloc(), boost::movelib::to_raw_pointer(nodep));
boost::movelib::to_raw_pointer(nodep)->destructor(this->node_alloc());
this->deallocate_one(nodep);
}
@@ -346,28 +461,25 @@ struct node_alloc_holder
Node *p = 0;
BOOST_TRY{
Deallocator node_deallocator(NodePtr(), nalloc);
dtl::scoped_destructor<NodeAlloc> sdestructor(nalloc, 0);
dtl::scoped_node_destructor<NodeAlloc> sdestructor(nalloc, 0);
while(n){
--n;
p = boost::movelib::iterator_to_raw_pointer(itbeg);
++itbeg; //Increment iterator before overwriting pointed memory
//This does not throw
p = ::new(p, boost_container_new_t()) Node;
node_deallocator.set(p);
//This can throw
boost::container::construct_in_place(nalloc, p->get_real_data_ptr(), beg);
::new(boost::movelib::iterator_to_raw_pointer(p), boost_container_new_t())
Node(iterator_arg_t(), nalloc, beg);
sdestructor.set(p);
++beg;
//This can throw in some containers (predicate might throw).
//(sdestructor will destruct the node and node_deallocator will deallocate it in case of exception)
inserter(*p);
sdestructor.set(0);
sdestructor.release();
}
sdestructor.release();
node_deallocator.release();
}
BOOST_CATCH(...){
p->destroy_header();
chain.incorporate_after(chain.last(), &*itbeg, &*itlast, n);
node_allocator_version_traits_type::deallocate_individual(this->node_alloc(), chain);
BOOST_RETHROW
@@ -382,7 +494,7 @@ struct node_alloc_holder
void clear(version_2)
{
typename NodeAlloc::multiallocation_chain chain;
allocator_destroyer_and_chain_builder<NodeAlloc> builder(this->node_alloc(), chain);
allocator_node_destroyer_and_chain_builder<NodeAlloc> builder(this->node_alloc(), chain);
this->icont().clear_and_dispose(builder);
//BOOST_STATIC_ASSERT((::boost::has_move_emulation_enabled<typename NodeAlloc::multiallocation_chain>::value == true));
if(!chain.empty())
@@ -396,7 +508,7 @@ struct node_alloc_holder
{
NodeAlloc & nalloc = this->node_alloc();
typename NodeAlloc::multiallocation_chain chain;
allocator_destroyer_and_chain_builder<NodeAlloc> chain_builder(nalloc, chain);
allocator_node_destroyer_and_chain_builder<NodeAlloc> chain_builder(nalloc, chain);
icont_iterator ret_it = this->icont().erase_and_dispose(first, last, chain_builder);
nalloc.deallocate_individual(chain);
return ret_it;