Skip to content

Commit

Permalink
Added stored_size option to small_vector
Browse files Browse the repository at this point in the history
  • Loading branch information
igaztanaga committed Oct 12, 2024
1 parent 13603d7 commit af58c7d
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 8 deletions.
10 changes: 9 additions & 1 deletion doc/container.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -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`:

Expand Down Expand Up @@ -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"]].
Expand Down
8 changes: 8 additions & 0 deletions example/doc_custom_small_vector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
//]
15 changes: 10 additions & 5 deletions include/boost/container/options.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
};
Expand Down
8 changes: 6 additions & 2 deletions include/boost/container/small_vector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<>
Expand Down Expand Up @@ -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
Expand Down
48 changes: 48 additions & 0 deletions test/small_vector_options_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
}

0 comments on commit af58c7d

Please sign in to comment.