From 1a50b78e15bb4c2ea77d5013763a91bec76b2e9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Thu, 12 Feb 2026 22:42:54 +0100 Subject: [PATCH] Add "store_data_in_block" option to nest --- include/boost/container/experimental/nest.hpp | 236 +++++++++++++----- 1 file changed, 180 insertions(+), 56 deletions(-) diff --git a/include/boost/container/experimental/nest.hpp b/include/boost/container/experimental/nest.hpp index a504eb2..a2e3953 100644 --- a/include/boost/container/experimental/nest.hpp +++ b/include/boost/container/experimental/nest.hpp @@ -26,6 +26,7 @@ // container #include +#include #include #include // container/detail @@ -127,10 +128,70 @@ do{ \ namespace boost { namespace container { +//////////////////////////////////////////////////////////////// +// +// +// OPTIONS FOR NEST CONTAINER (EXPERIMENTAL) +// +// +//////////////////////////////////////////////////////////////// + +#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + +template +struct nest_opt +{ + BOOST_STATIC_CONSTEXPR bool store_data_in_block = StoreDataInBlock; +}; + +typedef nest_opt nest_null_opt; + +#endif // !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + +//! This option specifies whether block data (value storage) is inlined +//! in each block (true) or allocated separately via the allocator (false). +//! Inline data can improve locality but increases block size. +//! +//!\tparam Enabled A boolean value. +BOOST_INTRUSIVE_OPTION_CONSTANT(store_data_in_block, bool, Enabled, store_data_in_block) + +//! Helper metafunction to combine options into a single type to be used +//! by \c boost::container::nest. +#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) || defined(BOOST_CONTAINER_VARIADIC_TEMPLATES) +template +#else +template +#endif +struct nest_options +{ + /// @cond + typedef typename ::boost::intrusive::pack_options + < nest_null_opt, + #if !defined(BOOST_CONTAINER_VARIADIC_TEMPLATES) + O1, O2, O3, O4 + #else + Options... + #endif + >::type packed_options; + typedef nest_opt implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + +template +using nest_options_t = typename boost::container::nest_options::type; + +#endif + +#endif // !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED template + ,class Allocator = void + ,class Options = void> class nest; namespace nest_detail { @@ -218,12 +279,12 @@ struct block_base BOOST_STATIC_CONSTEXPR std::size_t N = 64; BOOST_STATIC_CONSTEXPR mask_type full = (mask_type)(-1); - static pointer pointer_to(block_base& x) BOOST_NOEXCEPT + BOOST_CONTAINER_FORCEINLINE static pointer pointer_to(block_base& x) BOOST_NOEXCEPT { return boost::intrusive::pointer_traits::pointer_to(x); } - static const_pointer pointer_to(const block_base& x) BOOST_NOEXCEPT + BOOST_CONTAINER_FORCEINLINE static const_pointer pointer_to(const block_base& x) BOOST_NOEXCEPT { return boost::intrusive::pointer_traits::pointer_to(x); } @@ -232,16 +293,18 @@ struct block_base { next_available = p; prev_available = p->prev_available; - next_available->prev_available = pointer_to(*this); - prev_available->next_available = pointer_to(*this); + pointer const pthis = pointer_to(*this); + next_available->prev_available = pthis; + prev_available->next_available = pthis; } BOOST_CONTAINER_FORCEINLINE void link_available_after(pointer p) BOOST_NOEXCEPT { prev_available = p; next_available = p->next_available; - next_available->prev_available = pointer_to(*this); - prev_available->next_available = pointer_to(*this); + pointer const pthis = pointer_to(*this); + next_available->prev_available = pthis; + prev_available->next_available = pthis; } BOOST_CONTAINER_FORCEINLINE void unlink_available() BOOST_NOEXCEPT @@ -254,16 +317,18 @@ struct block_base { next = p; prev = p->prev; - next->prev = pointer_to(*this); - prev->next = pointer_to(*this); + pointer const pthis = pointer_to(*this); + next->prev = pthis; + prev->next = pthis; } BOOST_CONTAINER_FORCEINLINE void link_after(pointer p) BOOST_NOEXCEPT { prev = p; next = p->next; - next->prev = pointer_to(*this); - prev->next = pointer_to(*this); + pointer const pthis = pointer_to(*this); + next->prev = pthis; + prev->next = pthis; } BOOST_CONTAINER_FORCEINLINE void unlink() BOOST_NOEXCEPT @@ -279,28 +344,49 @@ struct block_base mask_type mask; }; -template +template struct block : block_base::type> { typedef block_base::type> super; - + typedef typename boost::intrusive::pointer_traits::element_type value_type; ValuePointer data() BOOST_NOEXCEPT { return data_; } + static void set_data_null(block* p) BOOST_NOEXCEPT { p->data_ = ValuePointer(); } ValuePointer data_; }; template -void swap_payload(block& x, block& y) BOOST_NOEXCEPT +struct block + : block_base::type> +{ + typedef block_base::type> super; + typedef typename boost::intrusive::pointer_traits::element_type value_type; + ValuePointer data() BOOST_NOEXCEPT { return static_cast(static_cast(&data_stor)); } + static void set_data_null(block*) BOOST_NOEXCEPT {} + typename dtl::aligned_storage::value>::type data_stor; +}; + +template +void swap_payload(block& x, block& y) BOOST_NOEXCEPT; + +template +void swap_payload(block& x, block& y) BOOST_NOEXCEPT +{ + boost::adl_move_swap(x.mask, y.mask); +} + +template +void swap_payload(block& x, block& y) BOOST_NOEXCEPT { boost::adl_move_swap(x.mask, y.mask); boost::adl_move_swap(x.data_, y.data_); } -template +template struct block_list - : block + : block { - typedef nest_detail::block block_type; + typedef nest_detail::block block_type; typedef typename block_type::super block_base_type; typedef typename block_base_type::pointer block_base_pointer; typedef typename block_base_type::const_pointer const_block_base_pointer; @@ -313,7 +399,6 @@ struct block_list using block_base_type::prev; using block_base_type::next; using block_base_type::mask; - using block_type::data_; static block_pointer static_cast_block_pointer(block_base_pointer pbb) BOOST_NOEXCEPT @@ -326,14 +411,14 @@ struct block_list { reset(); mask = 1; /* sentinel */ - data_ = ValuePointer(); + block_type::set_data_null(this); } block_list(BOOST_RV_REF(block_list) x) BOOST_NOEXCEPT { reset(); mask = 1; /* sentinel */ - data_ = ValuePointer(); + block_type::set_data_null(this); if(x.next_available != x.header()) { prev_available = x.prev_available; next_available = x.next_available; @@ -427,7 +512,7 @@ private: // ////////////////////////////////////////////// -template +template class iterator { typedef typename boost::intrusive::pointer_traits::element_type element_type; @@ -450,7 +535,7 @@ public: typedef typename nest_detail::pointer_rebind::type maybe_nonconst_pointer; typedef typename dtl::if_c< boost::move_detail::is_const::value - , iterator< maybe_nonconst_pointer > + , iterator< maybe_nonconst_pointer, StoreDataInBlock > , nat>::type maybe_nonconst_iterator; iterator() BOOST_NOEXCEPT @@ -538,15 +623,15 @@ public: } private: - template friend class iterator; - template friend class boost::container::nest; + template friend class iterator; + template friend class boost::container::nest; typedef typename pointer_rebind::type void_pointer; typedef nest_detail::block_base block_base_type; typedef typename pointer_rebind::type block_base_pointer; typedef typename pointer_rebind::type const_block_base_pointer; typedef typename pointer_rebind::type nonconst_pointer; - typedef nest_detail::block block_type; + typedef nest_detail::block block_type; typedef typename block_base_type::mask_type mask_type; BOOST_STATIC_CONSTEXPR std::size_t N = block_base_type::N; @@ -736,7 +821,7 @@ void move_assign_if(dtl::false_type, T&, T&) {} // ////////////////////////////////////////////// -template +template struct block_typedefs { typedef boost::container::allocator_traits val_alloc_traits; @@ -749,14 +834,14 @@ struct block_typedefs typedef typename pointer_rebind< value_pointer, const block_base_t>::type const_block_base_pointer; - typedef nest_detail::block block_t; + typedef nest_detail::block block_t; typedef typename pointer_rebind< value_pointer, block_t>::type block_pointer; typedef typename val_alloc_traits:: template portable_rebind_alloc::type block_allocator; - typedef nest_detail::block_list block_list_t; + typedef nest_detail::block_list block_list_t; }; ////////////////////////////////////////////// @@ -810,15 +895,35 @@ struct visit_adaptor }; template -struct const_visit_adaptor +struct const_conditional_visit_adaptor { F& f; - explicit const_visit_adaptor(F& f_) : f(f_) {} + explicit const_conditional_visit_adaptor(F& f_) : f(f_) {} bool operator()(const T& x) const { return f(x); } }; } // namespace nest_detail +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +template +struct get_nest_opt +{ + typedef nest_opt type; +}; + +template<> +struct get_nest_opt +{ + typedef nest_null_opt type; +}; + +template +struct get_nest_opt > +{ + typedef nest_opt type; +}; + #endif // BOOST_CONTAINER_DOXYGEN_INVOKED ////////////////////////////////////////////////////////////////////////////// @@ -834,21 +939,25 @@ struct const_visit_adaptor //! \tparam T The type of object stored in the nest //! \tparam Allocator The allocator used for all internal memory management, use void //! for the default allocator +//! \tparam Options A type produced from \c boost::container::nest_options (e.g. \c store_data_in_block). #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED -template +template #else -template +template #endif class nest : private boost::empty_value< typename nest_detail::block_typedefs< typename real_allocator::type + , get_nest_opt::type::store_data_in_block >::block_allocator, 0> { #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED typedef typename real_allocator::type ValueAllocator; + typedef typename get_nest_opt::type options_type; + BOOST_STATIC_CONSTEXPR bool store_data_in_block = options_type::store_data_in_block; typedef boost::container::allocator_traits allocator_traits_type; - typedef nest_detail::block_typedefs btd; + typedef nest_detail::block_typedefs btd; typedef typename btd::block_base_t block_base; typedef typename btd::block_base_pointer block_base_pointer; typedef typename btd::const_block_base_pointer const_block_base_pointer; @@ -881,8 +990,8 @@ class nest typedef const T& const_reference; typedef typename allocator_traits_type::size_type size_type; typedef typename allocator_traits_type::difference_type difference_type; - typedef BOOST_CONTAINER_IMPDEF(nest_detail::iterator) iterator; - typedef BOOST_CONTAINER_IMPDEF(nest_detail::iterator) const_iterator; + typedef BOOST_CONTAINER_IMPDEF(nest_detail::iterator) iterator; + typedef BOOST_CONTAINER_IMPDEF(nest_detail::iterator) const_iterator; typedef BOOST_CONTAINER_IMPDEF(boost::container::reverse_iterator) reverse_iterator; typedef BOOST_CONTAINER_IMPDEF(boost::container::reverse_iterator) const_reverse_iterator; @@ -1277,14 +1386,15 @@ class nest BOOST_CONTAINER_FORCEINLINE iterator emplace(BOOST_FWD_REF(Args)... args) { int n; - block_pointer pb = priv_retrieve_available_block(n); + block_pointer const pb = priv_retrieve_available_block(n); block_alloc_traits::construct( al(), boost::movelib::to_raw_pointer(pb->data() + n), boost::forward(args)...); pb->mask |= pb->mask + 1; - if(BOOST_UNLIKELY(pb->mask + 1 <= 2)) { - if(pb->mask == 1) blist.link_at_back(pb); - else blist.unlink_available(pb); + const mask_type m = pb->mask; + if(BOOST_UNLIKELY(m + 1 <= 2)) { + if(m == 1) blist.link_at_back(pb); + else blist.unlink_available(pb); } ++size_; return iterator(pb, n); @@ -1617,7 +1727,7 @@ class nest template const_iterator visit_while(const_iterator first, const_iterator last, F f) const { - nest_detail::const_visit_adaptor adaptor(f); + nest_detail::const_conditional_visit_adaptor adaptor(f); iterator it = const_cast(this)->visit_while( iterator(first.pbb, first.n), iterator(last.pbb, last.n), @@ -1650,9 +1760,10 @@ class nest #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: - template - friend typename nest::size_type erase_if(nest&, P); + template + friend typename nest::size_type erase_if(nest&, P); + private: ////////////////////////////////////////////// // // private: allocator access @@ -1675,10 +1786,8 @@ class nest static_cast_block_pointer(block_base_pointer pbb) BOOST_NOEXCEPT { return block_list::static_cast_block_pointer(pbb); } - block_pointer priv_create_new_available_block() + void priv_allocate_block_data(block_pointer pb, dtl::bool_) { - block_pointer pb = block_alloc_traits::allocate(al(), 1); - pb->mask = 0; BOOST_TRY { allocator_type val_al(al()); pb->data_ = allocator_traits_type::allocate(val_al, N); @@ -1688,6 +1797,21 @@ class nest BOOST_RETHROW; } BOOST_CATCH_END + } + void priv_allocate_block_data(block_pointer, dtl::bool_) BOOST_NOEXCEPT {} + + void priv_deallocate_block_data(block_pointer pb, dtl::bool_) BOOST_NOEXCEPT + { + allocator_type val_al(al()); + allocator_traits_type::deallocate(val_al, pb->data(), N); + } + void priv_deallocate_block_data(block_pointer, dtl::bool_) BOOST_NOEXCEPT {} + + block_pointer priv_create_new_available_block() + { + block_pointer pb = block_alloc_traits::allocate(al(), 1); + pb->mask = 0; + priv_allocate_block_data(pb, dtl::bool_()); blist.link_available_at_back(pb); ++num_blocks; return pb; @@ -1695,8 +1819,7 @@ class nest void priv_delete_block(block_pointer pb) BOOST_NOEXCEPT { - allocator_type val_al(al()); - allocator_traits_type::deallocate(val_al, pb->data(), N); + priv_deallocate_block_data(pb, dtl::bool_()); block_alloc_traits::deallocate(al(), pb, 1); } @@ -2413,8 +2536,8 @@ class nest ////////////////////////////////////////////// //! Effects: Swaps x and y. -template -inline void swap(nest& x, nest& y) +template +inline void swap(nest& x, nest& y) BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT(x.swap(y))) { x.swap(y); @@ -2423,9 +2546,9 @@ inline void swap(nest& x, nest& y) //! Effects: Erases all elements for which pred returns true. //! //! Returns: The number of erased elements. -template -typename nest::size_type -erase_if(nest& x, Predicate pred) +template +typename nest::size_type +erase_if(nest& x, Predicate pred) { return x.priv_erase_if(pred); } @@ -2433,9 +2556,9 @@ erase_if(nest& x, Predicate pred) //! Effects: Erases all elements equal to value. //! //! Returns: The number of erased elements. -template -typename nest::size_type -erase(nest& x, const T& value) +template +typename nest::size_type +erase(nest& x, const T& value) { return erase_if(x, equal_to_value(value)); } @@ -2449,7 +2572,8 @@ template< nest(InpIt, InpIt, Allocator = Allocator()) -> nest< typename iterator_traits::value_type, - Allocator>; + Allocator, + void>; #endif