From d4e38179fcc494a4de57e477ca05607b7d691dea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 24 Jan 2026 11:08:28 +0100 Subject: [PATCH] Add options "stored_size" and "growth_factor" options to string. Make string's default growth factor the same as vector's (60%) --- include/boost/container/container_fwd.hpp | 5 +- .../boost/container/detail/next_capacity.hpp | 10 +- include/boost/container/options.hpp | 54 +++ include/boost/container/string.hpp | 356 ++++++++++-------- include/boost/container/vector.hpp | 3 - test/string_options_test.cpp | 142 +++++++ 6 files changed, 407 insertions(+), 163 deletions(-) create mode 100644 test/string_options_test.cpp diff --git a/include/boost/container/container_fwd.hpp b/include/boost/container/container_fwd.hpp index 2525b7d..b09342e 100644 --- a/include/boost/container/container_fwd.hpp +++ b/include/boost/container/container_fwd.hpp @@ -272,8 +272,9 @@ struct small_flat_multimap_of }; template - ,class Allocator = void > + ,class Traits = std::char_traits + ,class Allocator = void + ,class Options = void > class basic_string; typedef basic_string string; diff --git a/include/boost/container/detail/next_capacity.hpp b/include/boost/container/detail/next_capacity.hpp index 76bf0a0..2b51993 100644 --- a/include/boost/container/detail/next_capacity.hpp +++ b/include/boost/container/detail/next_capacity.hpp @@ -84,10 +84,18 @@ inline void clamp_by_stored_size_type(SizeType &, SizeType) template inline void clamp_by_stored_size_type(SizeType &s, SomeStoredSizeType) { - if (s >= SomeStoredSizeType(-1) ) + if (s > SomeStoredSizeType(-1) ) s = SomeStoredSizeType(-1); } +template +inline void clamp_by_half_stored_size_type(SizeType &s, SomeStoredSizeType) +{ + const SizeType half_max = SizeType(SomeStoredSizeType(-1)) >> 1u; + if (s > half_max ) + s = half_max; +} + } //namespace container { } //namespace boost { diff --git a/include/boost/container/options.hpp b/include/boost/container/options.hpp index 1a9bda9..f5fdd4a 100644 --- a/include/boost/container/options.hpp +++ b/include/boost/container/options.hpp @@ -244,6 +244,26 @@ class default_next_capacity; typedef vector_opt vector_null_opt; +template +struct string_opt +{ + typedef GrowthType growth_factor_type; + typedef StoredSizeType stored_size_type; + + template + struct get_stored_size_type + : get_stored_size_type_with_alloctraits + {}; +}; + +typedef string_opt string_null_opt; + +struct growth_factor_50; + +struct growth_factor_60; + +struct growth_factor_100; + #else //!This growth factor argument specifies that the container should increase its @@ -674,6 +694,40 @@ using deque_options_t = typename boost::container::deque_options::ty #endif +//! 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 +#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) || defined(BOOST_CONTAINER_VARIADIC_TEMPLATES) +template +#else +template +#endif +struct string_options +{ + /// @cond + typedef typename ::boost::intrusive::pack_options + < string_null_opt, + #if !defined(BOOST_CONTAINER_VARIADIC_TEMPLATES) + O1, O2, O3, O4 + #else + Options... + #endif + >::type packed_options; + typedef string_opt< typename packed_options::growth_factor_type + , typename packed_options::stored_size_type> implementation_defined; + /// @endcond + typedef implementation_defined type; +}; + +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + +//! Helper alias metafunction to combine options into a single type to be used +//! by \c boost::container::string. +template +using string_options_t = typename boost::container::string_options::type; + +#endif + //!This option specifies the maximum size of a block in bytes: this delimites the number of contiguous elements //!that will be allocated by some containers as min(1u, BlockBytes/sizeof(value_type)) //!A value zero represents the default value. diff --git a/include/boost/container/string.hpp b/include/boost/container/string.hpp index d8df11d..d8707ca 100644 --- a/include/boost/container/string.hpp +++ b/include/boost/container/string.hpp @@ -26,6 +26,7 @@ #include #include //new_allocator #include +#include // container/detail #include #include @@ -73,6 +74,21 @@ namespace boost { namespace container { #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +template +struct get_string_opt +{ + typedef string_opt< typename default_if_void::type + , typename default_if_void::type + > type; +}; + +template +struct get_string_opt +{ + typedef string_opt type; +}; + namespace dtl { // ------------------------------------------------------------ // Class basic_string_base. @@ -84,7 +100,7 @@ namespace dtl { // memory. The destructor assumes that the memory either is the internal buffer, // or else points to a block of memory that was allocated using string_base's // allocator and whose size is this->m_storage. -template +template class basic_string_base { basic_string_base & operator=(const basic_string_base &); @@ -98,6 +114,12 @@ class basic_string_base typedef typename allocator_traits_type::value_type value_type; typedef typename allocator_traits_type::size_type size_type; typedef typename allocator_traits_type::difference_type difference_type; + typedef typename boost::container:: + allocator_traits::size_type alloc_size_type; + typedef typename get_string_opt + ::type options_type; + typedef typename options_type::growth_factor_type growth_factor_type; + typedef typename options_type::stored_size_type stored_size_type; typedef ::boost::intrusive::pointer_traits pointer_traits; @@ -142,10 +164,10 @@ class basic_string_base //This is the structure controlling a long string struct long_t { - size_type is_short : 1; - size_type length : (sizeof(size_type)*CHAR_BIT - 1); - size_type storage; - pointer start; + stored_size_type is_short : 1; + stored_size_type length : (sizeof(stored_size_type)*CHAR_BIT - 1); + stored_size_type storage; + pointer start; inline long_t() : is_short(0) @@ -192,9 +214,8 @@ class basic_string_base ::value>::type long_raw_t; protected: - BOOST_STATIC_CONSTEXPR size_type MinInternalBufferChars = 8; - BOOST_STATIC_CONSTEXPR size_type AlignmentOfValueType = - alignment_of::value; + BOOST_STATIC_CONSTEXPR size_type MinInternalBufferChars = 0; + BOOST_STATIC_CONSTEXPR size_type AlignmentOfValueType = alignment_of::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); @@ -322,7 +343,6 @@ class basic_string_base return this->members_.plong_repr(); } - protected: typedef dtl::integral_constantalloc(), command, limit_size, prefer_in_recvd_out_size, reuse); } - size_type next_capacity(size_type additional_objects) const + size_type next_storage(size_type additional_objects, size_type current_storage) const { - return growth_factor_100() - ( this->priv_storage(), additional_objects, allocator_traits_type::max_size(this->alloc())); + const size_type cur_cap = this->priv_capacity(); + const size_type spare_cap = size_type(cur_cap - this->priv_size()); + BOOST_ASSERT(additional_objects > spare_cap); + size_type max_storage = allocator_traits_type::max_size(this->alloc()); + //We need a bit to store the short/ong bit so we can only use half of the stored_size_type capacity + (clamp_by_half_stored_size_type)(max_storage, stored_size_type()); + const size_type max_cap = max_storage - 1u; //we need to save space for null terminator + const size_type achievable_additional_obj = size_type(max_cap - size_type(cur_cap)); + const size_type min_additional_obj = size_type(additional_objects - spare_cap); + + if ( achievable_additional_obj < min_additional_obj ) + boost::container::throw_length_error("get_next_capacity, allocator or storage_size_type's max size reached"); + + return growth_factor_type() + ( current_storage, min_additional_obj, max_storage); } void deallocate(pointer p, size_type n) @@ -373,17 +406,17 @@ class basic_string_base { if (n <= this->max_size()) { if(n > InternalBufferChars){ - size_type new_cap = this->next_capacity(n); + size_type new_storage = n + 1u; pointer reuse = 0; - pointer p = this->allocation_command(allocate_new, n, new_cap, reuse); + pointer p = this->allocation_command(allocate_new, n, new_storage, reuse); BOOST_ASSERT(this->is_short()); this->construct_long(); this->priv_long_addr(p); this->priv_long_size(0); - this->priv_long_storage(new_cap); + this->priv_long_storage(new_storage); } } - else{ + else { throw_length_error("basic_string::allocate_initial_block max_size() exceeded"); } } @@ -440,7 +473,7 @@ class basic_string_base inline void priv_long_storage(size_type storage) { - this->members_.plong_repr()->storage = storage; + this->members_.plong_repr()->storage = static_cast(storage); } inline size_type priv_size() const @@ -463,6 +496,7 @@ class basic_string_base inline void priv_short_size(size_type sz) { typedef unsigned char uchar_type; + BOOST_ASSERT(sz < uchar_type(-1)); BOOST_STATIC_CONSTEXPR uchar_type mask = uchar_type(uchar_type(-1) >> 1U); BOOST_ASSERT( sz <= mask ); //Make -Wconversion happy @@ -471,10 +505,10 @@ class basic_string_base inline void priv_long_size(size_type sz) { - BOOST_STATIC_CONSTEXPR size_type mask = size_type(-1) >> 1U; + BOOST_STATIC_CONSTEXPR stored_size_type mask = static_cast(stored_size_type(-1) >> 1U); BOOST_ASSERT( sz <= mask ); //Make -Wconversion happy - this->members_.plong_repr()->length = sz & mask; + this->members_.plong_repr()->length = static_cast(sz & mask); } #if defined(BOOST_GCC) && (BOOST_GCC >= 40700) #pragma GCC diagnostic pop @@ -548,21 +582,22 @@ class basic_string_base //! \tparam Traits The Character Traits type, which encapsulates basic character operations //! \tparam Allocator The allocator, used for internal memory management. #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED -template , class Allocator = void > +template , class Allocator = void, class Options = void > #else -template +template #endif class basic_string - : private dtl::basic_string_base::type> + : private dtl::basic_string_base::type, Options> { #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: BOOST_COPYABLE_AND_MOVABLE(basic_string) - typedef dtl::basic_string_base::type> base_t; + typedef dtl::basic_string_base::type, Options> base_t; typedef typename base_t::allocator_traits_type allocator_traits_type; + BOOST_STATIC_CONSTEXPR typename base_t::size_type InternalBufferChars = base_t::InternalBufferChars; - protected: + private: // Allocator helper class to use a char_traits as a function object. template @@ -604,23 +639,29 @@ class basic_string // types // ////////////////////////////////////////////// - typedef Traits traits_type; - typedef CharT value_type; - typedef typename real_allocator::type allocator_type; - typedef typename ::boost::container::allocator_traits::pointer pointer; - typedef typename ::boost::container::allocator_traits::const_pointer const_pointer; - typedef typename ::boost::container::allocator_traits::reference reference; - typedef typename ::boost::container::allocator_traits::const_reference const_reference; - typedef typename ::boost::container::allocator_traits::size_type size_type; - typedef typename ::boost::container::allocator_traits::difference_type difference_type; - typedef BOOST_CONTAINER_IMPDEF(allocator_type) stored_allocator_type; - typedef BOOST_CONTAINER_IMPDEF(pointer) iterator; - typedef BOOST_CONTAINER_IMPDEF(const_pointer) const_iterator; - typedef BOOST_CONTAINER_IMPDEF(boost::container::reverse_iterator) reverse_iterator; - typedef BOOST_CONTAINER_IMPDEF(boost::container::reverse_iterator) const_reverse_iterator; + typedef Traits traits_type; + typedef CharT value_type; + typedef typename real_allocator::type allocator_type; + typedef typename ::boost::container::allocator_traits::pointer pointer; + typedef typename ::boost::container::allocator_traits::const_pointer const_pointer; + typedef typename ::boost::container::allocator_traits::reference reference; + typedef typename ::boost::container::allocator_traits::const_reference const_reference; + typedef typename ::boost::container::allocator_traits::size_type size_type; + typedef typename ::boost::container::allocator_traits::difference_type difference_type; + typedef BOOST_CONTAINER_IMPDEF(allocator_type) stored_allocator_type; + typedef BOOST_CONTAINER_IMPDEF(pointer) iterator; + typedef BOOST_CONTAINER_IMPDEF(const_pointer) const_iterator; + typedef BOOST_CONTAINER_IMPDEF(boost::container::reverse_iterator) reverse_iterator; + typedef BOOST_CONTAINER_IMPDEF(boost::container::reverse_iterator) const_reverse_iterator; static const size_type npos = size_type(-1); #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + typedef typename base_t::alloc_size_type alloc_size_type; + typedef typename base_t::options_type options_type; + typedef typename base_t::growth_factor_type growth_factor_type; + typedef typename base_t::stored_size_type stored_size_type; + private: //`allocator_type::value_type` must match container's `value type`. If this @@ -651,6 +692,7 @@ class basic_string #if !defined( BOOST_NO_CXX11_NULLPTR ) BOOST_DELETED_FUNCTION(basic_string( decltype(nullptr) )) + public: #endif //!defined( BOOST_NO_CXX11_NULLPTR ) #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED @@ -1846,10 +1888,10 @@ class basic_string if (first != last) { const size_type n = boost::container::iterator_udistance(first, last); const size_type old_size = this->priv_size(); - const size_type remaining = this->capacity() - old_size; + const size_type old_cap = this->capacity(); + const size_type remaining = old_cap - old_size; const pointer old_start = this->priv_addr(); - bool enough_capacity = false; - size_type new_cap = 0; + size_type new_storage = 0; //Check if we have enough capacity pointer hint = pointer(); @@ -1858,15 +1900,15 @@ class basic_string if (!enough_capacity) { //Otherwise expand current buffer or allocate new storage - new_cap = this->next_capacity(n); + new_storage = this->next_storage(n, old_cap+1u); hint = old_start; allocation_ret = this->allocation_command - (allocate_new | expand_fwd | expand_bwd, old_size + n + 1u, new_cap, hint); + (allocate_new | expand_fwd | expand_bwd, old_size + n + 1u, new_storage, hint); //Check forward expansion enough_capacity = old_start == allocation_ret; if(enough_capacity){ - this->priv_long_storage(new_cap); + this->priv_long_storage(new_storage); } } @@ -1921,7 +1963,7 @@ class basic_string this->assure_long(); this->priv_long_addr(new_start); this->priv_long_size(new_length); - this->priv_long_storage(new_cap); + this->priv_long_storage(new_storage); } else{ //value_type is POD, so backwards expansion is much easier @@ -1940,7 +1982,7 @@ class basic_string this->assure_long(); this->priv_long_addr(new_start); this->priv_long_size(old_size + n); - this->priv_long_storage(new_cap); + this->priv_long_storage(new_storage); } } } @@ -3146,9 +3188,9 @@ class basic_string if (do_alloc){ //size_type n = dtl::max_value(res_arg, this->size()) + 1; size_type n = res_arg + 1; - size_type new_cap = this->next_capacity(n); + size_type new_storage = this->next_storage(n, this->priv_storage()); pointer reuse = 0; - pointer new_start = this->allocation_command(allocate_new, n, new_cap, reuse); + pointer new_start = this->allocation_command(allocate_new, n, new_storage, reuse); const pointer addr = this->priv_addr(); size_type new_length = priv_uninitialized_copy @@ -3157,7 +3199,7 @@ class basic_string this->assure_long(); this->priv_long_addr(new_start); this->priv_long_size(new_length); - this->priv_long_storage(new_cap); + this->priv_long_storage(new_storage); } return do_alloc; } @@ -3302,9 +3344,9 @@ wstring; #else -template -const typename basic_string::size_type - basic_string::npos; +template +const typename basic_string::size_type + basic_string::npos; template struct is_string @@ -3325,12 +3367,12 @@ struct is_string< basic_string > // Operator+ -template inline - basic_string - operator+(const basic_string& x - ,const basic_string& y) +template inline + basic_string + operator+(const basic_string& x + ,const basic_string& y) { - typedef basic_string str_t; + typedef basic_string str_t; typedef typename str_t::reserve_t reserve_t; reserve_t reserve; str_t result(reserve, x.size() + y.size(), x.get_stored_allocator()); @@ -3339,61 +3381,61 @@ template inline return result; } -template inline - basic_string operator+ - ( BOOST_RV_REF_BEG basic_string BOOST_RV_REF_END x - , BOOST_RV_REF_BEG basic_string BOOST_RV_REF_END y) +template inline + basic_string operator+ + ( BOOST_RV_REF_BEG basic_string BOOST_RV_REF_END x + , BOOST_RV_REF_BEG basic_string BOOST_RV_REF_END y) { x += y; return boost::move(x); } -template inline - basic_string operator+ - ( BOOST_RV_REF_BEG basic_string BOOST_RV_REF_END x - , const basic_string& y) +template inline + basic_string operator+ + ( BOOST_RV_REF_BEG basic_string BOOST_RV_REF_END x + , const basic_string& y) { x += y; return boost::move(x); } -template inline - basic_string operator+ - (const basic_string& x - ,BOOST_RV_REF_BEG basic_string BOOST_RV_REF_END y) +template inline + basic_string operator+ + (const basic_string& x + ,BOOST_RV_REF_BEG basic_string BOOST_RV_REF_END y) { y.insert(y.begin(), x.begin(), x.end()); return boost::move(y); } -template inline - basic_string operator+ - (const CharT* s, basic_string y) +template inline + basic_string operator+ + (const CharT* s, basic_string y) { BOOST_ASSERT(s != 0); y.insert(y.begin(), s, s + Traits::length(s)); return y; } -template inline - basic_string operator+ - (basic_string x, const CharT* s) +template inline + basic_string operator+ + (basic_string x, const CharT* s) { x += s; //operator+= checks s != 0 return x; } -template inline - basic_string operator+ - (CharT c, basic_string y) +template inline + basic_string operator+ + (CharT c, basic_string y) { y.insert(y.begin(), c); return y; } -template inline - basic_string operator+ - (basic_string x, const CharT c) +template inline + basic_string operator+ + (basic_string x, const CharT c) { x += c; return x; @@ -3401,227 +3443,227 @@ template inline // Operator== and operator!= -template +template inline bool -operator==(const basic_string& x, const basic_string& y) +operator==(const basic_string& x, const basic_string& y) { return x.size() == y.size() && Traits::compare(x.data(), y.data(), x.size()) == 0; } -template +template inline bool -operator==(const CharT* s, const basic_string& y) +operator==(const CharT* s, const basic_string& y) { BOOST_ASSERT(s != 0); - typename basic_string::size_type n = Traits::length(s); + typename basic_string::size_type n = Traits::length(s); return n == y.size() && Traits::compare(s, y.data(), n) == 0; } -template +template inline bool -operator==(const basic_string& x, const CharT* s) +operator==(const basic_string& x, const CharT* s) { BOOST_ASSERT(s != 0); - typename basic_string::size_type n = Traits::length(s); + typename basic_string::size_type n = Traits::length(s); return x.size() == n && Traits::compare(x.data(), s, n) == 0; } -template class BasicStringView> +template class BasicStringView> inline BOOST_CONTAINER_DOC1ST( bool, typename dtl::disable_if > BOOST_MOVE_I bool >::type) - operator==( BasicStringView x, const basic_string& y) + operator==( BasicStringView x, const basic_string& y) { return x.size() == y.size() && Traits::compare(x.data(), y.data(), x.size()) == 0; } -template class BasicStringView> +template class BasicStringView> inline BOOST_CONTAINER_DOC1ST( bool, typename dtl::disable_if > BOOST_MOVE_I bool >::type) - operator==( const basic_string& x, BasicStringView y) + operator==( const basic_string& x, BasicStringView y) { return x.size() == y.size() && Traits::compare(x.data(), y.data(), x.size()) == 0; } -template +template inline bool -operator!=(const basic_string& x, const basic_string& y) +operator!=(const basic_string& x, const basic_string& y) { return !(x == y); } -template +template inline bool -operator!=(const CharT* s, const basic_string& y) +operator!=(const CharT* s, const basic_string& y) { return !(s == y); } -template +template inline bool -operator!=(const basic_string& x, const CharT* s) +operator!=(const basic_string& x, const CharT* s) { return !(x == s); } -template class BasicStringView> +template class BasicStringView> inline BOOST_CONTAINER_DOC1ST( bool, typename dtl::disable_if > BOOST_MOVE_I bool >::type) -operator!=( BasicStringView x, const basic_string& y) +operator!=( BasicStringView x, const basic_string& y) { return !(x == y); } -template class BasicStringView> +template class BasicStringView> inline BOOST_CONTAINER_DOC1ST( bool, typename dtl::disable_if > BOOST_MOVE_I bool >::type) -operator!=( const basic_string& x, BasicStringView y) +operator!=( const basic_string& x, BasicStringView y) { return !(x == y); } // Operator< (and also >, <=, and >=). -template +template inline bool -operator<(const basic_string& x, const basic_string& y) +operator<(const basic_string& x, const basic_string& y) { return x.compare(y) < 0; } -template +template inline bool -operator<(const CharT* s, const basic_string& y) +operator<(const CharT* s, const basic_string& y) { return y.compare(s) > 0; } -template +template inline bool -operator<(const basic_string& x, const CharT* s) +operator<(const basic_string& x, const CharT* s) { return x.compare(s) < 0; } -template class BasicStringView> +template class BasicStringView> inline BOOST_CONTAINER_DOC1ST( bool, typename dtl::disable_if > BOOST_MOVE_I bool >::type) -operator<( BasicStringView x, const basic_string& y) +operator<( BasicStringView x, const basic_string& y) { return y.compare(x) > 0; } -template class BasicStringView> +template class BasicStringView> inline BOOST_CONTAINER_DOC1ST( bool, typename dtl::disable_if > BOOST_MOVE_I bool >::type) -operator<( const basic_string& x, BasicStringView y) +operator<( const basic_string& x, BasicStringView y) { return x.compare(y) < 0; } -template +template inline bool -operator>(const basic_string& x, const basic_string& y) +operator>(const basic_string& x, const basic_string& y) { return y < x; } -template +template inline bool -operator>(const CharT* s, const basic_string& y) +operator>(const CharT* s, const basic_string& y) { return y < s; } -template +template inline bool -operator>(const basic_string& x, const CharT* s) +operator>(const basic_string& x, const CharT* s) { return s < x; } -template class BasicStringView> +template class BasicStringView> inline BOOST_CONTAINER_DOC1ST( bool, typename dtl::disable_if > BOOST_MOVE_I bool >::type) -operator>( BasicStringView x, const basic_string& y) +operator>( BasicStringView x, const basic_string& y) { return y < x; } -template class BasicStringView> +template class BasicStringView> inline BOOST_CONTAINER_DOC1ST( bool, typename dtl::disable_if > BOOST_MOVE_I bool >::type) -operator>( const basic_string& x, BasicStringView y) +operator>( const basic_string& x, BasicStringView y) { return y < x; } -template +template inline bool -operator<=(const basic_string& x, const basic_string& y) +operator<=(const basic_string& x, const basic_string& y) { return !(y < x); } -template +template inline bool -operator<=(const CharT* s, const basic_string& y) +operator<=(const CharT* s, const basic_string& y) { return !(y < s); } -template +template inline bool -operator<=(const basic_string& x, const CharT* s) +operator<=(const basic_string& x, const CharT* s) { return !(s < x); } -template class BasicStringView> +template class BasicStringView> inline BOOST_CONTAINER_DOC1ST( bool, typename dtl::disable_if > BOOST_MOVE_I bool >::type) -operator<=( BasicStringView x, const basic_string& y) +operator<=( BasicStringView x, const basic_string& y) { return !(y < x); } -template class BasicStringView> +template class BasicStringView> inline BOOST_CONTAINER_DOC1ST( bool, typename dtl::disable_if > BOOST_MOVE_I bool >::type) -operator<=( const basic_string& x, BasicStringView y) +operator<=( const basic_string& x, BasicStringView y) { return !(y < x); } -template +template inline bool -operator>=(const basic_string& x, - const basic_string& y) +operator>=(const basic_string& x, + const basic_string& y) { return !(x < y); } -template +template inline bool -operator>=(const CharT* s, const basic_string& y) +operator>=(const CharT* s, const basic_string& y) { return !(s < y); } -template +template inline bool -operator>=(const basic_string& x, const CharT* s) +operator>=(const basic_string& x, const CharT* s) { return !(x < s); } -template class BasicStringView> +template class BasicStringView> inline BOOST_CONTAINER_DOC1ST( bool, typename dtl::disable_if > BOOST_MOVE_I bool >::type) -operator>=( BasicStringView x, const basic_string& y) +operator>=( BasicStringView x, const basic_string& y) { return !(x < y); } -template class BasicStringView> +template class BasicStringView> inline BOOST_CONTAINER_DOC1ST( bool, typename dtl::disable_if > BOOST_MOVE_I bool >::type) -operator>=( const basic_string& x, BasicStringView y) +operator>=( const basic_string& x, BasicStringView y) { return !(x < y); } // Swap. -template -inline void swap(basic_string& x, basic_string& y) +template +inline void swap(basic_string& x, basic_string& y) BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT(x.swap(y))) { x.swap(y); } @@ -3647,17 +3689,17 @@ string_fill(std::basic_ostream& os, } //namespace dtl { #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED -template +template std::basic_ostream& -operator<<(std::basic_ostream& os, const basic_string& s) +operator<<(std::basic_ostream& os, const basic_string& s) { typename std::basic_ostream::sentry sentry(os); bool ok = false; if (sentry) { ok = true; - typename basic_string::size_type n = s.size(); - typename basic_string::size_type pad_len = 0; + typename basic_string::size_type n = s.size(); + typename basic_string::size_type pad_len = 0; const bool left = (os.flags() & std::ios::left) != 0; const std::size_t w = static_cast(os.width(0)); std::basic_streambuf* buf = os.rdbuf(); @@ -3682,9 +3724,9 @@ operator<<(std::basic_ostream& os, const basic_string +template std::basic_istream& -operator>>(std::basic_istream& is, basic_string& s) +operator>>(std::basic_istream& is, basic_string& s) { typename std::basic_istream::sentry sentry(is); @@ -3729,11 +3771,11 @@ operator>>(std::basic_istream& is, basic_string +template std::basic_istream& -getline(std::istream& is, basic_string& s,CharT delim) +getline(std::istream& is, basic_string& s,CharT delim) { - typename basic_string::size_type nread = 0; + typename basic_string::size_type nread = 0; typename std::basic_istream::sentry sentry(is, true); if (sentry) { std::basic_streambuf* buf = is.rdbuf(); @@ -3761,9 +3803,9 @@ getline(std::istream& is, basic_string& s,CharT delim) return is; } -template +template inline std::basic_istream& -getline(std::basic_istream& is, basic_string& s) +getline(std::basic_istream& is, basic_string& s) { return getline(is, s, '\n'); } diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index b824603..5706489 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -799,9 +799,6 @@ struct vector_alloc_holder } }; -struct growth_factor_60; -struct growth_factor_100; - template struct get_vector_opt { diff --git a/test/string_options_test.cpp b/test/string_options_test.cpp new file mode 100644 index 0000000..b837067 --- /dev/null +++ b/test/string_options_test.cpp @@ -0,0 +1,142 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include + +using namespace boost::container; + +template +void test_stored_size_type_impl() +{ + #ifndef BOOST_NO_EXCEPTIONS + StringType s; + typedef typename StringType::size_type size_type; + typedef typename StringType::value_type value_type; + //We need a bit to store short/long info, minus the null terminator + size_type const max = Unsigned(-1)/2u - 1u; + s.resize(5); + s.resize(max); + BOOST_TEST_THROWS(s.resize(max+1), std::exception); + BOOST_TEST_THROWS(s.push_back(value_type(1)), std::exception); + BOOST_TEST_THROWS(s.insert(s.begin(), value_type(1)), std::exception); + BOOST_TEST_THROWS(s.reserve(max+1), std::exception); + #endif +} + +template +void test_stored_size_type() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = string_options_t< stored_size >; + #else + typedef typename string_options + < stored_size >::type options_t; + #endif + + basic_string, void> default_string_t; + //Test first with a typical allocator + { + typedef basic_string, void, options_t> string_t; + BOOST_CONTAINER_STATIC_ASSERT(sizeof(string_t) < sizeof(default_string_t)); + test_stored_size_type_impl(); + } + //Test with a V2 allocator + { + basic_string, allocator, options_t> string_t; + BOOST_CONTAINER_STATIC_ASSERT(sizeof(string_t) < sizeof(default_string_t)); + //test_stored_size_type_impl(); + } + { + //Test initial capacity + typedef basic_string, void, options_t> string_t; + const std::size_t theoretical_long_repr_t = ((2 * sizeof(Unsigned) - 1u) / sizeof(void*) + 1u) * sizeof(void*) + sizeof(void*); + BOOST_CONTAINER_STATIC_ASSERT(sizeof(string_t) == theoretical_long_repr_t); + const std::size_t theoretical_sso_cap = theoretical_long_repr_t - 2u; //-2 --> 1 for short header, 1 for null terminator + string_t s; + BOOST_ASSERT(s.capacity() == theoretical_sso_cap); + } +} + +void test_growth_factor_50() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = string_options_t< growth_factor >; + #else + typedef string_options + < growth_factor >::type options_t; + #endif + + basic_string, void, options_t> s; + + s.resize(5); + s.resize(s.capacity()); + std::size_t old_capacity = s.capacity(); + s.push_back(0); + std::size_t new_capacity = s.capacity(); + std::size_t old_storage = old_capacity+1u; + std::size_t new_storage = new_capacity + 1u; + BOOST_TEST(new_storage == (old_storage + old_storage/2)); +} + +void test_growth_factor_60() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = string_options_t< growth_factor >; + #else + typedef string_options + < growth_factor >::type options_t; + #endif + + basic_string, void, options_t> s; + + s.resize(5); + s.resize(s.capacity()); + std::size_t old_capacity = s.capacity(); + s.push_back(0); + std::size_t new_capacity = s.capacity(); + std::size_t old_storage = old_capacity+1u; + std::size_t new_storage = new_capacity + 1u; + BOOST_TEST(new_storage == (old_storage + 3*old_storage/5)); +} + +void test_growth_factor_100() +{ + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + using options_t = string_options_t< growth_factor >; + #else + typedef string_options + < growth_factor >::type options_t; + #endif + + basic_string, void, options_t> s; + + s.resize(5); + s.resize(s.capacity()); + std::size_t old_capacity = s.capacity(); + s.push_back(0); + std::size_t new_capacity = s.capacity(); + std::size_t old_storage = old_capacity+1u; + std::size_t new_storage = new_capacity + 1u; + BOOST_TEST(new_storage == 2u*old_storage); +} + +int main() +{ + test_growth_factor_50(); + test_growth_factor_60(); + test_growth_factor_100(); + test_stored_size_type(); + test_stored_size_type(); + + return ::boost::report_errors(); +}