diff --git a/doc/container.qbk b/doc/container.qbk index 3ad5063..4efb678 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1341,6 +1341,7 @@ use [*Boost.Container]? There are several reasons for that: [section:release_notes_boost_1_80_00 Boost 1.80 Release] * Fixed bugs/issues: + * [@https://github.com/boostorg/container/issues/221 GitHub #218: ['"small_vector static capacity is too small when not a multiple of 8 bytes"]]. * [@https://github.com/boostorg/container/issues/221 GitHub #221: ['"flat_set and friends should offer a const sequence_type& sequence() const method (...)"]]. * [@https://github.com/boostorg/container/pull/222 GitHub #222: ['"Fix incomplete type error when using list with pair"]]. * [@https://github.com/boostorg/container/issues/223 GitHub #223: ['"Possible copypaste typo"]]. diff --git a/include/boost/container/small_vector.hpp b/include/boost/container/small_vector.hpp index 088d51d..6ba4675 100644 --- a/include/boost/container/small_vector.hpp +++ b/include/boost/container/small_vector.hpp @@ -77,14 +77,14 @@ struct get_vopt_from_svopt typedef void type; }; -template +template struct vector_for_small_vector { typedef vector < T , small_vector_allocator < T - , typename allocator_traits::type>::template portable_rebind_alloc::type + , typename allocator_traits::type>::template portable_rebind_alloc::type , Options> , typename dtl::get_vopt_from_svopt::type > type; @@ -118,15 +118,15 @@ struct vector_for_small_vector //! `boost::container::vector< T, small_vector_allocator >` //! and internal storage can be obtained downcasting that vector //! to `small_vector_base`. -template +template class small_vector_allocator - : public allocator_traits::type>::template portable_rebind_alloc::type + : public allocator_traits::template portable_rebind_alloc::type { typedef unsigned int allocation_type; #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: - typedef typename allocator_traits::type>::template portable_rebind_alloc::type allocator_type; + typedef typename allocator_traits::template portable_rebind_alloc::type allocator_type; BOOST_COPYABLE_AND_MOVABLE(small_vector_allocator) @@ -282,65 +282,36 @@ class small_vector_allocator { return !(l == r); } #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED - /* - //!An advanced function that offers in-place expansion shrink to fit and new allocation - //!capabilities. Memory allocated with this function can only be deallocated with deallocate() - //!or deallocate_many(). - //!This function is available only with Version == 2 - pointer allocation_command(allocation_type command, - size_type limit_size, - size_type &prefer_in_recvd_out_size, - pointer &reuse) - { return allocator_traits_type::allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse); } - - //!Returns maximum the number of objects the previously allocated memory - //!pointed by p can hold. - //!Memory must not have been allocated with - //!allocate_one or allocate_individual. - //!This function is available only with Version == 2 - size_type size(pointer p) const BOOST_NOEXCEPT_OR_NOTHROW - { return allocator_traits_type::size(p); } - */ private: - /* - //!Allocates just one object. Memory allocated with this function - //!must be deallocated only with deallocate_one(). - //!Throws bad_alloc if there is no enough memory - //!This function is available only with Version == 2 - using allocator_type::allocate_one; - using allocator_type::allocate_individual; - using allocator_type::deallocate_one; - using allocator_type::deallocate_individual; - using allocator_type::allocate_many; - using allocator_type::deallocate_many;*/ - typedef vector_alloc_holder< small_vector_allocator, size_type > vector_alloc_holder_t; - typedef typename dtl::vector_for_small_vector::type vector_base; typedef small_vector_base derived_type; + typedef typename dtl::vector_for_small_vector + ::type vector_type; BOOST_CONTAINER_FORCEINLINE bool is_internal_storage(const_pointer p) const { return this->internal_storage() == p; } - BOOST_CONTAINER_FORCEINLINE - const_pointer internal_storage() const - { - const vector_alloc_holder_t &v_holder = static_cast(*this); - const vector_base &v_base = *move_detail::force_ptr(&v_holder); - const derived_type &d_base = static_cast(v_base); - return d_base.internal_storage(); - } - - BOOST_CONTAINER_FORCEINLINE - pointer internal_storage() - { - vector_alloc_holder_t &v_holder = static_cast(*this); - vector_base &v_base = *move_detail::force_ptr(&v_holder); - derived_type &d_base = static_cast(v_base); - return d_base.internal_storage(); - } + public: + BOOST_CONTAINER_FORCEINLINE const_pointer internal_storage() const BOOST_NOEXCEPT_OR_NOTHROW; + BOOST_CONTAINER_FORCEINLINE pointer internal_storage() BOOST_NOEXCEPT_OR_NOTHROW; #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED }; +template +struct small_vector_storage +{ + typedef typename dtl::aligned_storage + ::type storage_type; + storage_type m_storage; + static const std::size_t sms_size = sizeof(storage_type)/sizeof(T); +}; + +template +struct small_vector_storage +{ + static const std::size_t sms_size = 0u; +}; + //! This class consists of common code from all small_vector types that don't depend on the //! "N" template parameter. This class is non-copyable and non-destructible, so this class typically //! used as reference argument to functions that read or write small vectors. Since `small_vector` @@ -366,20 +337,20 @@ class small_vector_allocator //! //! All `boost::container:vector` member functions are inherited. See `vector` documentation for details. //! -template +template class small_vector_base - : public dtl::vector_for_small_vector::type + : public dtl::vector_for_small_vector::type { #ifndef BOOST_CONTAINER_DOXYGEN_INVOKEDVECTOR public: //Make it public as it will be inherited by small_vector and container //must have this public member - typedef typename real_allocator::type secondary_allocator_t; + typedef typename real_allocator::type secondary_allocator_t; typedef typename allocator_traits:: template portable_rebind_alloc::type void_allocator_t; typedef typename dtl::get_small_vector_opt::type options_t; typedef typename dtl::vector_for_small_vector - ::type base_type; + ::type base_type; typedef typename allocator_traits::pointer pointer; typedef typename allocator_traits::const_pointer const_pointer; typedef typename allocator_traits::void_pointer void_pointer; @@ -393,34 +364,18 @@ class small_vector_base BOOST_CONTAINER_FORCEINLINE const_pointer internal_storage() const BOOST_NOEXCEPT_OR_NOTHROW - { - typedef typename boost::intrusive::pointer_traits::template - rebind_pointer::type const_char_pointer; - const_void_pointer void_p = boost::intrusive::pointer_traits:: - pointer_to(*m_storage_start.data); - return boost::intrusive::pointer_traits::static_cast_from(void_p); - } + { return this->base_type::get_stored_allocator().internal_storage(); } BOOST_CONTAINER_FORCEINLINE pointer internal_storage() BOOST_NOEXCEPT_OR_NOTHROW - { - typedef typename boost::intrusive::pointer_traits::template - rebind_pointer::type char_pointer; - void_pointer void_p = boost::intrusive::pointer_traits:: - pointer_to(*m_storage_start.data); - return boost::intrusive::pointer_traits::static_cast_from(void_p); - } + { return this->base_type::get_stored_allocator().internal_storage(); } + private: base_type &as_base() { return static_cast(*this); } const base_type &as_base() const { return static_cast(*this); } - static const std::size_t final_alignment = - options_t::inplace_alignment ? options_t::inplace_alignment : dtl::alignment_of::value; public: - typedef typename dtl::aligned_storage - ::type storage_type; - protected: BOOST_CONTAINER_FORCEINLINE explicit small_vector_base(initial_capacity_t, std::size_t initial_capacity) @@ -433,11 +388,6 @@ class small_vector_base {} //~small_vector_base(){} - - private: - //The only member - storage_type m_storage_start; - #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED public: @@ -469,67 +419,74 @@ class small_vector_base #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED -///////////////////////////////////////////////////// -// -// small_vector_storage_calculator -// -///////////////////////////////////////////////////// -template -struct small_vector_storage_calculator_helper -{ - static const std::size_t value = (Needed - Hdr - 1u)/SSize + 1u; -}; - -template -struct small_vector_storage_calculator_helper -{ - static const std::size_t value = 0u; -}; - -template -struct small_vector_storage_calculator -{ - typedef small_vector_base svh_type; - typedef typename real_allocator::type value_allocator_t; - typedef typename allocator_traits::template portable_rebind_alloc::type void_allocator_t; - typedef typename dtl::vector_for_small_vector::type svhb_type; - - static const std::size_t s_align = dtl::alignment_of::value; - static const std::size_t s_size = sizeof(Storage); - static const std::size_t svh_sizeof = sizeof(svh_type); - static const std::size_t svhb_sizeof = sizeof(svhb_type); - static const std::size_t s_start = ((svhb_sizeof-1)/s_align+1)*s_align; - static const std::size_t header_bytes = svh_sizeof-s_start; - static const std::size_t needed_bytes = sizeof(T)*N; - static const std::size_t needed_extra_storages = - small_vector_storage_calculator_helper::value; -}; - ///////////////////////////////////////////////////// // // small_vector_storage_definer // ///////////////////////////////////////////////////// -template -struct small_vector_storage -{ - Storage m_rest_of_storage[N]; -}; - -template -struct small_vector_storage -{}; - -template +template struct small_vector_storage_definer { - typedef T value_type; - typedef typename small_vector_base::storage_type storage_type; - static const std::size_t needed_extra_storages = - small_vector_storage_calculator::needed_extra_storages; - typedef small_vector_storage type; + typedef typename dtl::get_small_vector_opt::type options_t; + static const std::size_t final_alignment = + options_t::inplace_alignment ? options_t::inplace_alignment : dtl::alignment_of::value; + typedef small_vector_storage type; }; +template +struct small_vector_storage_strawman + : public small_vector_base + , public small_vector_storage_definer::type +{ + typedef typename small_vector_storage_definer::type sm_storage_t; +}; + +//Internal storage hack +template +BOOST_CONTAINER_FORCEINLINE typename small_vector_allocator::const_pointer + small_vector_allocator::internal_storage() const BOOST_NOEXCEPT_OR_NOTHROW +{ + typedef small_vector_storage_strawman strawman_t; + typedef typename strawman_t::sm_storage_t sm_storage_t; + + #if defined(BOOST_GCC) && (BOOST_GCC >= 40600) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-align" + #endif + const vector_type& v = reinterpret_cast(*this); + BOOST_ASSERT((std::size_t(this) % dtl::alignment_of::value) == 0); + #if defined(BOOST_GCC) && (BOOST_GCC >= 40600) + #pragma GCC diagnostic pop + #endif + + const strawman_t &straw = static_cast(v); + const sm_storage_t& stor = static_cast(straw); + return boost::intrusive::pointer_traits::pointer_to(*((T*)&stor.m_storage)); +} + +template +BOOST_CONTAINER_FORCEINLINE typename small_vector_allocator::pointer + small_vector_allocator::internal_storage() BOOST_NOEXCEPT_OR_NOTHROW +{ + typedef small_vector_storage_strawman strawman_t; + typedef typename strawman_t::sm_storage_t sm_storage_t; + + #if defined(BOOST_GCC) && (BOOST_GCC >= 40600) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-align" + #endif + vector_type& v = reinterpret_cast(*this); + BOOST_ASSERT((std::size_t(this) % dtl::alignment_of::value) == 0); + #if defined(BOOST_GCC) && (BOOST_GCC >= 40600) + #pragma GCC diagnostic pop + #endif + + strawman_t &straw = static_cast(v); + sm_storage_t& stor = static_cast(straw); + return boost::intrusive::pointer_traits::pointer_to(*((T*)&stor.m_storage)); +} + + #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED //! small_vector is a vector-like container optimized for the case when it contains few elements. @@ -547,41 +504,31 @@ struct small_vector_storage_definer //! for the default allocator //! |tparam Options A type produced from \c boost::container::small_vector_options. template -class small_vector : public small_vector_base +class small_vector + : public small_vector_base #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED - , private small_vector_storage_definer::type + , private small_vector_storage_definer::type #endif { #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED - typedef small_vector_base base_type; - typedef typename small_vector_storage_definer - ::type remaining_storage_holder; BOOST_COPYABLE_AND_MOVABLE(small_vector) - typedef allocator_traits allocator_traits_type; - public: - typedef small_vector_storage_calculator - < typename small_vector_base::storage_type - , Allocator, T, N, Options> storage_test; - - static const std::size_t needed_extra_storages = storage_test::needed_extra_storages; - static const std::size_t needed_bytes = storage_test::needed_bytes; - static const std::size_t header_bytes = storage_test::header_bytes; - static const std::size_t s_start = storage_test::s_start; - + typedef small_vector_base base_type; typedef typename base_type::allocator_type allocator_type; typedef typename base_type::size_type size_type; typedef typename base_type::value_type value_type; BOOST_CONTAINER_FORCEINLINE static std::size_t internal_capacity() - { return (sizeof(small_vector) - storage_test::s_start)/sizeof(T); } + { return static_capacity; } + + typedef allocator_traits allocator_traits_type; #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED //! @brief The capacity/max size of the container - static const size_type static_capacity = N; + static const size_type static_capacity = small_vector_storage_definer::type::sms_size; public: BOOST_CONTAINER_FORCEINLINE small_vector()