Home | History | Annotate | Download | only in ext
      1 // Short-string-optimized versatile string base -*- C++ -*-
      2 
      3 // Copyright (C) 2005-2013 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       }
     89 
     90       void
     91       _M_destroy(size_type __size) throw()
     92       { _M_get_allocator().deallocate(_M_data(), __size + 1); }
     93 
     94       // _M_construct_aux is used to implement the 21.3.1 para 15 which
     95       // requires special behaviour if _InIterator is an integral type
     96       template<typename _InIterator>
     97         void
     98         _M_construct_aux(_InIterator __beg, _InIterator __end,
     99 			 std::__false_type)
    100 	{
    101           typedef typename iterator_traits<_InIterator>::iterator_category _Tag;
    102           _M_construct(__beg, __end, _Tag());
    103 	}
    104 
    105       // _GLIBCXX_RESOLVE_LIB_DEFECTS
    106       // 438. Ambiguity in the "do the right thing" clause
    107       template<typename _Integer>
    108         void
    109         _M_construct_aux(_Integer __beg, _Integer __end, std::__true_type)
    110 	{ _M_construct_aux_2(static_cast<size_type>(__beg), __end); }
    111 
    112       void
    113       _M_construct_aux_2(size_type __req, _CharT __c)
    114       { _M_construct(__req, __c); }
    115 
    116       template<typename _InIterator>
    117         void
    118         _M_construct(_InIterator __beg, _InIterator __end)
    119 	{
    120 	  typedef typename std::__is_integer<_InIterator>::__type _Integral;
    121 	  _M_construct_aux(__beg, __end, _Integral());
    122         }
    123 
    124       // For Input Iterators, used in istreambuf_iterators, etc.
    125       template<typename _InIterator>
    126         void
    127         _M_construct(_InIterator __beg, _InIterator __end,
    128 		     std::input_iterator_tag);
    129 
    130       // For forward_iterators up to random_access_iterators, used for
    131       // string::iterator, _CharT*, etc.
    132       template<typename _FwdIterator>
    133         void
    134         _M_construct(_FwdIterator __beg, _FwdIterator __end,
    135 		     std::forward_iterator_tag);
    136 
    137       void
    138       _M_construct(size_type __req, _CharT __c);
    139 
    140     public:
    141       size_type
    142       _M_max_size() const
    143       { return (_M_get_allocator().max_size() - 1) / 2; }
    144 
    145       _CharT*
    146       _M_data() const
    147       { return _M_dataplus._M_p; }
    148 
    149       size_type
    150       _M_length() const
    151       { return _M_string_length; }
    152 
    153       size_type
    154       _M_capacity() const
    155       {
    156 	return _M_is_local() ? size_type(_S_local_capacity)
    157 	                     : _M_allocated_capacity;
    158       }
    159 
    160       bool
    161       _M_is_shared() const
    162       { return false; }
    163 
    164       void
    165       _M_set_leaked() { }
    166 
    167       void
    168       _M_leak() { }
    169 
    170       void
    171       _M_set_length(size_type __n)
    172       {
    173 	_M_length(__n);
    174 	traits_type::assign(_M_data()[__n], _CharT());
    175       }
    176 
    177       __sso_string_base()
    178       : _M_dataplus(_M_local_data)
    179       { _M_set_length(0); }
    180 
    181       __sso_string_base(const _Alloc& __a);
    182 
    183       __sso_string_base(const __sso_string_base& __rcs);
    184 
    185 #if __cplusplus >= 201103L
    186       __sso_string_base(__sso_string_base&& __rcs);
    187 #endif
    188 
    189       __sso_string_base(size_type __n, _CharT __c, const _Alloc& __a);
    190 
    191       template<typename _InputIterator>
    192         __sso_string_base(_InputIterator __beg, _InputIterator __end,
    193 			  const _Alloc& __a);
    194 
    195       ~__sso_string_base()
    196       { _M_dispose(); }
    197 
    198       _CharT_alloc_type&
    199       _M_get_allocator()
    200       { return _M_dataplus; }
    201 
    202       const _CharT_alloc_type&
    203       _M_get_allocator() const
    204       { return _M_dataplus; }
    205 
    206       void
    207       _M_swap(__sso_string_base& __rcs);
    208 
    209       void
    210       _M_assign(const __sso_string_base& __rcs);
    211 
    212       void
    213       _M_reserve(size_type __res);
    214 
    215       void
    216       _M_mutate(size_type __pos, size_type __len1, const _CharT* __s,
    217 		size_type __len2);
    218 
    219       void
    220       _M_erase(size_type __pos, size_type __n);
    221 
    222       void
    223       _M_clear()
    224       { _M_set_length(0); }
    225 
    226       bool
    227       _M_compare(const __sso_string_base&) const
    228       { return false; }
    229     };
    230 
    231   template<typename _CharT, typename _Traits, typename _Alloc>
    232     void
    233     __sso_string_base<_CharT, _Traits, _Alloc>::
    234     _M_swap(__sso_string_base& __rcs)
    235     {
    236       if (this == &__rcs)
    237 	return;
    238 
    239       // _GLIBCXX_RESOLVE_LIB_DEFECTS
    240       // 431. Swapping containers with unequal allocators.
    241       std::__alloc_swap<_CharT_alloc_type>::_S_do_it(_M_get_allocator(),
    242 						     __rcs._M_get_allocator());
    243 
    244       if (_M_is_local())
    245 	if (__rcs._M_is_local())
    246 	  {
    247 	    if (_M_length() && __rcs._M_length())
    248 	      {
    249 		_CharT __tmp_data[_S_local_capacity + 1];
    250 		traits_type::copy(__tmp_data, __rcs._M_local_data,
    251 				  _S_local_capacity + 1);
    252 		traits_type::copy(__rcs._M_local_data, _M_local_data,
    253 				  _S_local_capacity + 1);
    254 		traits_type::copy(_M_local_data, __tmp_data,
    255 				  _S_local_capacity + 1);
    256 	      }
    257 	    else if (__rcs._M_length())
    258 	      {
    259 		traits_type::copy(_M_local_data, __rcs._M_local_data,
    260 				  _S_local_capacity + 1);
    261 		_M_length(__rcs._M_length());
    262 		__rcs._M_set_length(0);
    263 		return;
    264 	      }
    265 	    else if (_M_length())
    266 	      {
    267 		traits_type::copy(__rcs._M_local_data, _M_local_data,
    268 				  _S_local_capacity + 1);
    269 		__rcs._M_length(_M_length());
    270 		_M_set_length(0);
    271 		return;
    272 	      }
    273 	  }
    274 	else
    275 	  {
    276 	    const size_type __tmp_capacity = __rcs._M_allocated_capacity;
    277 	    traits_type::copy(__rcs._M_local_data, _M_local_data,
    278 			      _S_local_capacity + 1);
    279 	    _M_data(__rcs._M_data());
    280 	    __rcs._M_data(__rcs._M_local_data);
    281 	    _M_capacity(__tmp_capacity);
    282 	  }
    283       else
    284 	{
    285 	  const size_type __tmp_capacity = _M_allocated_capacity;
    286 	  if (__rcs._M_is_local())
    287 	    {
    288 	      traits_type::copy(_M_local_data, __rcs._M_local_data,
    289 				_S_local_capacity + 1);
    290 	      __rcs._M_data(_M_data());
    291 	      _M_data(_M_local_data);
    292 	    }
    293 	  else
    294 	    {
    295 	      _CharT* __tmp_ptr = _M_data();
    296 	      _M_data(__rcs._M_data());
    297 	      __rcs._M_data(__tmp_ptr);
    298 	      _M_capacity(__rcs._M_allocated_capacity);
    299 	    }
    300 	  __rcs._M_capacity(__tmp_capacity);
    301 	}
    302 
    303       const size_type __tmp_length = _M_length();
    304       _M_length(__rcs._M_length());
    305       __rcs._M_length(__tmp_length);
    306     }
    307 
    308   template<typename _CharT, typename _Traits, typename _Alloc>
    309     _CharT*
    310     __sso_string_base<_CharT, _Traits, _Alloc>::
    311     _M_create(size_type& __capacity, size_type __old_capacity)
    312     {
    313       // _GLIBCXX_RESOLVE_LIB_DEFECTS
    314       // 83.  String::npos vs. string::max_size()
    315       if (__capacity > _M_max_size())
    316 	std::__throw_length_error(__N("__sso_string_base::_M_create"));
    317 
    318       // The below implements an exponential growth policy, necessary to
    319       // meet amortized linear time requirements of the library: see
    320       // http://gcc.gnu.org/ml/libstdc++/2001-07/msg00085.html.
    321       if (__capacity > __old_capacity && __capacity < 2 * __old_capacity)
    322 	{
    323 	  __capacity = 2 * __old_capacity;
    324 	  // Never allocate a string bigger than max_size.
    325 	  if (__capacity > _M_max_size())
    326 	    __capacity = _M_max_size();
    327 	}
    328 
    329       // NB: Need an array of char_type[__capacity], plus a terminating
    330       // null char_type() element.
    331       return _M_get_allocator().allocate(__capacity + 1);
    332     }
    333 
    334   template<typename _CharT, typename _Traits, typename _Alloc>
    335     __sso_string_base<_CharT, _Traits, _Alloc>::
    336     __sso_string_base(const _Alloc& __a)
    337     : _M_dataplus(__a, _M_local_data)
    338     { _M_set_length(0); }
    339 
    340   template<typename _CharT, typename _Traits, typename _Alloc>
    341     __sso_string_base<_CharT, _Traits, _Alloc>::
    342     __sso_string_base(const __sso_string_base& __rcs)
    343     : _M_dataplus(__rcs._M_get_allocator(), _M_local_data)
    344     { _M_construct(__rcs._M_data(), __rcs._M_data() + __rcs._M_length()); }
    345 
    346 #if __cplusplus >= 201103L
    347   template<typename _CharT, typename _Traits, typename _Alloc>
    348     __sso_string_base<_CharT, _Traits, _Alloc>::
    349     __sso_string_base(__sso_string_base&& __rcs)
    350     : _M_dataplus(__rcs._M_get_allocator(), _M_local_data)
    351     {
    352       if (__rcs._M_is_local())
    353 	{
    354 	  if (__rcs._M_length())
    355 	    traits_type::copy(_M_local_data, __rcs._M_local_data,
    356 			      _S_local_capacity + 1);
    357 	}
    358       else
    359 	{
    360 	  _M_data(__rcs._M_data());
    361 	  _M_capacity(__rcs._M_allocated_capacity);
    362 	}
    363 
    364       _M_set_length(__rcs._M_length());
    365       __rcs._M_data(__rcs._M_local_data);
    366       __rcs._M_set_length(0);
    367     }
    368 #endif
    369 
    370   template<typename _CharT, typename _Traits, typename _Alloc>
    371     __sso_string_base<_CharT, _Traits, _Alloc>::
    372     __sso_string_base(size_type __n, _CharT __c, const _Alloc& __a)
    373     : _M_dataplus(__a, _M_local_data)
    374     { _M_construct(__n, __c); }
    375 
    376   template<typename _CharT, typename _Traits, typename _Alloc>
    377     template<typename _InputIterator>
    378     __sso_string_base<_CharT, _Traits, _Alloc>::
    379     __sso_string_base(_InputIterator __beg, _InputIterator __end,
    380 		      const _Alloc& __a)
    381     : _M_dataplus(__a, _M_local_data)
    382     { _M_construct(__beg, __end); }
    383 
    384   // NB: This is the special case for Input Iterators, used in
    385   // istreambuf_iterators, etc.
    386   // Input Iterators have a cost structure very different from
    387   // pointers, calling for a different coding style.
    388   template<typename _CharT, typename _Traits, typename _Alloc>
    389     template<typename _InIterator>
    390       void
    391       __sso_string_base<_CharT, _Traits, _Alloc>::
    392       _M_construct(_InIterator __beg, _InIterator __end,
    393 		   std::input_iterator_tag)
    394       {
    395 	size_type __len = 0;
    396 	size_type __capacity = size_type(_S_local_capacity);
    397 
    398 	while (__beg != __end && __len < __capacity)
    399 	  {
    400 	    _M_data()[__len++] = *__beg;
    401 	    ++__beg;
    402 	  }
    403 
    404 	__try
    405 	  {
    406 	    while (__beg != __end)
    407 	      {
    408 		if (__len == __capacity)
    409 		  {
    410 		    // Allocate more space.
    411 		    __capacity = __len + 1;
    412 		    _CharT* __another = _M_create(__capacity, __len);
    413 		    this->_S_copy(__another, _M_data(), __len);
    414 		    _M_dispose();
    415 		    _M_data(__another);
    416 		    _M_capacity(__capacity);
    417 		  }
    418 		_M_data()[__len++] = *__beg;
    419 		++__beg;
    420 	      }
    421 	  }
    422 	__catch(...)
    423 	  {
    424 	    _M_dispose();
    425 	    __throw_exception_again;
    426 	  }
    427 
    428 	_M_set_length(__len);
    429       }
    430 
    431   template<typename _CharT, typename _Traits, typename _Alloc>
    432     template<typename _InIterator>
    433       void
    434       __sso_string_base<_CharT, _Traits, _Alloc>::
    435       _M_construct(_InIterator __beg, _InIterator __end,
    436 		   std::forward_iterator_tag)
    437       {
    438 	// NB: Not required, but considered best practice.
    439 	if (__is_null_pointer(__beg) && __beg != __end)
    440 	  std::__throw_logic_error(__N("__sso_string_base::"
    441 				       "_M_construct null not valid"));
    442 
    443 	size_type __dnew = static_cast<size_type>(std::distance(__beg, __end));
    444 
    445 	if (__dnew > size_type(_S_local_capacity))
    446 	  {
    447 	    _M_data(_M_create(__dnew, size_type(0)));
    448 	    _M_capacity(__dnew);
    449 	  }
    450 
    451 	// Check for out_of_range and length_error exceptions.
    452 	__try
    453 	  { this->_S_copy_chars(_M_data(), __beg, __end); }
    454 	__catch(...)
    455 	  {
    456 	    _M_dispose();
    457 	    __throw_exception_again;
    458 	  }
    459 
    460 	_M_set_length(__dnew);
    461       }
    462 
    463   template<typename _CharT, typename _Traits, typename _Alloc>
    464     void
    465     __sso_string_base<_CharT, _Traits, _Alloc>::
    466     _M_construct(size_type __n, _CharT __c)
    467     {
    468       if (__n > size_type(_S_local_capacity))
    469 	{
    470 	  _M_data(_M_create(__n, size_type(0)));
    471 	  _M_capacity(__n);
    472 	}
    473 
    474       if (__n)
    475 	this->_S_assign(_M_data(), __n, __c);
    476 
    477       _M_set_length(__n);
    478     }
    479 
    480   template<typename _CharT, typename _Traits, typename _Alloc>
    481     void
    482     __sso_string_base<_CharT, _Traits, _Alloc>::
    483     _M_assign(const __sso_string_base& __rcs)
    484     {
    485       if (this != &__rcs)
    486 	{
    487 	  const size_type __rsize = __rcs._M_length();
    488 	  const size_type __capacity = _M_capacity();
    489 
    490 	  if (__rsize > __capacity)
    491 	    {
    492 	      size_type __new_capacity = __rsize;
    493 	      _CharT* __tmp = _M_create(__new_capacity, __capacity);
    494 	      _M_dispose();
    495 	      _M_data(__tmp);
    496 	      _M_capacity(__new_capacity);
    497 	    }
    498 
    499 	  if (__rsize)
    500 	    this->_S_copy(_M_data(), __rcs._M_data(), __rsize);
    501 
    502 	  _M_set_length(__rsize);
    503 	}
    504     }
    505 
    506   template<typename _CharT, typename _Traits, typename _Alloc>
    507     void
    508     __sso_string_base<_CharT, _Traits, _Alloc>::
    509     _M_reserve(size_type __res)
    510     {
    511       // Make sure we don't shrink below the current size.
    512       if (__res < _M_length())
    513 	__res = _M_length();
    514 
    515       const size_type __capacity = _M_capacity();
    516       if (__res != __capacity)
    517 	{
    518 	  if (__res > __capacity
    519 	      || __res > size_type(_S_local_capacity))
    520 	    {
    521 	      _CharT* __tmp = _M_create(__res, __capacity);
    522 	      this->_S_copy(__tmp, _M_data(), _M_length() + 1);
    523 	      _M_dispose();
    524 	      _M_data(__tmp);
    525 	      _M_capacity(__res);
    526 	    }
    527 	  else if (!_M_is_local())
    528 	    {
    529 	      this->_S_copy(_M_local_data, _M_data(), _M_length() + 1);
    530 	      _M_destroy(__capacity);
    531 	      _M_data(_M_local_data);
    532 	    }
    533 	}
    534     }
    535 
    536   template<typename _CharT, typename _Traits, typename _Alloc>
    537     void
    538     __sso_string_base<_CharT, _Traits, _Alloc>::
    539     _M_mutate(size_type __pos, size_type __len1, const _CharT* __s,
    540 	      size_type __len2)
    541     {
    542       const size_type __how_much = _M_length() - __pos - __len1;
    543 
    544       size_type __new_capacity = _M_length() + __len2 - __len1;
    545       _CharT* __r = _M_create(__new_capacity, _M_capacity());
    546 
    547       if (__pos)
    548 	this->_S_copy(__r, _M_data(), __pos);
    549       if (__s && __len2)
    550 	this->_S_copy(__r + __pos, __s, __len2);
    551       if (__how_much)
    552 	this->_S_copy(__r + __pos + __len2,
    553 		      _M_data() + __pos + __len1, __how_much);
    554 
    555       _M_dispose();
    556       _M_data(__r);
    557       _M_capacity(__new_capacity);
    558     }
    559 
    560   template<typename _CharT, typename _Traits, typename _Alloc>
    561     void
    562     __sso_string_base<_CharT, _Traits, _Alloc>::
    563     _M_erase(size_type __pos, size_type __n)
    564     {
    565       const size_type __how_much = _M_length() - __pos - __n;
    566 
    567       if (__how_much && __n)
    568 	this->_S_move(_M_data() + __pos, _M_data() + __pos + __n, __how_much);
    569 
    570       _M_set_length(_M_length() - __n);
    571     }
    572 
    573 _GLIBCXX_END_NAMESPACE_VERSION
    574 } // namespace
    575 
    576 #endif /* _SSO_STRING_BASE_H */
    577