basic_string_base & operator=(const basic_string_base &);
basic_string_base(const basic_string_base &);
- typedef allocator_traits<Allocator> allocator_traits_type;
+ typedef Allocator allocator_type;
public:
- typedef Allocator allocator_type;
+ typedef allocator_traits<allocator_type> allocator_traits_type;
typedef allocator_type stored_allocator_type;
typedef typename allocator_traits_type::pointer pointer;
typedef typename allocator_traits_type::value_type value_type;
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);
}
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)
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
+ : public allocator_type
{
+ void init()
+ {
+ short_t &s = *::new(this->m_repr.data) short_t;
+ s.h.is_short = 1;
+ s.h.length = 0;
+ }
+
members_holder()
- : Allocator()
- {}
+ : allocator_type()
+ { this->init(); }
template<class AllocatorConvertible>
explicit members_holder(BOOST_FWD_REF(AllocatorConvertible) a)
- : Allocator(boost::forward<AllocatorConvertible>(a))
- {}
+ : allocator_type(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_;
- const Allocator &alloc() const
+ const allocator_type &alloc() const
{ return members_; }
- Allocator &alloc()
+ allocator_type &alloc()
{ return members_; }
static const size_type InternalBufferChars = (sizeof(repr_t) - ShortDataOffset)/sizeof(value_type);
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,
- boost::container::dtl::version<Allocator>::value> alloc_version;
+ boost::container::dtl::version<allocator_type>::value> alloc_version;
pointer allocation_command(allocation_type command,
size_type limit_size,
reuse = 0;
command &= ~(expand_fwd | expand_bwd);
}
- return dtl::allocator_version_traits<Allocator>::allocation_command
+ return dtl::allocator_version_traits<allocator_type>::allocation_command
(this->alloc(), command, limit_size, prefer_in_recvd_out_size, reuse);
}
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);
{ 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
{
}
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(); }
{ 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)
{
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)
{
}
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)
{
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());
}
}
}
//! \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 CharT, class Traits = std::char_traits<CharT>, class Allocator = new_allocator<CharT> >
+template <class CharT, class Traits = std::char_traits<CharT>, class Allocator = void >
#else
template <class CharT, class Traits, class Allocator>
#endif
class basic_string
- : private dtl::basic_string_base<Allocator>
+ : private dtl::basic_string_base<typename real_allocator<CharT, Allocator>::type>
{
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
private:
- typedef allocator_traits<Allocator> allocator_traits_type;
BOOST_COPYABLE_AND_MOVABLE(basic_string)
- typedef dtl::basic_string_base<Allocator> base_t;
+ typedef dtl::basic_string_base<typename real_allocator<CharT, Allocator>::type> base_t;
+ typedef typename base_t::allocator_traits_type allocator_traits_type;
static const typename base_t::size_type InternalBufferChars = base_t::InternalBufferChars;
protected:
//////////////////////////////////////////////
typedef Traits traits_type;
typedef CharT value_type;
- typedef typename ::boost::container::allocator_traits<Allocator>::pointer pointer;
- typedef typename ::boost::container::allocator_traits<Allocator>::const_pointer const_pointer;
- typedef typename ::boost::container::allocator_traits<Allocator>::reference reference;
- typedef typename ::boost::container::allocator_traits<Allocator>::const_reference const_reference;
- typedef typename ::boost::container::allocator_traits<Allocator>::size_type size_type;
- typedef typename ::boost::container::allocator_traits<Allocator>::difference_type difference_type;
- typedef Allocator allocator_type;
+ typedef typename real_allocator<CharT, Allocator>::type allocator_type;
+ typedef typename ::boost::container::allocator_traits<allocator_type>::pointer pointer;
+ typedef typename ::boost::container::allocator_traits<allocator_type>::const_pointer const_pointer;
+ typedef typename ::boost::container::allocator_traits<allocator_type>::reference reference;
+ typedef typename ::boost::container::allocator_traits<allocator_type>::const_reference const_reference;
+ typedef typename ::boost::container::allocator_traits<allocator_type>::size_type size_type;
+ typedef typename ::boost::container::allocator_traits<allocator_type>::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;
//! <b>Effects</b>: Default constructs a basic_string.
//!
//! <b>Throws</b>: If allocator_type's default constructor throws.
- basic_string() BOOST_NOEXCEPT_IF(dtl::is_nothrow_default_constructible<Allocator>::value)
+ basic_string() BOOST_NOEXCEPT_IF(dtl::is_nothrow_default_constructible<allocator_type>::value)
: base_t()
{ this->priv_terminate_string(); }
//!
//! <b>Throws</b>: If allocator_type's default constructor or allocation throws.
template<template <class, class> class BasicStringView>
- explicit basic_string(BasicStringView<CharT, Traits> sv, const Allocator& a = Allocator())
+ explicit basic_string(BasicStringView<CharT, Traits> sv, const allocator_type& a = allocator_type())
: base_t(allocator_traits_type::select_on_container_copy_construction(a))
{
this->priv_terminate_string();
: base_t(a)
{
this->priv_terminate_string();
- if(a == this->alloc()){
+ if(s.alloc() == this->alloc()){
this->swap_data(s);
}
else{
//! <b>Complexity</b>: Linear to the elements x contains.
basic_string& operator=(BOOST_COPY_ASSIGN_REF(basic_string) x)
{
- if (&x != this){
+ if (BOOST_LIKELY(this != &x)) {
allocator_type &this_alloc = this->alloc();
const allocator_type &x_alloc = x.alloc();
dtl::bool_<allocator_traits_type::
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);
}
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.
- BOOST_ASSERT(this != &x);
- allocator_type &this_alloc = this->alloc();
- allocator_type &x_alloc = x.alloc();
- const bool propagate_alloc = allocator_traits_type::
- propagate_on_container_move_assignment::value;
- dtl::bool_<propagate_alloc> flag;
- const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal;
- //Resources can be transferred if both allocators are
- //going to be equal after this function (either propagated or already equal)
- if(propagate_alloc || allocators_equal){
- //Destroy objects but retain memory in case x reuses it in the future
- this->clear();
- //Move allocator if needed
- dtl::move_alloc(this_alloc, x_alloc, flag);
- //Nothrow swap
- this->swap_data(x);
- }
- //Else do a one by one move
- else{
- this->assign( x.begin(), x.end());
+ if (BOOST_LIKELY(this != &x)) {
+ allocator_type &this_alloc = this->alloc();
+ allocator_type &x_alloc = x.alloc();
+ const bool propagate_alloc = allocator_traits_type::
+ propagate_on_container_move_assignment::value;
+ dtl::bool_<propagate_alloc> flag;
+ const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal;
+ //Resources can be transferred if both allocators are
+ //going to be equal after this function (either propagated or already equal)
+ if(propagate_alloc || allocators_equal){
+ //Destroy objects but retain memory in case x reuses it in the future
+ this->clear();
+ //Move allocator if needed
+ dtl::move_alloc(this_alloc, x_alloc, flag);
+ //Nothrow swap
+ this->swap_data(x);
+ }
+ //Else do a one by one move
+ else{
+ this->assign( x.begin(), x.end());
+ }
}
return *this;
}
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{
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);
//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);
//!
//! <b>Throws</b>: Nothing
//!
- //! <b>Returns</b>: find(basic_string<CharT,traits,Allocator>(s,n),pos).
+ //! <b>Returns</b>: find(basic_string<CharT,traits,allocator_type>(s,n),pos).
size_type find(const CharT* s, size_type pos, size_type n) const
{
if (pos + n > this->size())
//! <b>Throws</b>: Nothing
//!
- //! <b>Returns</b>: find(basic_string<CharT,traits,Allocator>(1,c), pos).
+ //! <b>Returns</b>: find(basic_string<CharT,traits,allocator_type>(1,c), pos).
size_type find(CharT c, size_type pos = 0) const
{
const size_type sz = this->size();
//! <b>Throws</b>: Nothing
//!
- //! <b>Returns</b>: rfind(basic_string<CharT,traits,Allocator>(1,c),pos).
+ //! <b>Returns</b>: rfind(basic_string<CharT,traits,allocator_type>(1,c),pos).
size_type rfind(CharT c, size_type pos = npos) const
{
const size_type len = this->size();
//!
//! <b>Throws</b>: Nothing
//!
- //! <b>Returns</b>: find_first_of(basic_string<CharT,traits,Allocator>(1,c), pos).
+ //! <b>Returns</b>: find_first_of(basic_string<CharT,traits,allocator_type>(1,c), pos).
size_type find_first_of(CharT c, size_type pos = 0) const
{ return this->find(c, pos); }
//!
//! <b>Throws</b>: Nothing
//!
- //! <b>Returns</b>: find_last_of(basic_string<CharT,traits,Allocator>(1,c),pos).
+ //! <b>Returns</b>: find_last_of(basic_string<CharT,traits,allocator_type>(1,c),pos).
size_type find_last_of(const CharT* s, size_type pos = npos) const
{ return find_last_of(s, pos, Traits::length(s)); }
//!
//! <b>Throws</b>: If memory allocation throws or out_of_range if pos > size().
//!
- //! <b>Returns</b>: basic_string<CharT,traits,Allocator>(data()+pos,rlen).
+ //! <b>Returns</b>: basic_string<CharT,traits,allocator_type>(data()+pos,rlen).
basic_string substr(size_type pos = 0, size_type n = npos) const
{
if (pos > this->size())
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);
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
};
+#ifndef BOOST_CONTAINER_NO_CXX17_CTAD
+
+template <typename InputIterator>
+basic_string(InputIterator, InputIterator) ->
+ basic_string<typename iterator_traits<InputIterator>::value_type>;
+
+template <typename InputIterator, typename Allocator>
+basic_string(InputIterator, InputIterator, Allocator const&) ->
+ basic_string<typename iterator_traits<InputIterator>::value_type, Allocator>;
+
+#endif
+
#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED
//!Typedef for a basic_string of
template <class C, class T, class Allocator>
struct has_trivial_destructor_after_move<boost::container::basic_string<C, T, Allocator> >
{
- typedef typename ::boost::container::allocator_traits<Allocator>::pointer pointer;
- static const bool value = ::boost::has_trivial_destructor_after_move<Allocator>::value &&
+ typedef typename boost::container::basic_string<C, T, Allocator>::allocator_type allocator_type;
+ typedef typename ::boost::container::allocator_traits<allocator_type>::pointer pointer;
+ static const bool value = ::boost::has_trivial_destructor_after_move<allocator_type>::value &&
::boost::has_trivial_destructor_after_move<pointer>::value;
};