mirror of
https://github.com/boostorg/container.git
synced 2025-08-01 21:44:27 +02:00
Improve short/long representation to avoid aliasing problems and disable "-Wmaybe-uninitialized" for compilers that have false positives.
This commit is contained in:
@@ -98,27 +98,25 @@ class basic_string_base
|
|||||||
|
|
||||||
basic_string_base()
|
basic_string_base()
|
||||||
: members_()
|
: members_()
|
||||||
{ init(); }
|
{}
|
||||||
|
|
||||||
explicit basic_string_base(const allocator_type& a)
|
explicit basic_string_base(const allocator_type& a)
|
||||||
: members_(a)
|
: members_(a)
|
||||||
{ init(); }
|
{}
|
||||||
|
|
||||||
explicit basic_string_base(BOOST_RV_REF(allocator_type) a)
|
explicit basic_string_base(BOOST_RV_REF(allocator_type) a)
|
||||||
: members_(boost::move(a))
|
: members_(boost::move(a))
|
||||||
{ this->init(); }
|
{}
|
||||||
|
|
||||||
basic_string_base(const allocator_type& a, size_type n)
|
basic_string_base(const allocator_type& a, size_type n)
|
||||||
: members_(a)
|
: members_(a)
|
||||||
{
|
{
|
||||||
this->init();
|
|
||||||
this->allocate_initial_block(n);
|
this->allocate_initial_block(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit basic_string_base(size_type n)
|
explicit basic_string_base(size_type n)
|
||||||
: members_()
|
: members_()
|
||||||
{
|
{
|
||||||
this->init();
|
|
||||||
this->allocate_initial_block(n);
|
this->allocate_initial_block(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,6 +138,11 @@ class basic_string_base
|
|||||||
pointer start;
|
pointer start;
|
||||||
|
|
||||||
long_t()
|
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)
|
long_t(const long_t &other)
|
||||||
@@ -190,35 +193,49 @@ class basic_string_base
|
|||||||
value_type data[UnalignedFinalInternalBufferChars];
|
value_type data[UnalignedFinalInternalBufferChars];
|
||||||
};
|
};
|
||||||
|
|
||||||
union repr_t
|
union repr_t_size_t
|
||||||
{
|
{
|
||||||
long_raw_t r;
|
long_raw_t r;
|
||||||
short_t s;
|
short_t s;
|
||||||
|
};
|
||||||
|
|
||||||
const short_t &short_repr() const
|
union repr_t
|
||||||
{ return s; }
|
{
|
||||||
|
long_raw_t r_aligner;
|
||||||
const long_t &long_repr() const
|
short_t s_aligner;
|
||||||
{ return *static_cast<const long_t*>(static_cast<const void*>(r.data)); }
|
unsigned char data[sizeof(repr_t_size_t)];
|
||||||
|
|
||||||
short_t &short_repr()
|
|
||||||
{ return s; }
|
|
||||||
|
|
||||||
long_t &long_repr()
|
|
||||||
{ return *static_cast<long_t*>(static_cast<void*>(&r)); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct members_holder
|
struct members_holder
|
||||||
: public Allocator
|
: 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()
|
members_holder()
|
||||||
: Allocator()
|
: Allocator()
|
||||||
{}
|
{ this->init(); }
|
||||||
|
|
||||||
template<class AllocatorConvertible>
|
template<class AllocatorConvertible>
|
||||||
explicit members_holder(BOOST_FWD_REF(AllocatorConvertible) a)
|
explicit members_holder(BOOST_FWD_REF(AllocatorConvertible) a)
|
||||||
: Allocator(boost::forward<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;
|
repr_t m_repr;
|
||||||
} members_;
|
} members_;
|
||||||
@@ -246,32 +263,43 @@ class basic_string_base
|
|||||||
return hdr.is_short != 0;
|
return hdr.is_short != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void is_short(bool yes)
|
short_t *make_short()
|
||||||
{
|
{
|
||||||
const bool was_short = this->is_short();
|
BOOST_ASSERT(!this->is_short());
|
||||||
if(yes && !was_short){
|
allocator_traits_type::destroy
|
||||||
allocator_traits_type::destroy
|
( this->alloc()
|
||||||
( this->alloc()
|
, reinterpret_cast<long_t*>(this->members_.m_repr.data)
|
||||||
, static_cast<long_t*>(static_cast<void*>(&this->members_.m_repr.r))
|
);
|
||||||
);
|
short_t *ps = ::new(this->members_.m_repr.data) short_t;
|
||||||
this->members_.m_repr.s.h.is_short = true;
|
ps->h.is_short = 1;
|
||||||
}
|
return ps;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
long_t *make_long()
|
||||||
void init()
|
|
||||||
{
|
{
|
||||||
this->members_.m_repr.s.h.is_short = 1;
|
BOOST_ASSERT(this->is_short());
|
||||||
this->members_.m_repr.s.h.length = 0;
|
long_t *pl = reinterpret_cast<long_t*>(this->members_.m_repr.data);
|
||||||
|
allocator_traits_type::construct(this->alloc(), pl);
|
||||||
|
//is_short flag is written in the constructor
|
||||||
|
return pl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long_t *make_long_if_needed()
|
||||||
|
{
|
||||||
|
if (this->is_short()){
|
||||||
|
this->members_.pshort_repr()->~short_t();
|
||||||
|
}
|
||||||
|
return this->make_long();
|
||||||
|
}
|
||||||
|
|
||||||
|
short_t *make_short_if_needed()
|
||||||
|
{
|
||||||
|
if (!this->is_short()){
|
||||||
|
this->members_.plong_repr()->~long_t();
|
||||||
|
}
|
||||||
|
return this->make_short();
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
typedef dtl::integral_constant<unsigned,
|
typedef dtl::integral_constant<unsigned,
|
||||||
@@ -334,7 +362,7 @@ class basic_string_base
|
|||||||
size_type new_cap = this->next_capacity(n);
|
size_type new_cap = this->next_capacity(n);
|
||||||
pointer reuse = 0;
|
pointer reuse = 0;
|
||||||
pointer p = this->allocation_command(allocate_new, n, new_cap, reuse);
|
pointer p = this->allocation_command(allocate_new, n, new_cap, reuse);
|
||||||
this->is_short(false);
|
this->make_long();
|
||||||
this->priv_long_addr(p);
|
this->priv_long_addr(p);
|
||||||
this->priv_long_size(0);
|
this->priv_long_size(0);
|
||||||
this->priv_storage(new_cap);
|
this->priv_storage(new_cap);
|
||||||
@@ -356,10 +384,16 @@ class basic_string_base
|
|||||||
{ return this->priv_storage() - 1; }
|
{ return this->priv_storage() - 1; }
|
||||||
|
|
||||||
pointer priv_short_addr() const
|
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
|
pointer priv_long_addr() const
|
||||||
{ return this->members_.m_repr.long_repr().start; }
|
{ return this->members_.plong_repr()->start; }
|
||||||
|
|
||||||
pointer priv_addr() const
|
pointer priv_addr() const
|
||||||
{
|
{
|
||||||
@@ -378,7 +412,7 @@ class basic_string_base
|
|||||||
}
|
}
|
||||||
|
|
||||||
void priv_long_addr(pointer addr)
|
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
|
size_type priv_storage() const
|
||||||
{ return this->is_short() ? priv_short_storage() : priv_long_storage(); }
|
{ return this->is_short() ? priv_short_storage() : priv_long_storage(); }
|
||||||
@@ -387,7 +421,7 @@ class basic_string_base
|
|||||||
{ return InternalBufferChars; }
|
{ return InternalBufferChars; }
|
||||||
|
|
||||||
size_type priv_long_storage() const
|
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)
|
void priv_storage(size_type storage)
|
||||||
{
|
{
|
||||||
@@ -397,17 +431,17 @@ class basic_string_base
|
|||||||
|
|
||||||
void priv_long_storage(size_type storage)
|
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
|
size_type priv_size() const
|
||||||
{ return this->is_short() ? this->priv_short_size() : this->priv_long_size(); }
|
{ return this->is_short() ? this->priv_short_size() : this->priv_long_size(); }
|
||||||
|
|
||||||
size_type priv_short_size() const
|
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
|
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)
|
void priv_size(size_type sz)
|
||||||
{
|
{
|
||||||
@@ -418,14 +452,14 @@ class basic_string_base
|
|||||||
}
|
}
|
||||||
|
|
||||||
void priv_short_size(size_type sz)
|
void priv_short_size(size_type sz)
|
||||||
{
|
{ this->members_.pshort_repr()->h.length = (unsigned char)sz; }
|
||||||
this->members_.m_repr.s.h.length = (unsigned char)sz;
|
|
||||||
}
|
|
||||||
|
|
||||||
void priv_long_size(size_type sz)
|
void priv_long_size(size_type sz)
|
||||||
{
|
{ this->members_.plong_repr()->length = sz; }
|
||||||
this->members_.m_repr.long_repr().length = sz;
|
|
||||||
}
|
#if defined(BOOST_GCC) && (BOOST_GCC >= 40700)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
void swap_data(basic_string_base& other)
|
void swap_data(basic_string_base& other)
|
||||||
{
|
{
|
||||||
@@ -436,23 +470,23 @@ class basic_string_base
|
|||||||
other.members_.m_repr = tmp;
|
other.members_.m_repr = tmp;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
short_t short_backup(this->members_.m_repr.short_repr());
|
short_t short_backup(*this->members_.pshort_repr());
|
||||||
this->members_.m_repr.short_repr().~short_t();
|
this->members_.pshort_repr()->~short_t();
|
||||||
::new(&this->members_.m_repr.long_repr()) long_t(other.members_.m_repr.long_repr());
|
::new(this->members_.plong_repr()) long_t(*other.members_.plong_repr());
|
||||||
other.members_.m_repr.long_repr().~long_t();
|
other.members_.plong_repr()->~long_t();
|
||||||
::new(&other.members_.m_repr.short_repr()) short_t(short_backup);
|
::new(other.members_.pshort_repr()) short_t(short_backup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
if(other.is_short()){
|
if(other.is_short()){
|
||||||
short_t short_backup(other.members_.m_repr.short_repr());
|
short_t short_backup(*other.members_.pshort_repr());
|
||||||
other.members_.m_repr.short_repr().~short_t();
|
other.members_.pshort_repr()->~short_t();
|
||||||
::new(&other.members_.m_repr.long_repr()) long_t(this->members_.m_repr.long_repr());
|
::new(other.members_.plong_repr()) long_t(*this->members_.plong_repr());
|
||||||
this->members_.m_repr.long_repr().~long_t();
|
this->members_.plong_repr()->~long_t();
|
||||||
::new(&this->members_.m_repr.short_repr()) short_t(short_backup);
|
::new(this->members_.pshort_repr()) short_t(short_backup);
|
||||||
}
|
}
|
||||||
else{
|
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 +864,7 @@ class basic_string
|
|||||||
if(flag && this_alloc != x_alloc){
|
if(flag && this_alloc != x_alloc){
|
||||||
if(!this->is_short()){
|
if(!this->is_short()){
|
||||||
this->deallocate_block();
|
this->deallocate_block();
|
||||||
this->is_short(true);
|
this->make_short();
|
||||||
Traits::assign(*this->priv_addr(), CharT(0));
|
Traits::assign(*this->priv_addr(), CharT(0));
|
||||||
this->priv_short_size(0);
|
this->priv_short_size(0);
|
||||||
}
|
}
|
||||||
@@ -1159,7 +1193,7 @@ class basic_string
|
|||||||
Traits::copy( boost::movelib::to_raw_pointer(this->priv_short_addr())
|
Traits::copy( boost::movelib::to_raw_pointer(this->priv_short_addr())
|
||||||
, boost::movelib::to_raw_pointer(long_addr)
|
, boost::movelib::to_raw_pointer(long_addr)
|
||||||
, long_size+1);
|
, long_size+1);
|
||||||
this->is_short(true);
|
this->make_short();
|
||||||
this->alloc().deallocate(long_addr, long_storage);
|
this->alloc().deallocate(long_addr, long_storage);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
@@ -1763,7 +1797,7 @@ class basic_string
|
|||||||
this->priv_construct_null(new_start + new_length);
|
this->priv_construct_null(new_start + new_length);
|
||||||
|
|
||||||
this->deallocate_block();
|
this->deallocate_block();
|
||||||
this->is_short(false);
|
this->make_long_if_needed();
|
||||||
this->priv_long_addr(new_start);
|
this->priv_long_addr(new_start);
|
||||||
this->priv_long_size(new_length);
|
this->priv_long_size(new_length);
|
||||||
this->priv_long_storage(new_cap);
|
this->priv_long_storage(new_cap);
|
||||||
@@ -1782,7 +1816,9 @@ class basic_string
|
|||||||
//Now initialize the new data
|
//Now initialize the new data
|
||||||
priv_uninitialized_copy(first, last, new_start + before);
|
priv_uninitialized_copy(first, last, new_start + before);
|
||||||
this->priv_construct_null(new_start + (old_size + n));
|
this->priv_construct_null(new_start + (old_size + n));
|
||||||
this->is_short(false);
|
if(this->is_short())
|
||||||
|
this->members_.pshort_repr()->~short_t();
|
||||||
|
this->make_long_if_needed();
|
||||||
this->priv_long_addr(new_start);
|
this->priv_long_addr(new_start);
|
||||||
this->priv_long_size(old_size + n);
|
this->priv_long_size(old_size + n);
|
||||||
this->priv_long_storage(new_cap);
|
this->priv_long_storage(new_cap);
|
||||||
@@ -2790,7 +2826,7 @@ class basic_string
|
|||||||
this->priv_construct_null(new_start + new_length);
|
this->priv_construct_null(new_start + new_length);
|
||||||
}
|
}
|
||||||
this->deallocate_block();
|
this->deallocate_block();
|
||||||
this->is_short(false);
|
this->make_long_if_needed();
|
||||||
this->priv_long_addr(new_start);
|
this->priv_long_addr(new_start);
|
||||||
this->priv_long_size(new_length);
|
this->priv_long_size(new_length);
|
||||||
this->priv_storage(new_cap);
|
this->priv_storage(new_cap);
|
||||||
|
Reference in New Issue
Block a user