mirror of
https://github.com/boostorg/container.git
synced 2026-02-24 16:02:22 +00:00
Add "inline_chars" option to basic_string
This commit is contained in:
@@ -882,6 +882,12 @@ the last template parameter and defined using the utility class
|
||||
small string optimization buffer might be reduced in size if a smaller than `std::size_t` `stored_size` unsigned
|
||||
type is used.
|
||||
|
||||
* [classref boost::container::inline_chars inline_chars]: the number of characters (excluding terminating null) that
|
||||
will be stored inside `basic_string` (small string optimization) before using dynamic allocation. Due to internal
|
||||
data structure limitations, this value must be equal or less than 127. The implementation will guarantee at least
|
||||
that number of characters in the internal buffer, but it might be more depending on alignment issues and the `stored_size`
|
||||
option.
|
||||
|
||||
See the following example to see how [classref boost::container::string_options string_options] can be
|
||||
used to customize `string_options`:
|
||||
|
||||
@@ -1472,6 +1478,10 @@ use [*Boost.Container]? There are several reasons for that:
|
||||
* Added C++20 `starts_with`/`ends_with` and C++23 `contains` overloads.
|
||||
* Added null pointer checks for `basic_string` methods taking `const CharT*` parameters.
|
||||
* Deleted constructor from `std::nullptr_t`.
|
||||
* Added [classref boost::container::inline_chars inline_chars],
|
||||
[classref boost::container::growth_factor growth_factor] and
|
||||
[classref boost::container::stored_size stored_size] options to [classref boost::container::basic_string basic_string].
|
||||
|
||||
* Fixed bugs/issues:
|
||||
* [@https://github.com/boostorg/container/issues/323 GitHub #323: ['"flat_tree::try_emplace UB"]].
|
||||
* [@https://github.com/boostorg/container/issues/328 GitHub #328: ['"boost::container::deque stores a redundant copy of the allocator, increasing size"]].
|
||||
|
||||
@@ -20,6 +20,10 @@ int main ()
|
||||
{
|
||||
using namespace boost::container;
|
||||
|
||||
//--------------------------
|
||||
// Option "stored_size"
|
||||
//--------------------------
|
||||
|
||||
//This option specifies that a string that will use "unsigned char" as
|
||||
//the type to store capacity or size internally.
|
||||
typedef string_options< stored_size<unsigned char> >::type size_option_t;
|
||||
@@ -37,16 +41,36 @@ int main ()
|
||||
bool exception_thrown = false;
|
||||
/*<-*/
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
BOOST_CONTAINER_TRY{ size_optimized_string_t v(127, '\0');} BOOST_CONTAINER_CATCH(...) { exception_thrown = true; } BOOST_CONTAINER_CATCH_END
|
||||
BOOST_CONTAINER_TRY{ size_optimized_string_t v(127, 'a');} BOOST_CONTAINER_CATCH(...) { exception_thrown = true; } BOOST_CONTAINER_CATCH_END
|
||||
#else
|
||||
exception_thrown = true;
|
||||
#endif //BOOST_NO_EXCEPTIONS
|
||||
/*->*/
|
||||
//=try { size_optimized_string_t v(127, '\0'); }
|
||||
//=try { size_optimized_string_t v(127, 'a'); }
|
||||
//=catch(...){ exception_thrown = true; }
|
||||
|
||||
assert(exception_thrown == true);
|
||||
|
||||
//--------------------------
|
||||
// Option "inline_chars"
|
||||
//--------------------------
|
||||
|
||||
//This option specifies the capacity of the internally stored buffer
|
||||
//The maximum value due to internal data organization is 127 chars
|
||||
typedef string_options< inline_chars<100> >::type inline_chars_option_t;
|
||||
typedef basic_string<char, std::char_traits<char>, void, inline_chars_option_t > inline100_string_t;
|
||||
|
||||
//The size of the object will grow accordingly
|
||||
assert(( sizeof(inline100_string_t) > sizeof(basic_string<char>) ));
|
||||
assert(( sizeof(inline100_string_t) > 100 ));
|
||||
|
||||
//Internal capacity will be at least the specified one
|
||||
assert((inline100_string_t().capacity() >= 100));
|
||||
|
||||
//--------------------------
|
||||
// Option "growth_factor"
|
||||
//--------------------------
|
||||
|
||||
//This option specifies that a string will increase its capacity 50%
|
||||
//each time the previous capacity was exhausted.
|
||||
typedef string_options< growth_factor<growth_factor_50> >::type growth_50_option_t;
|
||||
|
||||
@@ -244,11 +244,12 @@ class default_next_capacity;
|
||||
|
||||
typedef vector_opt<void, void> vector_null_opt;
|
||||
|
||||
template<class GrowthType, class StoredSizeType>
|
||||
template<class GrowthType, class StoredSizeType, std::size_t InlineChars>
|
||||
struct string_opt
|
||||
{
|
||||
typedef GrowthType growth_factor_type;
|
||||
typedef StoredSizeType stored_size_type;
|
||||
static const std::size_t inline_chars = InlineChars;
|
||||
|
||||
template<class AllocTraits>
|
||||
struct get_stored_size_type
|
||||
@@ -256,7 +257,7 @@ struct string_opt
|
||||
{};
|
||||
};
|
||||
|
||||
typedef string_opt<void, void> string_null_opt;
|
||||
typedef string_opt<void, void, 0u> string_null_opt;
|
||||
|
||||
struct growth_factor_50;
|
||||
|
||||
@@ -695,6 +696,24 @@ using deque_options_t = typename boost::container::deque_options<Options...>::ty
|
||||
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
//
|
||||
// OPTIONS FOR STRING CONTAINER
|
||||
//
|
||||
//
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
//! This option specifies the desired number of characters to be hold inline
|
||||
//! in the container.
|
||||
//!
|
||||
//! A value zero represents the default value
|
||||
//! (typically 10 chars in 32-bit systems and 22 chars in 64-bit systems).
|
||||
//!
|
||||
//!\tparam InlineChars An unsigned integer value. Values greater than 127 are not supported
|
||||
//! duet to the internal data structure design.
|
||||
BOOST_INTRUSIVE_OPTION_CONSTANT(inline_chars, std::size_t, InlineChars, inline_chars)
|
||||
|
||||
//! Helper metafunction to combine options into a single type to be used
|
||||
//! by \c boost::container::string.
|
||||
//! Supported options are: \c boost::container::growth_factor and \c boost::container::stored_size
|
||||
@@ -715,7 +734,9 @@ struct string_options
|
||||
#endif
|
||||
>::type packed_options;
|
||||
typedef string_opt< typename packed_options::growth_factor_type
|
||||
, typename packed_options::stored_size_type> implementation_defined;
|
||||
, typename packed_options::stored_size_type
|
||||
, packed_options::inline_chars
|
||||
> implementation_defined;
|
||||
/// @endcond
|
||||
typedef implementation_defined type;
|
||||
};
|
||||
|
||||
@@ -80,13 +80,14 @@ struct get_string_opt
|
||||
{
|
||||
typedef string_opt< typename default_if_void<typename Options::growth_factor_type, growth_factor_60>::type
|
||||
, typename default_if_void<typename Options::stored_size_type, AllocatorSizeType>::type
|
||||
, Options::inline_chars
|
||||
> type;
|
||||
};
|
||||
|
||||
template<class AllocatorSizeType>
|
||||
struct get_string_opt<void, AllocatorSizeType>
|
||||
{
|
||||
typedef string_opt<growth_factor_60, AllocatorSizeType> type;
|
||||
typedef string_opt<growth_factor_60, AllocatorSizeType, 0u> type;
|
||||
};
|
||||
|
||||
namespace dtl {
|
||||
@@ -123,6 +124,8 @@ class basic_string_base
|
||||
|
||||
typedef ::boost::intrusive::pointer_traits<pointer> pointer_traits;
|
||||
|
||||
static const std::size_t inline_chars = options_type::inline_chars;
|
||||
|
||||
inline basic_string_base()
|
||||
: members_()
|
||||
{}
|
||||
@@ -209,24 +212,43 @@ class basic_string_base
|
||||
|
||||
//This type has the same alignment and size as long_t but it's POD
|
||||
//so, unlike long_t, it can be placed in a union
|
||||
|
||||
typedef typename dtl::aligned_storage
|
||||
<sizeof(long_t), dtl::alignment_of<long_t>::value>::type long_raw_t;
|
||||
|
||||
template <std::size_t NChar>
|
||||
union short_type_test
|
||||
{
|
||||
long_raw_t l;
|
||||
struct short_t
|
||||
{
|
||||
short_header h;
|
||||
value_type data[NChar+1u];
|
||||
} s;
|
||||
};
|
||||
|
||||
protected:
|
||||
BOOST_STATIC_CONSTEXPR size_type MinInternalBufferChars = 0;
|
||||
BOOST_STATIC_CONSTEXPR size_type AlignmentOfValueType = alignment_of<value_type>::value;
|
||||
BOOST_STATIC_CONSTEXPR size_type ShortDataOffset = ((sizeof(short_header)-1)/AlignmentOfValueType+1)*AlignmentOfValueType;
|
||||
BOOST_STATIC_CONSTEXPR size_type ZeroCostInternalBufferChars =
|
||||
(sizeof(long_t) - ShortDataOffset)/sizeof(value_type);
|
||||
BOOST_STATIC_CONSTEXPR size_type UnalignedFinalInternalBufferChars =
|
||||
(ZeroCostInternalBufferChars > MinInternalBufferChars) ?
|
||||
ZeroCostInternalBufferChars : MinInternalBufferChars;
|
||||
//Due to internal data representation constraints, inline chars cannot be bigger than this
|
||||
BOOST_STATIC_CONSTEXPR size_type MaxInlineChars = 127u;
|
||||
BOOST_CONTAINER_STATIC_ASSERT(inline_chars <= MaxInlineChars);
|
||||
|
||||
BOOST_STATIC_CONSTEXPR size_type SizeOfValueType = sizeof(value_type);
|
||||
BOOST_STATIC_CONSTEXPR size_type ShortDataOffset = ((sizeof(short_header)-1)/SizeOfValueType+1)*SizeOfValueType;
|
||||
BOOST_STATIC_CONSTEXPR size_type ZeroCostInternalStorage = (sizeof(long_t) - ShortDataOffset)/sizeof(value_type);
|
||||
BOOST_STATIC_CONSTEXPR size_type InlineCharsStorage = (sizeof(short_type_test<inline_chars>) - ShortDataOffset)/sizeof(value_type);
|
||||
|
||||
//Select the biggest internal buffer between zero-cost SSO and user-requested SSO
|
||||
BOOST_STATIC_CONSTEXPR size_type CandidateInternalStorageChars =
|
||||
ZeroCostInternalStorage > InlineCharsStorage ? ZeroCostInternalStorage : InlineCharsStorage;
|
||||
|
||||
//Clamp internal buffer chars to MaxInlineChars
|
||||
BOOST_STATIC_CONSTEXPR size_type MaxInlineStorage = MaxInlineChars+1u;
|
||||
BOOST_STATIC_CONSTEXPR size_type FinalInternalStorage =
|
||||
CandidateInternalStorageChars < MaxInlineStorage ? CandidateInternalStorageChars : MaxInlineStorage;
|
||||
|
||||
struct short_t
|
||||
{
|
||||
short_header h;
|
||||
value_type data[UnalignedFinalInternalBufferChars];
|
||||
value_type data[FinalInternalStorage];
|
||||
};
|
||||
|
||||
union repr_t_size_t
|
||||
@@ -282,7 +304,7 @@ class basic_string_base
|
||||
inline allocator_type &alloc()
|
||||
{ return members_; }
|
||||
|
||||
BOOST_STATIC_CONSTEXPR size_type InternalBufferChars = (sizeof(repr_t) - ShortDataOffset)/sizeof(value_type);
|
||||
BOOST_STATIC_CONSTEXPR size_type InternalBufferChars = FinalInternalStorage;
|
||||
|
||||
private:
|
||||
|
||||
@@ -581,6 +603,7 @@ class basic_string_base
|
||||
//! \tparam CharT The type of character it contains.
|
||||
//! \tparam Traits The Character Traits type, which encapsulates basic character operations
|
||||
//! \tparam Allocator The allocator, used for internal memory management.
|
||||
//! \tparam Options A type produced from \c boost::container::string_options.
|
||||
#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED
|
||||
template <class CharT, class Traits = std::char_traits<CharT>, class Allocator = void, class Options = void >
|
||||
#else
|
||||
|
||||
Reference in New Issue
Block a user