summaryrefslogtreecommitdiff
path: root/boost/container/string.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/container/string.hpp')
-rw-r--r--boost/container/string.hpp185
1 files changed, 115 insertions, 70 deletions
diff --git a/boost/container/string.hpp b/boost/container/string.hpp
index 6c0cc96870..ca51cfdd73 100644
--- a/boost/container/string.hpp
+++ b/boost/container/string.hpp
@@ -98,27 +98,25 @@ class basic_string_base
basic_string_base()
: members_()
- { init(); }
+ {}
explicit basic_string_base(const allocator_type& a)
: members_(a)
- { init(); }
+ {}
explicit basic_string_base(BOOST_RV_REF(allocator_type) a)
: members_(boost::move(a))
- { this->init(); }
+ {}
basic_string_base(const allocator_type& a, size_type n)
: members_(a)
{
- this->init();
this->allocate_initial_block(n);
}
explicit basic_string_base(size_type n)
: members_()
{
- this->init();
this->allocate_initial_block(n);
}
@@ -140,6 +138,11 @@ class basic_string_base
pointer start;
long_t()
+ : is_short(0)
+ {}
+
+ 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)
@@ -190,35 +193,49 @@ class basic_string_base
value_type data[UnalignedFinalInternalBufferChars];
};
- union repr_t
+ union repr_t_size_t
{
long_raw_t r;
short_t s;
+ };
- const short_t &short_repr() const
- { return s; }
-
- const long_t &long_repr() const
- { return *static_cast<const long_t*>(static_cast<const void*>(r.data)); }
-
- short_t &short_repr()
- { return s; }
-
- long_t &long_repr()
- { return *static_cast<long_t*>(static_cast<void*>(&r)); }
+ union repr_t
+ {
+ long_raw_t r_aligner;
+ short_t s_aligner;
+ unsigned char data[sizeof(repr_t_size_t)];
};
struct members_holder
: public Allocator
{
+ void init()
+ {
+ short_t &s = *::new(this->m_repr.data) short_t;
+ s.h.is_short = 1;
+ s.h.length = 0;
+ }
+
members_holder()
: Allocator()
- {}
+ { this->init(); }
template<class AllocatorConvertible>
explicit members_holder(BOOST_FWD_REF(AllocatorConvertible) a)
: Allocator(boost::forward<AllocatorConvertible>(a))
- {}
+ { this->init(); }
+
+ const short_t *pshort_repr() const
+ { return reinterpret_cast<const short_t*>(m_repr.data); }
+
+ const long_t *plong_repr() const
+ { return reinterpret_cast<const long_t*>(m_repr.data); }
+
+ short_t *pshort_repr()
+ { return reinterpret_cast<short_t*>(m_repr.data); }
+
+ long_t *plong_repr()
+ { return reinterpret_cast<long_t*>(m_repr.data); }
repr_t m_repr;
} members_;
@@ -246,32 +263,51 @@ class basic_string_base
return hdr.is_short != 0;
}
- void is_short(bool yes)
+ short_t *construct_short()
{
- const bool was_short = this->is_short();
- if(yes && !was_short){
- allocator_traits_type::destroy
- ( this->alloc()
- , static_cast<long_t*>(static_cast<void*>(&this->members_.m_repr.r))
- );
- this->members_.m_repr.s.h.is_short = true;
- }
- else if(!yes && was_short){
- allocator_traits_type::construct
- ( this->alloc()
- , static_cast<long_t*>(static_cast<void*>(&this->members_.m_repr.r))
- );
- this->members_.m_repr.s.h.is_short = false;
+ short_t *ps = ::new(this->members_.m_repr.data) short_t;
+ ps->h.is_short = 1;
+ return ps;
+ }
+
+ void destroy_short()
+ {
+ BOOST_ASSERT(this->is_short());
+ this->members_.pshort_repr()->~short_t();
+ }
+
+ short_t *assure_short()
+ {
+ if (!this->is_short()){
+ this->destroy_long();
+ return construct_short();
}
+ return this->members_.pshort_repr();
}
- private:
- void init()
+ 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_ASSERT(!this->is_short());
+ this->members_.plong_repr()->~long_t();
+ }
+
+ long_t *assure_long()
{
- this->members_.m_repr.s.h.is_short = 1;
- this->members_.m_repr.s.h.length = 0;
+ if (this->is_short()){
+ this->destroy_short();
+ return this->construct_long();
+ }
+ return this->members_.plong_repr();
}
+
protected:
typedef dtl::integral_constant<unsigned,
@@ -334,7 +370,8 @@ class basic_string_base
size_type new_cap = this->next_capacity(n);
pointer reuse = 0;
pointer p = this->allocation_command(allocate_new, n, new_cap, reuse);
- this->is_short(false);
+ BOOST_ASSERT(this->is_short());
+ this->construct_long();
this->priv_long_addr(p);
this->priv_long_size(0);
this->priv_storage(new_cap);
@@ -356,10 +393,16 @@ class basic_string_base
{ return this->priv_storage() - 1; }
pointer priv_short_addr() const
- { return pointer_traits::pointer_to(const_cast<value_type&>(this->members_.m_repr.short_repr().data[0])); }
+ { return pointer_traits::pointer_to(const_cast<value_type&>(this->members_.pshort_repr()->data[0])); }
+
+ //GCC seems a bit confused about uninitialized accesses
+ #if defined(BOOST_GCC) && (BOOST_GCC >= 40700)
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+ #endif
pointer priv_long_addr() const
- { return this->members_.m_repr.long_repr().start; }
+ { return this->members_.plong_repr()->start; }
pointer priv_addr() const
{
@@ -378,7 +421,7 @@ class basic_string_base
}
void priv_long_addr(pointer addr)
- { this->members_.m_repr.long_repr().start = addr; }
+ { this->members_.plong_repr()->start = addr; }
size_type priv_storage() const
{ return this->is_short() ? priv_short_storage() : priv_long_storage(); }
@@ -387,7 +430,7 @@ class basic_string_base
{ return InternalBufferChars; }
size_type priv_long_storage() const
- { return this->members_.m_repr.long_repr().storage; }
+ { return this->members_.plong_repr()->storage; }
void priv_storage(size_type storage)
{
@@ -397,17 +440,17 @@ class basic_string_base
void priv_long_storage(size_type storage)
{
- this->members_.m_repr.long_repr().storage = storage;
+ this->members_.plong_repr()->storage = storage;
}
size_type priv_size() const
{ return this->is_short() ? this->priv_short_size() : this->priv_long_size(); }
size_type priv_short_size() const
- { return this->members_.m_repr.short_repr().h.length; }
+ { return this->members_.pshort_repr()->h.length; }
size_type priv_long_size() const
- { return this->members_.m_repr.long_repr().length; }
+ { return this->members_.plong_repr()->length; }
void priv_size(size_type sz)
{
@@ -418,14 +461,14 @@ class basic_string_base
}
void priv_short_size(size_type sz)
- {
- this->members_.m_repr.s.h.length = (unsigned char)sz;
- }
+ { this->members_.pshort_repr()->h.length = (unsigned char)sz; }
void priv_long_size(size_type sz)
- {
- this->members_.m_repr.long_repr().length = sz;
- }
+ { this->members_.plong_repr()->length = sz; }
+
+ #if defined(BOOST_GCC) && (BOOST_GCC >= 40700)
+ #pragma GCC diagnostic pop
+ #endif
void swap_data(basic_string_base& other)
{
@@ -436,23 +479,23 @@ class basic_string_base
other.members_.m_repr = tmp;
}
else{
- short_t short_backup(this->members_.m_repr.short_repr());
- this->members_.m_repr.short_repr().~short_t();
- ::new(&this->members_.m_repr.long_repr()) long_t(other.members_.m_repr.long_repr());
- other.members_.m_repr.long_repr().~long_t();
- ::new(&other.members_.m_repr.short_repr()) short_t(short_backup);
+ short_t short_backup(*this->members_.pshort_repr());
+ this->members_.pshort_repr()->~short_t();
+ ::new(this->members_.plong_repr()) long_t(*other.members_.plong_repr());
+ other.members_.plong_repr()->~long_t();
+ ::new(other.members_.pshort_repr()) short_t(short_backup);
}
}
else{
if(other.is_short()){
- short_t short_backup(other.members_.m_repr.short_repr());
- other.members_.m_repr.short_repr().~short_t();
- ::new(&other.members_.m_repr.long_repr()) long_t(this->members_.m_repr.long_repr());
- this->members_.m_repr.long_repr().~long_t();
- ::new(&this->members_.m_repr.short_repr()) short_t(short_backup);
+ short_t short_backup(*other.members_.pshort_repr());
+ other.members_.pshort_repr()->~short_t();
+ ::new(other.members_.plong_repr()) long_t(*this->members_.plong_repr());
+ this->members_.plong_repr()->~long_t();
+ ::new(this->members_.pshort_repr()) short_t(short_backup);
}
else{
- boost::adl_move_swap(this->members_.m_repr.long_repr(), other.members_.m_repr.long_repr());
+ boost::adl_move_swap(*this->members_.plong_repr(), *other.members_.plong_repr());
}
}
}
@@ -830,7 +873,7 @@ class basic_string
if(flag && this_alloc != x_alloc){
if(!this->is_short()){
this->deallocate_block();
- this->is_short(true);
+ this->assure_short();
Traits::assign(*this->priv_addr(), CharT(0));
this->priv_short_size(0);
}
@@ -853,7 +896,7 @@ class basic_string
BOOST_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value
|| allocator_traits_type::is_always_equal::value)
{
- //for move constructor, no aliasing (&x != this) is assummed.
+ //for move constructor, no aliasing (&x != this) is assumed.
BOOST_ASSERT(this != &x);
allocator_type &this_alloc = this->alloc();
allocator_type &x_alloc = x.alloc();
@@ -1159,7 +1202,9 @@ class basic_string
Traits::copy( boost::movelib::to_raw_pointer(this->priv_short_addr())
, boost::movelib::to_raw_pointer(long_addr)
, long_size+1);
- this->is_short(true);
+ BOOST_ASSERT(!this->is_short());
+ this->destroy_long();
+ this->construct_short();
this->alloc().deallocate(long_addr, long_storage);
}
else{
@@ -1763,7 +1808,7 @@ class basic_string
this->priv_construct_null(new_start + new_length);
this->deallocate_block();
- this->is_short(false);
+ this->assure_long();
this->priv_long_addr(new_start);
this->priv_long_size(new_length);
this->priv_long_storage(new_cap);
@@ -1782,7 +1827,7 @@ class basic_string
//Now initialize the new data
priv_uninitialized_copy(first, last, new_start + before);
this->priv_construct_null(new_start + (old_size + n));
- this->is_short(false);
+ this->assure_long();
this->priv_long_addr(new_start);
this->priv_long_size(old_size + n);
this->priv_long_storage(new_cap);
@@ -2790,7 +2835,7 @@ class basic_string
this->priv_construct_null(new_start + new_length);
}
this->deallocate_block();
- this->is_short(false);
+ this->assure_long();
this->priv_long_addr(new_start);
this->priv_long_size(new_length);
this->priv_storage(new_cap);
@@ -2933,7 +2978,7 @@ class basic_string
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
};
-#if __cplusplus >= 201703L
+#ifndef BOOST_CONTAINER_NO_CXX17_CTAD
template <typename InputIterator>
basic_string(InputIterator, InputIterator) ->