Added stored_size option to small_vector

This commit is contained in:
Ion Gaztañaga 2024-10-13 00:29:12 +02:00
parent 13603d7de1
commit af58c7d226
5 changed files with 81 additions and 8 deletions

View File

@ -803,6 +803,12 @@ the last template parameter and defined using the utility class
[classref boost::container::growth_factor_60 growth_factor_60] and
[classref boost::container::growth_factor_50 growth_factor_100].
* [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 maximum capacity to be used is much less than the
theoretical maximum that a vector can hold, it's interesting to use smaller unsigned integer types to represent
`size()` and `capacity()` inside 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::small_vector_options small_vector_options] can be
used to customize `small_vector`:
@ -1417,7 +1423,9 @@ 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].
* Added [classref boost::container::stored_size stored_size] option to
[classref boost::container::static_vector static_vector] and
[classref boost::container::small_vector small_vector].
* Fixed bugs/issues:
* [@https://github.com/boostorg/container/issues/261 GitHub #261: ['"End iterators are not dereferencable"]].

View File

@ -41,6 +41,14 @@ int main ()
growth_50_vector.push_back(1);
assert(growth_50_vector.capacity() == old_cap*3/2);
//This option specifies that a vector that will use "unsigned char" as
//the type to store capacity or size internally.
typedef small_vector_options< stored_size<unsigned char> >::type size_option_t;
//Size-optimized vector is smaller than the default one.
typedef small_vector<int, 10, new_allocator<int>, size_option_t > size_optimized_vector_t;
assert((sizeof(size_optimized_vector_t) < sizeof(small_vector<int, 10>)));
return 0;
}
//]

View File

@ -359,20 +359,23 @@ BOOST_INTRUSIVE_OPTION_CONSTANT(inplace_alignment, std::size_t, Alignment, inpla
#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
template<class GrowthType, std::size_t InplaceAlignment>
template<class GrowthType, std::size_t InplaceAlignment, class StoredSizeType>
struct small_vector_opt
{
typedef GrowthType growth_factor_type;
typedef GrowthType growth_factor_type;
BOOST_STATIC_CONSTEXPR std::size_t inplace_alignment = InplaceAlignment;
typedef StoredSizeType stored_size_type;
};
typedef small_vector_opt<void, 0u> small_vector_null_opt;
typedef small_vector_opt<void, 0u, void> small_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::small_vector.
//! Supported options are: \c boost::container::growth_factor and \c boost::container::inplace_alignment
//! Supported options are: \c boost::container::growth_factor,
//! \c boost::container::inplace_alignment and
//! \c boost::container::stored_size.
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) || defined(BOOST_CONTAINER_VARIADIC_TEMPLATES)
template<class ...Options>
#else
@ -390,7 +393,9 @@ struct small_vector_options
#endif
>::type packed_options;
typedef small_vector_opt< typename packed_options::growth_factor_type
, packed_options::inplace_alignment> implementation_defined;
, packed_options::inplace_alignment
, typename packed_options::stored_size_type
> implementation_defined;
/// @endcond
typedef implementation_defined type;
};

View File

@ -69,7 +69,9 @@ struct get_vopt_from_svopt
: get_small_vector_opt<Options>::type
{
typedef typename get_small_vector_opt<Options>::type options_t;
typedef vector_opt< typename options_t::growth_factor_type, void> type;
typedef vector_opt< typename options_t::growth_factor_type
, typename options_t::stored_size_type
> type;
};
template<>
@ -340,9 +342,11 @@ struct small_vector_storage<T, 0u, Alignment>
//!
template <class T, class SecAlloc, class Options>
class small_vector_base
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
: public dtl::vector_for_small_vector<T, SecAlloc, Options>::type
#endif
{
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKEDVECTOR
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
public:
//Make it public as it will be inherited by small_vector and container
//must have this public member

View File

@ -8,6 +8,7 @@
//
//////////////////////////////////////////////////////////////////////////////
#include <boost/container/small_vector.hpp>
#include <boost/container/allocator.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/assert.hpp>
using namespace boost::container;
@ -100,11 +101,58 @@ void test_growth_factor_100()
BOOST_TEST(new_capacity == 2*old_capacity);
}
template<class Unsigned, class VectorType>
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<class Unsigned>
void test_stored_size_type()
{
#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
using options_t = small_vector_options_t< stored_size<Unsigned> >;
#else
typedef typename small_vector_options
< stored_size<Unsigned> >::type options_t;
#endif
typedef small_vector<unsigned char, Unsigned(-1)> normal_small_vector_t;
//Test first with a typical allocator
{
typedef small_vector<unsigned char, Unsigned(-1), new_allocator<unsigned char>, options_t> small_vector_t;
test_stored_size_type_impl<Unsigned, small_vector_t>();
BOOST_CONTAINER_STATIC_ASSERT(sizeof(normal_small_vector_t) > sizeof(small_vector_t));
}
//Test with a V2 allocator
{
typedef small_vector<unsigned char, Unsigned(-1), allocator<unsigned char>, options_t> small_vector_t;
test_stored_size_type_impl<Unsigned, small_vector_t>();
BOOST_CONTAINER_STATIC_ASSERT(sizeof(normal_small_vector_t) > sizeof(small_vector_t));
}
}
int main()
{
test_alignment();
test_growth_factor_50();
test_growth_factor_60();
test_growth_factor_100();
test_stored_size_type<unsigned char>();
test_stored_size_type<unsigned short>();
return ::boost::report_errors();
}