From 13603d7de15d8b410743173664cd579d38e221a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 12 Oct 2024 23:22:59 +0200 Subject: [PATCH] Added `stored_size` option to `static_vector` --- doc/container.qbk | 8 +++++ example/doc_custom_static_vector.cpp | 8 +++++ include/boost/container/options.hpp | 23 +++++++------ include/boost/container/static_vector.hpp | 24 ++++++++++++-- include/boost/container/vector.hpp | 4 +-- test/static_vector_options_test.cpp | 40 +++++++++++++++++++++++ 6 files changed, 90 insertions(+), 17 deletions(-) diff --git a/doc/container.qbk b/doc/container.qbk index 4de66bf8..4bd752be 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -770,6 +770,12 @@ the last template parameter and defined using the utility class of objects. When "false", if the capacit is overflowed, the implementation calls to BOOST_ASSERT and if that assertion does not throw or abort, undefined behavior is triggered. +* [classref boost::container::stored_size stored_size]: the type that will be used to store size-related + parameters inside of the vector. Sometimes, when the static to be used is much less than `std::size_t` + it's interesting to use a smaller unsigned integer types to represent `size()` inside `static_vector``, + so that the size of an empty vector is minimized and cache + performance might be improved. See [classref boost::container::stored_size stored_size] for more details. + See the following example to see how [classref boost::container::static_vector_options static_vector_options] can be used to customize `static_vector`: @@ -1411,6 +1417,8 @@ use [*Boost.Container]? There are several reasons for that: [section:release_notes_boost_1_87_00 Boost 1.87 Release] +* Added [classref boost::container::stored_size stored_size] option to [classref boost::container::static_vector static_vector]. + * Fixed bugs/issues: * [@https://github.com/boostorg/container/issues/261 GitHub #261: ['"End iterators are not dereferencable"]]. * [@https://github.com/boostorg/container/issues/288 GitHub #288: ['"Compile error when using flat_map::extract_sequence with small_vector"]]. diff --git a/example/doc_custom_static_vector.cpp b/example/doc_custom_static_vector.cpp index 3d62b079..0317a8a0 100644 --- a/example/doc_custom_static_vector.cpp +++ b/example/doc_custom_static_vector.cpp @@ -33,6 +33,14 @@ int main () //Create static_vector with no throw on overflow static_vector sv2; + //This options specifies that internal `size()` can be represented by an unsigned char + //instead of the default `std::size_t`. + typedef static_vector_options< stored_size >::type stored_size_uchar_t; + + //Create static_vector that internally stores `size()` in an unsigned char + //because `capacity()` will be less thatn 256. + static_vector sv3; + return 0; } //] diff --git a/include/boost/container/options.hpp b/include/boost/container/options.hpp index dad41b7a..b467db1f 100644 --- a/include/boost/container/options.hpp +++ b/include/boost/container/options.hpp @@ -289,8 +289,8 @@ BOOST_INTRUSIVE_OPTION_TYPE(growth_factor, GrowthFactor, GrowthFactor, growth_fa //! //!If the maximum capacity() to be used is limited, a user can try to use 8-bit, 16-bit //!(e.g. in 32-bit machines), or 32-bit size types (e.g. in a 64 bit machine) to see if some -//!memory can be saved for empty vectors. This could potentially performance benefits due to better -//!cache usage. +//!memory can be saved, specially for empty containers. This could potentially improve performance +//!due to better cache usage. //! //!Note that alignment requirements can disallow theoretical space savings. Example: //!\c vector holds a pointer and two size types (for size and capacity), in a 32 bit machine @@ -301,7 +301,7 @@ BOOST_INTRUSIVE_OPTION_TYPE(growth_factor, GrowthFactor, GrowthFactor, growth_fa //!Measure the size of the resulting container and do not assume a smaller \c stored_size //!will always lead to a smaller sizeof(container). //! -//!If a user tries to insert more elements than representable by \c stored_size, vector +//!If a user tries to insert more elements than representable by \c stored_size, the container //!will throw a length_error. //! //!If this option is not specified, `allocator_traits::size_type` (usually std::size_t) will @@ -337,7 +337,6 @@ struct vector_options //! Helper alias metafunction to combine options into a single type to be used //! by \c boost::container::vector. -//! Supported options are: \c boost::container::growth_factor and \c boost::container::stored_size template using vector_options_t = typename boost::container::vector_options::type; @@ -400,7 +399,6 @@ struct small_vector_options //! Helper alias metafunction to combine options into a single type to be used //! by \c boost::container::small_vector. -//! Supported options are: \c boost::container::growth_factor and \c boost::container::stored_size template using small_vector_options_t = typename boost::container::small_vector_options::type; @@ -427,20 +425,22 @@ BOOST_INTRUSIVE_OPTION_CONSTANT(throw_on_overflow, bool, ThrowOnOverflow, throw_ #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) -template +template struct static_vector_opt { BOOST_STATIC_CONSTEXPR bool throw_on_overflow = ThrowOnOverflow; BOOST_STATIC_CONSTEXPR std::size_t inplace_alignment = InplaceAlignment; + typedef StoredSizeType stored_size_type; }; -typedef static_vector_opt static_vector_null_opt; +typedef static_vector_opt static_vector_null_opt; #endif //!defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Helper metafunction to combine options into a single type to be used //! by \c boost::container::static_vector. -//! Supported options are: \c boost::container::throw_on_overflow and \c boost::container::inplace_alignment +//! Supported options are: \c boost::container::throw_on_overflow, \c boost::container::inplace_alignment +//! and \c boost::container::stored_size. #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) || defined(BOOST_CONTAINER_VARIADIC_TEMPLATES) template #else @@ -458,7 +458,9 @@ struct static_vector_options #endif >::type packed_options; typedef static_vector_opt< packed_options::throw_on_overflow - , packed_options::inplace_alignment> implementation_defined; + , packed_options::inplace_alignment + , typename packed_options::stored_size_type + > implementation_defined; /// @endcond typedef implementation_defined type; }; @@ -467,7 +469,6 @@ struct static_vector_options //! Helper alias metafunction to combine options into a single type to be used //! by \c boost::container::static_vector. -//! Supported options are: \c boost::container::growth_factor and \c boost::container::stored_size template using static_vector_options_t = typename boost::container::static_vector_options::type; @@ -587,7 +588,6 @@ struct devector_options //! Helper alias metafunction to combine options into a single type to be used //! by \c boost::container::devector. -//! Supported options are: \c boost::container::growth_factor and \c boost::container::stored_size template using devector_options_t = typename boost::container::devector_options::type; @@ -643,7 +643,6 @@ struct deque_options //! Helper alias metafunction to combine options into a single type to be used //! by \c boost::container::deque. -//! Supported options are: \c boost::container::block_bytes template using deque_options_t = typename boost::container::deque_options::type; diff --git a/include/boost/container/static_vector.hpp b/include/boost/container/static_vector.hpp index 1406fdb7..40399120 100644 --- a/include/boost/container/static_vector.hpp +++ b/include/boost/container/static_vector.hpp @@ -102,6 +102,19 @@ struct get_static_vector_opt typedef static_vector_null_opt type; }; +template +struct get_vector_opt_from_static_vector_opt +{ + typedef typename get_static_vector_opt::type options_t; + typedef vector_opt type; +}; + +template<> +struct get_vector_opt_from_static_vector_opt +{ + typedef void type; +}; + template struct get_static_vector_allocator { @@ -114,7 +127,6 @@ struct get_static_vector_allocator > type; }; - } //namespace dtl { #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED @@ -148,12 +160,18 @@ struct get_static_vector_allocator //! is specified, by default throw_on_overflow option is set. template class static_vector - : public vector::type> + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + : public vector< T + , typename dtl::get_static_vector_allocator< T, Capacity, Options>::type + , typename dtl::get_vector_opt_from_static_vector_opt::type + > + #endif { public: #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED typedef typename dtl::get_static_vector_allocator< T, Capacity, Options>::type allocator_type; - typedef vector base_t; + typedef typename dtl::get_vector_opt_from_static_vector_opt::type options_type; + typedef vector base_t; BOOST_COPYABLE_AND_MOVABLE(static_vector) diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index 57020d1c..959a4f08 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -643,7 +643,7 @@ struct vector_alloc_holder template vector_alloc_holder(vector_uninitialized_size_t, BOOST_FWD_REF(AllocConvertible) a, size_type initial_size) : allocator_type(boost::forward(a)) - , m_size(initial_size) //Size is initialized here... + , m_size(static_cast(initial_size)) //Size is initialized here... { //... and capacity here, so vector, must call uninitialized_xxx in the derived constructor this->priv_first_allocation(initial_size); @@ -652,7 +652,7 @@ struct vector_alloc_holder //Constructor, does not throw vector_alloc_holder(vector_uninitialized_size_t, size_type initial_size) : allocator_type() - , m_size(initial_size) //Size is initialized here... + , m_size(static_cast(initial_size)) //Size is initialized here... { //... and capacity here, so vector, must call uninitialized_xxx in the derived constructor this->priv_first_allocation(initial_size); diff --git a/test/static_vector_options_test.cpp b/test/static_vector_options_test.cpp index 25b8e824..05860af1 100644 --- a/test/static_vector_options_test.cpp +++ b/test/static_vector_options_test.cpp @@ -131,9 +131,49 @@ void test_throw_on_overflow() #endif } +template +void test_stored_size_type_impl() +{ + #ifndef BOOST_NO_EXCEPTIONS + VectorType v; + typedef typename VectorType::size_type size_type; + typedef typename VectorType::value_type value_type; + size_type const max = Unsigned(-1); + v.resize(5); + v.resize(max); + BOOST_TEST_THROWS(v.resize(max+1), std::exception); + BOOST_TEST_THROWS(v.push_back(value_type(1)), std::exception); + BOOST_TEST_THROWS(v.insert(v.begin(), value_type(1)), std::exception); + BOOST_TEST_THROWS(v.emplace(v.begin(), value_type(1)),std::exception); + BOOST_TEST_THROWS(v.reserve(max+1), std::exception); + BOOST_TEST_THROWS(VectorType v2(max+1), std::exception); + #endif +} + +template +void test_stored_size_type() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = static_vector_options_t< stored_size >; + #else + typedef typename static_vector_options + < stored_size >::type options_t; + #endif + + typedef static_vector normal_static_vector_t; + + { + typedef static_vector static_vector_t; + BOOST_CONTAINER_STATIC_ASSERT(sizeof(normal_static_vector_t) > sizeof(static_vector_t)); + test_stored_size_type_impl(); + } +} + int main() { test_alignment(); test_throw_on_overflow(); + test_stored_size_type(); + test_stored_size_type(); return ::boost::report_errors(); }