diff --git a/doc/container.qbk b/doc/container.qbk index 41956b0..501d582 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1344,6 +1344,7 @@ use [*Boost.Container]? There are several reasons for that: * [@https://github.com/boostorg/container/issues/186 GitHub #186: ['"Warnings out the wazoo"]]. * [@https://github.com/boostorg/container/issues/187 GitHub #187: ['"flat_map::erase and unique keys"]]. * [@https://github.com/boostorg/container/issues/188 GitHub #188: ['"Build fails when RTTI is disabled"]]. + * [@https://github.com/boostorg/container/issues/192 GitHub #192: ['"basic_string::clear() has poor codegen compared to STL implementations"]]. [endsect] diff --git a/include/boost/container/string.hpp b/include/boost/container/string.hpp index 330c09e..ebf649e 100644 --- a/include/boost/container/string.hpp +++ b/include/boost/container/string.hpp @@ -95,31 +95,31 @@ class basic_string_base typedef typename allocator_traits_type::size_type size_type; typedef ::boost::intrusive::pointer_traits pointer_traits; - basic_string_base() + BOOST_CONTAINER_FORCEINLINE basic_string_base() : members_() {} - explicit basic_string_base(const allocator_type& a) + BOOST_CONTAINER_FORCEINLINE explicit basic_string_base(const allocator_type& a) : members_(a) {} - explicit basic_string_base(BOOST_RV_REF(allocator_type) a) + BOOST_CONTAINER_FORCEINLINE explicit basic_string_base(BOOST_RV_REF(allocator_type) a) : members_(boost::move(a)) {} - basic_string_base(const allocator_type& a, size_type n) + BOOST_CONTAINER_FORCEINLINE basic_string_base(const allocator_type& a, size_type n) : members_(a) { this->allocate_initial_block(n); } - explicit basic_string_base(size_type n) + BOOST_CONTAINER_FORCEINLINE explicit basic_string_base(size_type n) : members_() { this->allocate_initial_block(n); } - ~basic_string_base() + BOOST_CONTAINER_FORCEINLINE ~basic_string_base() { if(!this->is_short()){ this->deallocate(this->priv_long_addr(), this->priv_long_storage()); @@ -136,15 +136,15 @@ class basic_string_base size_type storage; pointer start; - long_t() + BOOST_CONTAINER_FORCEINLINE long_t() : is_short(0) {} - long_t(size_type len, size_type stor, pointer ptr) + BOOST_CONTAINER_FORCEINLINE long_t(size_type len, size_type stor, pointer ptr) : is_short(0), length(len), storage(stor), start(ptr) {} - long_t(const long_t &other) + BOOST_CONTAINER_FORCEINLINE long_t(const long_t &other) { this->is_short = false; length = other.length; @@ -152,7 +152,7 @@ class basic_string_base start = other.start; } - long_t &operator= (const long_t &other) + BOOST_CONTAINER_FORCEINLINE long_t &operator= (const long_t &other) { length = other.length; storage = other.storage; @@ -208,41 +208,41 @@ class basic_string_base struct members_holder : public allocator_type { - void init() + BOOST_CONTAINER_FORCEINLINE void init() { short_t &s = *::new(this->m_repr.data) short_t; s.h.is_short = 1; s.h.length = 0; } - members_holder() + BOOST_CONTAINER_FORCEINLINE members_holder() : allocator_type() { this->init(); } template - explicit members_holder(BOOST_FWD_REF(AllocatorConvertible) a) + BOOST_CONTAINER_FORCEINLINE explicit members_holder(BOOST_FWD_REF(AllocatorConvertible) a) : allocator_type(boost::forward(a)) { this->init(); } - const short_t *pshort_repr() const + BOOST_CONTAINER_FORCEINLINE const short_t *pshort_repr() const { return reinterpret_cast(m_repr.data); } - const long_t *plong_repr() const + BOOST_CONTAINER_FORCEINLINE const long_t *plong_repr() const { return reinterpret_cast(m_repr.data); } - short_t *pshort_repr() + BOOST_CONTAINER_FORCEINLINE short_t *pshort_repr() { return reinterpret_cast(m_repr.data); } - long_t *plong_repr() + BOOST_CONTAINER_FORCEINLINE long_t *plong_repr() { return reinterpret_cast(m_repr.data); } repr_t m_repr; } members_; - const allocator_type &alloc() const + BOOST_CONTAINER_FORCEINLINE const allocator_type &alloc() const { return members_; } - allocator_type &alloc() + BOOST_CONTAINER_FORCEINLINE allocator_type &alloc() { return members_; } static const size_type InternalBufferChars = (sizeof(repr_t) - ShortDataOffset)/sizeof(value_type); @@ -252,7 +252,7 @@ class basic_string_base static const size_type MinAllocation = InternalBufferChars*2; protected: - bool is_short() const + BOOST_CONTAINER_FORCEINLINE bool is_short() const { //Access and copy (to avoid UB) the first byte of the union to know if the //active representation is short or long @@ -262,14 +262,14 @@ class basic_string_base return hdr.is_short != 0; } - short_t *construct_short() + BOOST_CONTAINER_FORCEINLINE short_t *construct_short() { short_t *ps = ::new(this->members_.m_repr.data) short_t; ps->h.is_short = 1; return ps; } - void destroy_short() + BOOST_CONTAINER_FORCEINLINE void destroy_short() { BOOST_ASSERT(this->is_short()); this->members_.pshort_repr()->~short_t(); @@ -284,14 +284,14 @@ class basic_string_base return this->members_.pshort_repr(); } - long_t *construct_long() + BOOST_CONTAINER_FORCEINLINE long_t *construct_long() { long_t *pl = ::new(this->members_.m_repr.data) long_t; //is_short flag is written in the constructor return pl; } - void destroy_long() + BOOST_CONTAINER_FORCEINLINE void destroy_long() { BOOST_ASSERT(!this->is_short()); this->members_.plong_repr()->~long_t(); @@ -337,7 +337,7 @@ class basic_string_base this->alloc().deallocate(p, n); } - void construct(pointer p, const value_type &value = value_type()) + BOOST_CONTAINER_FORCEINLINE void construct(pointer p, const value_type &value = value_type()) { allocator_traits_type::construct ( this->alloc() @@ -354,7 +354,7 @@ class basic_string_base } } - void destroy(pointer p) + BOOST_CONTAINER_FORCEINLINE void destroy(pointer p) { allocator_traits_type::destroy ( this->alloc() @@ -381,17 +381,17 @@ class basic_string_base } } - void deallocate_block() + BOOST_CONTAINER_FORCEINLINE void deallocate_block() { this->deallocate(this->priv_addr(), this->priv_storage()); } - size_type max_size() const + BOOST_CONTAINER_FORCEINLINE size_type max_size() const { return allocator_traits_type::max_size(this->alloc()) - 1; } protected: - size_type priv_capacity() const + BOOST_CONTAINER_FORCEINLINE size_type priv_capacity() const { return this->priv_storage() - 1; } - pointer priv_short_addr() const + BOOST_CONTAINER_FORCEINLINE pointer priv_short_addr() const { return pointer_traits::pointer_to(const_cast(this->members_.pshort_repr()->data[0])); } //GCC seems a bit confused about uninitialized accesses @@ -400,10 +400,10 @@ class basic_string_base #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif - pointer priv_long_addr() const + BOOST_CONTAINER_FORCEINLINE pointer priv_long_addr() const { return this->members_.plong_repr()->start; } - pointer priv_addr() const + BOOST_CONTAINER_FORCEINLINE pointer priv_addr() const { return this->is_short() ? priv_short_addr() @@ -411,7 +411,7 @@ class basic_string_base ; } - pointer priv_end_addr() const + BOOST_CONTAINER_FORCEINLINE pointer priv_end_addr() const { return this->is_short() ? this->priv_short_addr() + this->priv_short_size() @@ -419,39 +419,39 @@ class basic_string_base ; } - void priv_long_addr(pointer addr) + BOOST_CONTAINER_FORCEINLINE void priv_long_addr(pointer addr) { this->members_.plong_repr()->start = addr; } - size_type priv_storage() const + BOOST_CONTAINER_FORCEINLINE size_type priv_storage() const { return this->is_short() ? priv_short_storage() : priv_long_storage(); } - size_type priv_short_storage() const + BOOST_CONTAINER_FORCEINLINE size_type priv_short_storage() const { return InternalBufferChars; } - size_type priv_long_storage() const + BOOST_CONTAINER_FORCEINLINE size_type priv_long_storage() const { return this->members_.plong_repr()->storage; } - void priv_storage(size_type storage) + BOOST_CONTAINER_FORCEINLINE void priv_storage(size_type storage) { if(!this->is_short()) this->priv_long_storage(storage); } - void priv_long_storage(size_type storage) + BOOST_CONTAINER_FORCEINLINE void priv_long_storage(size_type storage) { this->members_.plong_repr()->storage = storage; } - size_type priv_size() const + BOOST_CONTAINER_FORCEINLINE size_type priv_size() const { return this->is_short() ? this->priv_short_size() : this->priv_long_size(); } - size_type priv_short_size() const + BOOST_CONTAINER_FORCEINLINE size_type priv_short_size() const { return this->members_.pshort_repr()->h.length; } - size_type priv_long_size() const + BOOST_CONTAINER_FORCEINLINE size_type priv_long_size() const { return this->members_.plong_repr()->length; } - void priv_size(size_type sz) + BOOST_CONTAINER_FORCEINLINE void priv_size(size_type sz) { if(this->is_short()) this->priv_short_size(sz); @@ -459,10 +459,10 @@ class basic_string_base this->priv_long_size(sz); } - void priv_short_size(size_type sz) + BOOST_CONTAINER_FORCEINLINE void priv_short_size(size_type sz) { this->members_.pshort_repr()->h.length = (unsigned char)sz; } - void priv_long_size(size_type sz) + BOOST_CONTAINER_FORCEINLINE void priv_long_size(size_type sz) { this->members_.plong_repr()->length = sz; } #if defined(BOOST_GCC) && (BOOST_GCC >= 40700) @@ -1869,7 +1869,7 @@ class basic_string //! //! Returns: An iterator which refers to the copy of the first inserted //! character, or p if i1 is empty. - iterator insert(const_iterator p, std::initializer_list il) + BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator p, std::initializer_list il) { return this->insert(p, il.begin(), il.end()); } @@ -1955,10 +1955,14 @@ class basic_string //! Complexity: Linear to the number of elements in the vector. void clear() BOOST_NOEXCEPT_OR_NOTHROW { - if (!this->empty()) { - Traits::assign(*this->priv_addr(), CharT(0)); - this->priv_size(0); - } + if(this->is_short()) { + Traits::assign(*this->priv_short_addr(), CharT(0)); + this->priv_short_size(0); + } + else { + Traits::assign(*this->priv_long_addr(), CharT(0)); + this->priv_long_size(0); + } } //! Requires: pos1 <= size(). @@ -1984,7 +1988,7 @@ class basic_string //! Effects: Calls `return replace(pos1, n1, sv.data(), sv.size());`. //! template class BasicStringView> - basic_string& replace(size_type pos1, size_type n1, BasicStringView sv) + BOOST_CONTAINER_FORCEINLINE basic_string& replace(size_type pos1, size_type n1, BasicStringView sv) { return this->replace(pos1, n1, sv.data(), sv.size()); } @@ -2061,7 +2065,7 @@ class basic_string //! if the length of the resulting string would exceed max_size() //! //! Returns: *this - basic_string& replace(size_type pos, size_type n1, const CharT* s) + BOOST_CONTAINER_FORCEINLINE basic_string& replace(size_type pos, size_type n1, const CharT* s) { return this->replace(pos, n1, s, Traits::length(s)); } @@ -2092,7 +2096,7 @@ class basic_string //! Throws: if memory allocation throws //! //! Returns: *this - basic_string& replace(const_iterator i1, const_iterator i2, const basic_string& str) + BOOST_CONTAINER_FORCEINLINE basic_string& replace(const_iterator i1, const_iterator i2, const basic_string& str) { return this->replace(i1, i2, str.data(), str.data()+str.size()); } //! Requires: [begin(),i1) and [i1,i2) are valid ranges and @@ -2103,7 +2107,7 @@ class basic_string //! Throws: if memory allocation throws //! //! Returns: *this - basic_string& replace(const_iterator i1, const_iterator i2, const CharT* s, size_type n) + BOOST_CONTAINER_FORCEINLINE basic_string& replace(const_iterator i1, const_iterator i2, const CharT* s, size_type n) { return this->replace(i1, i2, s, s + n); } //! Requires: [begin(),i1) and [i1,i2) are valid ranges and s points to an @@ -2114,7 +2118,7 @@ class basic_string //! Throws: if memory allocation throws //! //! Returns: *this - basic_string& replace(const_iterator i1, const_iterator i2, const CharT* s) + BOOST_CONTAINER_FORCEINLINE basic_string& replace(const_iterator i1, const_iterator i2, const CharT* s) { return this->replace(i1, i2, s, s + Traits::length(s)); } //! Requires: [begin(),i1) and [i1,i2) are valid ranges. @@ -2199,7 +2203,7 @@ class basic_string //! //! Returns: *this. template