Home | History | Annotate | Download | only in ext
      1 // Short-string-optimized versatile string base -*- C++ -*-
      2 
      3 // Copyright (C) 2005-2014 Free Software Foundation, Inc.
      4 //
      5 // This file is part of the GNU ISO C++ Library.  This library is free
      6 // software; you can redistribute it and/or modify it under the
      7 // terms of the GNU General Public License as published by the
      8 // Free Software Foundation; either version 3, or (at your option)
      9 // any later version.
     10 
     11 // This library is distributed in the hope that it will be useful,
     12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 // GNU General Public License for more details.
     15 
     16 // Under Section 7 of GPL version 3, you are granted additional
     17 // permissions described in the GCC Runtime Library Exception, version
     18 // 3.1, as published by the Free Software Foundation.
     19 
     20 // You should have received a copy of the GNU General Public License and
     21 // a copy of the GCC Runtime Library Exception along with this program;
     22 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     23 // <http://www.gnu.org/licenses/>.
     24 
     25 /** @file ext/sso_string_base.h
     26  *  This is an internal header file, included by other library headers.
     27  *  Do not attempt to use it directly. @headername{ext/vstring.h}
     28  */
     29 
     30 #ifndef _SSO_STRING_BASE_H
     31 #define _SSO_STRING_BASE_H 1
     32 
     33 namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
     34 {
     35 _GLIBCXX_BEGIN_NAMESPACE_VERSION
     36 
     37   template<typename _CharT, typename _Traits, typename _Alloc>
     38     class __sso_string_base
     39     : protected __vstring_utility<_CharT, _Traits, _Alloc>
     40     {
     41     public:
     42       typedef _Traits					    traits_type;
     43       typedef typename _Traits::char_type		    value_type;
     44 
     45       typedef __vstring_utility<_CharT, _Traits, _Alloc>    _Util_Base;
     46       typedef typename _Util_Base::_CharT_alloc_type        _CharT_alloc_type;
     47       typedef typename _CharT_alloc_type::size_type	    size_type;
     48 
     49     private:
     50       // Data Members:
     51       typename _Util_Base::template _Alloc_hider<_CharT_alloc_type>
     52                                                             _M_dataplus;
     53       size_type                                             _M_string_length;
     54 
     55       enum { _S_local_capacity = 15 };
     56 
     57       union
     58       {
     59 	_CharT           _M_local_data[_S_local_capacity + 1];
     60 	size_type        _M_allocated_capacity;
     61       };
     62 
     63       void
     64       _M_data(_CharT* __p)
     65       { _M_dataplus._M_p = __p; }
     66 
     67       void
     68       _M_length(size_type __length)
     69       { _M_string_length = __length; }
     70 
     71       void
     72       _M_capacity(size_type __capacity)
     73       { _M_allocated_capacity = __capacity; }
     74 
     75       bool
     76       _M_is_local() const
     77       { return _M_data() == _M_local_data; }
     78 
     79       // Create & Destroy
     80       _CharT*
     81       _M_create(size_type&, size_type);
     82 
     83       void
     84       _M_dispose()
     85       {
     86 	if (!_M_is_local())
     87 	  _M_destroy(_M_allocated_capacity);
     88 #if __google_stl_debug_dangling_string
     89 	else {
     90           // Wipe local storage for destructed string with 0xCD.
     91           // This mimics what DebugAllocation does to free()d memory.
     92           __builtin_memset(_M_local_data, 0xcd, sizeof(_M_local_data));
     93         }
     94 #endif
     95       }
     96 
     97       void
     98       _M_destroy(size_type __size) throw()
     99       { _M_get_allocator().deallocate(_M_data(), __size + 1); }
    100 
    101       // _M_construct_aux is used to implement the 21.3.1 para 15 which
    102       // requires special behaviour if _InIterator is an integral type
    103       template<typename _InIterator>
    104         void
    105         _M_construct_aux(_InIterator __beg, _InIterator __end,
    106 			 std::__false_type)
    107 	{
    108           typedef typename iterator_traits<_InIterator>::iterator_category _Tag;
    109           _M_construct(__beg, __end, _Tag());
    110 	}
    111 
    112       // _GLIBCXX_RESOLVE_LIB_DEFECTS
    113       // 438. Ambiguity in the "do the right thing" clause
    114       template<typename _Integer>
    115         void
    116         _M_construct_aux(_Integer __beg, _Integer __end, std::__true_type)
    117 	{ _M_construct_aux_2(static_cast<size_type>(__beg), __end); }
    118 
    119       void
    120       _M_construct_aux_2(size_type __req, _CharT __c)
    121       { _M_construct(__req, __c); }
    122 
    123       template<typename _InIterator>
    124         void
    125         _M_construct(_InIterator __beg, _InIterator __end)
    126 	{
    127 	  typedef typename std::__is_integer<_InIterator>::__type _Integral;
    128 	  _M_construct_aux(__beg, __end, _Integral());
    129         }
    130 
    131       // For Input Iterators, used in istreambuf_iterators, etc.
    132       template<typename _InIterator>
    133         void
    134         _M_construct(_InIterator __beg, _InIterator __end,
    135 		     std::input_iterator_tag);
    136 
    137       // For forward_iterators up to random_access_iterators, used for
    138       // string::iterator, _CharT*, etc.
    139       template<typename _FwdIterator>
    140         void
    141         _M_construct(_FwdIterator __beg, _FwdIterator __end,
    142 		     std::forward_iterator_tag);
    143 
    144       void
    145       _M_construct(size_type __req, _CharT __c);
    146 
    147     public:
    148       size_type
    149       _M_max_size() const
    150       { return (_M_get_allocator().max_size() - 1) / 2; }
    151 
    152       _CharT*
    153       _M_data() const
    154       { return _M_dataplus._M_p; }
    155 
    156       size_type
    157       _M_length() const
    158       { return _M_string_length; }
    159 
    160       size_type
    161       _M_capacity() const
    162       {
    163 	return _M_is_local() ? size_type(_S_local_capacity)
    164 	                     : _M_allocated_capacity;
    165       }
    166 
    167       bool
    168       _M_is_shared() const
    169       { return false; }
    170 
    171       void
    172       _M_set_leaked() { }
    173 
    174       void
    175       _M_leak() { }
    176 
    177       void
    178       _M_set_length_no_wipe(size_type __n)
    179       {
    180 	_M_length(__n);
    181 	traits_type::assign(_M_data()[__n], _CharT());
    182       }
    183 
    184       void
    185       _M_set_length(size_type __n)
    186       {
    187 #if __google_stl_debug_dangling_string
    188 	if (__n + 1 < _M_length())
    189 	  {
    190 	    // Wipe the storage with 0xCD.
    191 	    // Also wipes the old NUL terminator.
    192 	    __builtin_memset(_M_data() + __n + 1, 0xcd, _M_length() - __n);
    193 	  }
    194 #endif
    195 	  _M_set_length_no_wipe(__n);
    196       }
    197 
    198       __sso_string_base()
    199       : _M_dataplus(_M_local_data)
    200       { _M_set_length_no_wipe(0); }
    201 
    202       __sso_string_base(const _Alloc& __a);
    203 
    204       __sso_string_base(const __sso_string_base& __rcs);
    205 
    206 #if __cplusplus >= 201103L
    207       __sso_string_base(__sso_string_base&& __rcs);
    208 #endif
    209 
    210       __sso_string_base(size_type __n, _CharT __c, const _Alloc& __a);
    211 
    212       template<typename _InputIterator>
    213         __sso_string_base(_InputIterator __beg, _InputIterator __end,
    214 			  const _Alloc& __a);
    215 
    216       ~__sso_string_base()
    217       {
    218           _M_dispose();
    219 #ifdef __google_stl_debug_dangling_string
    220           __builtin_memset(this, 0xcd, sizeof(*this));
    221 #endif
    222       }
    223 
    224       _CharT_alloc_type&
    225       _M_get_allocator()
    226       { return _M_dataplus; }
    227 
    228       const _CharT_alloc_type&
    229       _M_get_allocator() const
    230       { return _M_dataplus; }
    231 
    232       void
    233       _M_swap(__sso_string_base& __rcs);
    234 
    235       void
    236       _M_assign(const __sso_string_base& __rcs);
    237 
    238       void
    239       _M_reserve(size_type __res);
    240 
    241       void
    242       _M_mutate(size_type __pos, size_type __len1, const _CharT* __s,
    243 		size_type __len2);
    244 
    245       void
    246       _M_erase(size_type __pos, size_type __n);
    247 
    248       void
    249       _M_clear()
    250       { _M_set_length(0); }
    251 
    252       bool
    253       _M_compare(const __sso_string_base&) const
    254       { return false; }
    255     };
    256 
    257   template<typename _CharT, typename _Traits, typename _Alloc>
    258     void
    259     __sso_string_base<_CharT, _Traits, _Alloc>::
    260     _M_swap(__sso_string_base& __rcs)
    261     {
    262       if (this == &__rcs)
    263 	return;
    264 
    265       // _GLIBCXX_RESOLVE_LIB_DEFECTS
    266       // 431. Swapping containers with unequal allocators.
    267       std::__alloc_swap<_CharT_alloc_type>::_S_do_it(_M_get_allocator(),
    268 						     __rcs._M_get_allocator());
    269 
    270       if (_M_is_local())
    271 	if (__rcs._M_is_local())
    272 	  {
    273 	    if (_M_length() && __rcs._M_length())
    274 	      {
    275 		_CharT __tmp_data[_S_local_capacity + 1];
    276 		traits_type::copy(__tmp_data, __rcs._M_local_data,
    277 				  _S_local_capacity + 1);
    278 		traits_type::copy(__rcs._M_local_data, _M_local_data,
    279 				  _S_local_capacity + 1);
    280 		traits_type::copy(_M_local_data, __tmp_data,
    281 				  _S_local_capacity + 1);
    282 	      }
    283 	    else if (__rcs._M_length())
    284 	      {
    285 		traits_type::copy(_M_local_data, __rcs._M_local_data,
    286 				  _S_local_capacity + 1);
    287 		_M_length(__rcs._M_length());
    288 		__rcs._M_set_length(0);
    289 		return;
    290 	      }
    291 	    else if (_M_length())
    292 	      {
    293 		traits_type::copy(__rcs._M_local_data, _M_local_data,
    294 				  _S_local_capacity + 1);
    295 		__rcs._M_length(_M_length());
    296 		_M_set_length(0);
    297 		return;
    298 	      }
    299 	  }
    300 	else
    301 	  {
    302 	    const size_type __tmp_capacity = __rcs._M_allocated_capacity;
    303 	    traits_type::copy(__rcs._M_local_data, _M_local_data,
    304 			      _S_local_capacity + 1);
    305 	    _M_data(__rcs._M_data());
    306 	    __rcs._M_data(__rcs._M_local_data);
    307 	    _M_capacity(__tmp_capacity);
    308 	  }
    309       else
    310 	{
    311 	  const size_type __tmp_capacity = _M_allocated_capacity;
    312 	  if (__rcs._M_is_local())
    313 	    {
    314 	      traits_type::copy(_M_local_data, __rcs._M_local_data,
    315 				_S_local_capacity + 1);
    316 	      __rcs._M_data(_M_data());
    317 	      _M_data(_M_local_data);
    318 	    }
    319 	  else
    320 	    {
    321 	      _CharT* __tmp_ptr = _M_data();
    322 	      _M_data(__rcs._M_data());
    323 	      __rcs._M_data(__tmp_ptr);
    324 	      _M_capacity(__rcs._M_allocated_capacity);
    325 	    }
    326 	  __rcs._M_capacity(__tmp_capacity);
    327 	}
    328 
    329       const size_type __tmp_length = _M_length();
    330       _M_length(__rcs._M_length());
    331       __rcs._M_length(__tmp_length);
    332     }
    333 
    334   template<typename _CharT, typename _Traits, typename _Alloc>
    335     _CharT*
    336     __sso_string_base<_CharT, _Traits, _Alloc>::
    337     _M_create(size_type& __capacity, size_type __old_capacity)
    338     {
    339       // _GLIBCXX_RESOLVE_LIB_DEFECTS
    340       // 83.  String::npos vs. string::max_size()
    341       if (__capacity > _M_max_size())
    342 	std::__throw_length_error(__N("__sso_string_base::_M_create"));
    343 
    344       // The below implements an exponential growth policy, necessary to
    345       // meet amortized linear time requirements of the library: see
    346       // http://gcc.gnu.org/ml/libstdc++/2001-07/msg00085.html.
    347       if (__capacity > __old_capacity && __capacity < 2 * __old_capacity)
    348 	{
    349 	  __capacity = 2 * __old_capacity;
    350 	  // Never allocate a string bigger than max_size.
    351 	  if (__capacity > _M_max_size())
    352 	    __capacity = _M_max_size();
    353 	}
    354 
    355       // NB: Need an array of char_type[__capacity], plus a terminating
    356       // null char_type() element.
    357       return _M_get_allocator().allocate(__capacity + 1);
    358     }
    359 
    360   template<typename _CharT, typename _Traits, typename _Alloc>
    361     __sso_string_base<_CharT, _Traits, _Alloc>::
    362     __sso_string_base(const _Alloc& __a)
    363     : _M_dataplus(__a, _M_local_data)
    364     { _M_set_length_no_wipe(0); }
    365 
    366   template<typename _CharT, typename _Traits, typename _Alloc>
    367     __sso_string_base<_CharT, _Traits, _Alloc>::
    368     __sso_string_base(const __sso_string_base& __rcs)
    369     : _M_dataplus(__rcs._M_get_allocator(), _M_local_data)
    370     { _M_construct(__rcs._M_data(), __rcs._M_data() + __rcs._M_length()); }
    371 
    372 #if __cplusplus >= 201103L
    373   template<typename _CharT, typename _Traits, typename _Alloc>
    374     __sso_string_base<_CharT, _Traits, _Alloc>::
    375     __sso_string_base(__sso_string_base&& __rcs)
    376     : _M_dataplus(__rcs._M_get_allocator(), _M_local_data)
    377     {
    378       if (__rcs._M_is_local())
    379 	{
    380 	  if (__rcs._M_length())
    381 	    traits_type::copy(_M_local_data, __rcs._M_local_data,
    382 			      _S_local_capacity + 1);
    383 	}
    384       else
    385 	{
    386 	  _M_data(__rcs._M_data());
    387 	  _M_capacity(__rcs._M_allocated_capacity);
    388 	}
    389 
    390       _M_set_length_no_wipe(__rcs._M_length());
    391       __rcs._M_data(__rcs._M_local_data);
    392       __rcs._M_set_length_no_wipe(0);
    393     }
    394 #endif
    395 
    396   template<typename _CharT, typename _Traits, typename _Alloc>
    397     __sso_string_base<_CharT, _Traits, _Alloc>::
    398     __sso_string_base(size_type __n, _CharT __c, const _Alloc& __a)
    399     : _M_dataplus(__a, _M_local_data)
    400     { _M_construct(__n, __c); }
    401 
    402   template<typename _CharT, typename _Traits, typename _Alloc>
    403     template<typename _InputIterator>
    404     __sso_string_base<_CharT, _Traits, _Alloc>::
    405     __sso_string_base(_InputIterator __beg, _InputIterator __end,
    406 		      const _Alloc& __a)
    407     : _M_dataplus(__a, _M_local_data)
    408     { _M_construct(__beg, __end); }
    409 
    410   // NB: This is the special case for Input Iterators, used in
    411   // istreambuf_iterators, etc.
    412   // Input Iterators have a cost structure very different from
    413   // pointers, calling for a different coding style.
    414   template<typename _CharT, typename _Traits, typename _Alloc>
    415     template<typename _InIterator>
    416       void
    417       __sso_string_base<_CharT, _Traits, _Alloc>::
    418       _M_construct(_InIterator __beg, _InIterator __end,
    419 		   std::input_iterator_tag)
    420       {
    421 	size_type __len = 0;
    422 	size_type __capacity = size_type(_S_local_capacity);
    423 
    424 	while (__beg != __end && __len < __capacity)
    425 	  {
    426 	    _M_data()[__len++] = *__beg;
    427 	    ++__beg;
    428 	  }
    429 
    430 	__try
    431 	  {
    432 	    while (__beg != __end)
    433 	      {
    434 		if (__len == __capacity)
    435 		  {
    436 		    // Allocate more space.
    437 		    __capacity = __len + 1;
    438 		    _CharT* __another = _M_create(__capacity, __len);
    439 		    this->_S_copy(__another, _M_data(), __len);
    440 		    _M_dispose();
    441 		    _M_data(__another);
    442 		    _M_capacity(__capacity);
    443 		  }
    444 		_M_data()[__len++] = *__beg;
    445 		++__beg;
    446 	      }
    447 	  }
    448 	__catch(...)
    449 	  {
    450 	    _M_dispose();
    451 	    __throw_exception_again;
    452 	  }
    453 
    454 	_M_set_length_no_wipe(__len);
    455       }
    456 
    457   template<typename _CharT, typename _Traits, typename _Alloc>
    458     template<typename _InIterator>
    459       void
    460       __sso_string_base<_CharT, _Traits, _Alloc>::
    461       _M_construct(_InIterator __beg, _InIterator __end,
    462 		   std::forward_iterator_tag)
    463       {
    464 	// NB: Not required, but considered best practice.
    465 	if (__is_null_pointer(__beg) && __beg != __end)
    466 	  std::__throw_logic_error(__N("__sso_string_base::"
    467 				       "_M_construct null not valid"));
    468 
    469 	size_type __dnew = static_cast<size_type>(std::distance(__beg, __end));
    470 
    471 	if (__dnew > size_type(_S_local_capacity))
    472 	  {
    473 	    _M_data(_M_create(__dnew, size_type(0)));
    474 	    _M_capacity(__dnew);
    475 	  }
    476 
    477 	// Check for out_of_range and length_error exceptions.
    478 	__try
    479 	  { this->_S_copy_chars(_M_data(), __beg, __end); }
    480 	__catch(...)
    481 	  {
    482 	    _M_dispose();
    483 	    __throw_exception_again;
    484 	  }
    485 
    486 	_M_set_length_no_wipe(__dnew);
    487       }
    488 
    489   template<typename _CharT, typename _Traits, typename _Alloc>
    490     void
    491     __sso_string_base<_CharT, _Traits, _Alloc>::
    492     _M_construct(size_type __n, _CharT __c)
    493     {
    494       if (__n > size_type(_S_local_capacity))
    495 	{
    496 	  _M_data(_M_create(__n, size_type(0)));
    497 	  _M_capacity(__n);
    498 	}
    499 
    500       if (__n)
    501 	this->_S_assign(_M_data(), __n, __c);
    502 
    503       _M_set_length_no_wipe(__n);
    504     }
    505 
    506   template<typename _CharT, typename _Traits, typename _Alloc>
    507     void
    508     __sso_string_base<_CharT, _Traits, _Alloc>::
    509     _M_assign(const __sso_string_base& __rcs)
    510     {
    511       if (this != &__rcs)
    512 	{
    513 	  const size_type __rsize = __rcs._M_length();
    514 	  const size_type __capacity = _M_capacity();
    515 
    516 	  if (__rsize > __capacity)
    517 	    {
    518 	      size_type __new_capacity = __rsize;
    519 	      _CharT* __tmp = _M_create(__new_capacity, __capacity);
    520 	      _M_dispose();
    521 	      _M_data(__tmp);
    522 	      _M_capacity(__new_capacity);
    523 	    }
    524 
    525 	  if (__rsize)
    526 	    this->_S_copy(_M_data(), __rcs._M_data(), __rsize);
    527 
    528 	  _M_set_length(__rsize);
    529 	}
    530     }
    531 
    532   template<typename _CharT, typename _Traits, typename _Alloc>
    533     void
    534     __sso_string_base<_CharT, _Traits, _Alloc>::
    535     _M_reserve(size_type __res)
    536     {
    537       // Make sure we don't shrink below the current size.
    538       if (__res < _M_length())
    539 	__res = _M_length();
    540 
    541       const size_type __capacity = _M_capacity();
    542       if (__res != __capacity)
    543 	{
    544 	  if (__res > __capacity
    545 	      || __res > size_type(_S_local_capacity))
    546 	    {
    547 	      _CharT* __tmp = _M_create(__res, __capacity);
    548 	      this->_S_copy(__tmp, _M_data(), _M_length() + 1);
    549 	      _M_dispose();
    550 	      _M_data(__tmp);
    551 	      _M_capacity(__res);
    552 	    }
    553 	  else if (!_M_is_local())
    554 	    {
    555 	      this->_S_copy(_M_local_data, _M_data(), _M_length() + 1);
    556 	      _M_destroy(__capacity);
    557 	      _M_data(_M_local_data);
    558 	    }
    559 	}
    560     }
    561 
    562   template<typename _CharT, typename _Traits, typename _Alloc>
    563     void
    564     __sso_string_base<_CharT, _Traits, _Alloc>::
    565     _M_mutate(size_type __pos, size_type __len1, const _CharT* __s,
    566 	      size_type __len2)
    567     {
    568       const size_type __how_much = _M_length() - __pos - __len1;
    569 
    570       size_type __new_capacity = _M_length() + __len2 - __len1;
    571       _CharT* __r = _M_create(__new_capacity, _M_capacity());
    572 
    573       if (__pos)
    574 	this->_S_copy(__r, _M_data(), __pos);
    575       if (__s && __len2)
    576 	this->_S_copy(__r + __pos, __s, __len2);
    577       if (__how_much)
    578 	this->_S_copy(__r + __pos + __len2,
    579 		      _M_data() + __pos + __len1, __how_much);
    580 
    581       _M_dispose();
    582       _M_data(__r);
    583       _M_capacity(__new_capacity);
    584     }
    585 
    586   template<typename _CharT, typename _Traits, typename _Alloc>
    587     void
    588     __sso_string_base<_CharT, _Traits, _Alloc>::
    589     _M_erase(size_type __pos, size_type __n)
    590     {
    591       const size_type __how_much = _M_length() - __pos - __n;
    592 
    593       if (__how_much && __n)
    594 	this->_S_move(_M_data() + __pos, _M_data() + __pos + __n, __how_much);
    595 
    596       _M_set_length(_M_length() - __n);
    597     }
    598 
    599 _GLIBCXX_END_NAMESPACE_VERSION
    600 } // namespace
    601 
    602 #endif /* _SSO_STRING_BASE_H */
    603