1  // Reference-counted versatile string base -*- C++ -*-
       2  
       3  // Copyright (C) 2005-2023 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/rc_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 _RC_STRING_BASE_H
      31  #define _RC_STRING_BASE_H 1
      32  
      33  #include <bits/requires_hosted.h> // GNU extensions are currently omitted
      34  
      35  #include <ext/atomicity.h>
      36  #include <ext/alloc_traits.h>
      37  #include <bits/stl_iterator_base_funcs.h>
      38  
      39  namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
      40  {
      41  _GLIBCXX_BEGIN_NAMESPACE_VERSION
      42  
      43    /**
      44     *  Documentation?  What's that?
      45     *  Nathan Myers <ncm@cantrip.org>.
      46     *
      47     *  A string looks like this:
      48     *
      49     *  @code
      50     *                                        [_Rep]
      51     *                                        _M_length
      52     *   [__rc_string_base<char_type>]        _M_capacity
      53     *   _M_dataplus                          _M_refcount
      54     *   _M_p ---------------->               unnamed array of char_type
      55     *  @endcode
      56     *
      57     *  Where the _M_p points to the first character in the string, and
      58     *  you cast it to a pointer-to-_Rep and subtract 1 to get a
      59     *  pointer to the header.
      60     *
      61     *  This approach has the enormous advantage that a string object
      62     *  requires only one allocation.  All the ugliness is confined
      63     *  within a single pair of inline functions, which each compile to
      64     *  a single @a add instruction: _Rep::_M_refdata(), and
      65     *  __rc_string_base::_M_rep(); and the allocation function which gets a
      66     *  block of raw bytes and with room enough and constructs a _Rep
      67     *  object at the front.
      68     *
      69     *  The reason you want _M_data pointing to the character array and
      70     *  not the _Rep is so that the debugger can see the string
      71     *  contents. (Probably we should add a non-inline member to get
      72     *  the _Rep for the debugger to use, so users can check the actual
      73     *  string length.)
      74     *
      75     *  Note that the _Rep object is a POD so that you can have a
      76     *  static <em>empty string</em> _Rep object already @a constructed before
      77     *  static constructors have run.  The reference-count encoding is
      78     *  chosen so that a 0 indicates one reference, so you never try to
      79     *  destroy the empty-string _Rep object.
      80     *
      81     *  All but the last paragraph is considered pretty conventional
      82     *  for a C++ string implementation.
      83    */
      84   template<typename _CharT, typename _Traits, typename _Alloc>
      85      class __rc_string_base
      86      : protected __vstring_utility<_CharT, _Traits, _Alloc>
      87      {
      88      public:
      89        typedef _Traits					    traits_type;
      90        typedef typename _Traits::char_type		    value_type;
      91        typedef _Alloc					    allocator_type;
      92  
      93        typedef __vstring_utility<_CharT, _Traits, _Alloc>    _Util_Base;
      94        typedef typename _Util_Base::_CharT_alloc_type        _CharT_alloc_type;
      95        typedef typename _CharT_alloc_type::size_type	    size_type;
      96  
      97      private:
      98        // _Rep: string representation
      99        //   Invariants:
     100        //   1. String really contains _M_length + 1 characters: due to 21.3.4
     101        //      must be kept null-terminated.
     102        //   2. _M_capacity >= _M_length
     103        //      Allocated memory is always (_M_capacity + 1) * sizeof(_CharT).
     104        //   3. _M_refcount has three states:
     105        //      -1: leaked, one reference, no ref-copies allowed, non-const.
     106        //       0: one reference, non-const.
     107        //     n>0: n + 1 references, operations require a lock, const.
     108        //   4. All fields == 0 is an empty string, given the extra storage
     109        //      beyond-the-end for a null terminator; thus, the shared
     110        //      empty string representation needs no constructor.
     111        struct _Rep
     112        {
     113  	union
     114  	{
     115  	  struct
     116  	  {
     117  	    size_type	    _M_length;
     118  	    size_type	    _M_capacity;
     119  	    _Atomic_word    _M_refcount;
     120  	  }                 _M_info;
     121  
     122  	  // Only for alignment purposes.
     123  	  _CharT            _M_align;
     124  	};
     125  
     126  	typedef typename __alloc_traits<_Alloc>::template rebind<_Rep>::other
     127  	  _Rep_alloc_type;
     128  
     129   	_CharT*
     130  	_M_refdata() throw()
     131  	{ return reinterpret_cast<_CharT*>(this + 1); }
     132  
     133  	_CharT*
     134  	_M_refcopy() throw()
     135  	{
     136  	  __atomic_add_dispatch(&_M_info._M_refcount, 1);
     137  	  return _M_refdata();
     138  	}  // XXX MT
     139  
     140  	void
     141  	_M_set_length(size_type __n)
     142  	{
     143  	  _M_info._M_refcount = 0;  // One reference.
     144  	  _M_info._M_length = __n;
     145  	  // grrr. (per 21.3.4)
     146  	  // You cannot leave those LWG people alone for a second.
     147  	  traits_type::assign(_M_refdata()[__n], _CharT());
     148  	}
     149  
     150  	// Create & Destroy
     151  	static _Rep*
     152  	_S_create(size_type, size_type, const _Alloc&);
     153  
     154  	void
     155  	_M_destroy(const _Alloc&) throw();
     156  
     157  	_CharT*
     158  	_M_clone(const _Alloc&, size_type __res = 0);
     159        };
     160  
     161        struct _Rep_empty
     162        : public _Rep
     163        {
     164  	_CharT              _M_terminal;
     165        };
     166  
     167        static _Rep_empty     _S_empty_rep;
     168  
     169        // The maximum number of individual char_type elements of an
     170        // individual string is determined by _S_max_size. This is the
     171        // value that will be returned by max_size().  (Whereas npos
     172        // is the maximum number of bytes the allocator can allocate.)
     173        // If one was to divvy up the theoretical largest size string,
     174        // with a terminating character and m _CharT elements, it'd
     175        // look like this:
     176        // npos = sizeof(_Rep) + (m * sizeof(_CharT)) + sizeof(_CharT)
     177        //        + sizeof(_Rep) - 1
     178        // (NB: last two terms for rounding reasons, see _M_create below)
     179        // Solving for m:
     180        // m = ((npos - 2 * sizeof(_Rep) + 1) / sizeof(_CharT)) - 1
     181        // In addition, this implementation halves this amount.
     182        enum { _S_max_size = (((static_cast<size_type>(-1) - 2 * sizeof(_Rep)
     183  			      + 1) / sizeof(_CharT)) - 1) / 2 };
     184  
     185        // Data Member (private):
     186        mutable typename _Util_Base::template _Alloc_hider<_Alloc>  _M_dataplus;
     187  
     188        void
     189        _M_data(_CharT* __p)
     190        { _M_dataplus._M_p = __p; }
     191  
     192        _Rep*
     193        _M_rep() const
     194        { return &((reinterpret_cast<_Rep*>(_M_data()))[-1]); }
     195  
     196        _CharT*
     197        _M_grab(const _Alloc& __alloc) const
     198        {
     199  	return (!_M_is_leaked() && _M_get_allocator() == __alloc)
     200  		? _M_rep()->_M_refcopy() : _M_rep()->_M_clone(__alloc);
     201        }
     202  
     203        void
     204        _M_dispose()
     205        {
     206  	// Be race-detector-friendly.  For more info see bits/c++config.
     207  	_GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_rep()->_M_info.
     208  						_M_refcount);
     209  	if (__exchange_and_add_dispatch(&_M_rep()->_M_info._M_refcount,
     210  					-1) <= 0)
     211  	  {
     212  	    _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_rep()->_M_info.
     213  						   _M_refcount);
     214  	    _M_rep()->_M_destroy(_M_get_allocator());
     215  	  }
     216        }  // XXX MT
     217  
     218        bool
     219        _M_is_leaked() const
     220        { return _M_rep()->_M_info._M_refcount < 0; }
     221  
     222        void
     223        _M_set_sharable()
     224        { _M_rep()->_M_info._M_refcount = 0; }
     225  
     226        void
     227        _M_leak_hard();
     228  
     229        // _S_construct_aux is used to implement the 21.3.1 para 15 which
     230        // requires special behaviour if _InIterator is an integral type
     231        template<typename _InIterator>
     232  	static _CharT*
     233  	_S_construct_aux(_InIterator __beg, _InIterator __end,
     234  			 const _Alloc& __a, std::__false_type)
     235  	{
     236  	  typedef typename std::iterator_traits<_InIterator>::iterator_category
     237  	    _Tag;
     238  	  return _S_construct(__beg, __end, __a, _Tag());
     239  	}
     240  
     241        // _GLIBCXX_RESOLVE_LIB_DEFECTS
     242        // 438. Ambiguity in the "do the right thing" clause
     243        template<typename _Integer>
     244  	static _CharT*
     245  	_S_construct_aux(_Integer __beg, _Integer __end,
     246  			 const _Alloc& __a, std::__true_type)
     247  	{ return _S_construct_aux_2(static_cast<size_type>(__beg),
     248  				    __end, __a); }
     249  
     250        static _CharT*
     251        _S_construct_aux_2(size_type __req, _CharT __c, const _Alloc& __a)
     252        { return _S_construct(__req, __c, __a); }
     253  
     254        template<typename _InIterator>
     255  	static _CharT*
     256  	_S_construct(_InIterator __beg, _InIterator __end, const _Alloc& __a)
     257  	{
     258  	  typedef typename std::__is_integer<_InIterator>::__type _Integral;
     259  	  return _S_construct_aux(__beg, __end, __a, _Integral());
     260  	}
     261  
     262        // For Input Iterators, used in istreambuf_iterators, etc.
     263        template<typename _InIterator>
     264  	static _CharT*
     265  	 _S_construct(_InIterator __beg, _InIterator __end, const _Alloc& __a,
     266  		      std::input_iterator_tag);
     267  
     268        // For forward_iterators up to random_access_iterators, used for
     269        // string::iterator, _CharT*, etc.
     270        template<typename _FwdIterator>
     271  	static _CharT*
     272  	_S_construct(_FwdIterator __beg, _FwdIterator __end, const _Alloc& __a,
     273  		     std::forward_iterator_tag);
     274  
     275        static _CharT*
     276        _S_construct(size_type __req, _CharT __c, const _Alloc& __a);
     277  
     278      public:
     279        size_type
     280        _M_max_size() const
     281        { return size_type(_S_max_size); }
     282  
     283        _CharT*
     284        _M_data() const
     285        { return _M_dataplus._M_p; }
     286  
     287        size_type
     288        _M_length() const
     289        { return _M_rep()->_M_info._M_length; }
     290  
     291        size_type
     292        _M_capacity() const
     293        { return _M_rep()->_M_info._M_capacity; }
     294  
     295        bool
     296        _M_is_shared() const
     297        { return _M_rep()->_M_info._M_refcount > 0; }
     298  
     299        void
     300        _M_set_leaked()
     301        { _M_rep()->_M_info._M_refcount = -1; }
     302  
     303        void
     304        _M_leak()    // for use in begin() & non-const op[]
     305        {
     306  	if (!_M_is_leaked())
     307  	  _M_leak_hard();
     308        }
     309  
     310        void
     311        _M_set_length(size_type __n)
     312        { _M_rep()->_M_set_length(__n); }
     313  
     314        __rc_string_base()
     315        : _M_dataplus(_S_empty_rep._M_refcopy()) { }
     316  
     317        __rc_string_base(const _Alloc& __a);
     318  
     319        __rc_string_base(const __rc_string_base& __rcs);
     320  
     321  #if __cplusplus >= 201103L
     322        __rc_string_base(__rc_string_base&& __rcs)
     323        : _M_dataplus(__rcs._M_dataplus)
     324        { __rcs._M_data(_S_empty_rep._M_refcopy()); }
     325  #endif
     326  
     327        __rc_string_base(size_type __n, _CharT __c, const _Alloc& __a);
     328  
     329        template<typename _InputIterator>
     330  	__rc_string_base(_InputIterator __beg, _InputIterator __end,
     331  			 const _Alloc& __a);
     332  
     333        ~__rc_string_base()
     334        { _M_dispose(); }
     335  
     336        allocator_type&
     337        _M_get_allocator()
     338        { return _M_dataplus; }
     339  
     340        const allocator_type&
     341        _M_get_allocator() const
     342        { return _M_dataplus; }
     343  
     344        void
     345        _M_swap(__rc_string_base& __rcs);
     346  
     347        void
     348        _M_assign(const __rc_string_base& __rcs);
     349  
     350        void
     351        _M_reserve(size_type __res);
     352  
     353        void
     354        _M_mutate(size_type __pos, size_type __len1, const _CharT* __s,
     355  		size_type __len2);
     356  
     357        void
     358        _M_erase(size_type __pos, size_type __n);
     359  
     360        void
     361        _M_clear()
     362        {
     363  	_M_dispose();
     364  	_M_data(_S_empty_rep._M_refcopy());
     365        }
     366  
     367        bool
     368        _M_compare(const __rc_string_base&) const
     369        { return false; }
     370      };
     371  
     372    template<typename _CharT, typename _Traits, typename _Alloc>
     373      typename __rc_string_base<_CharT, _Traits, _Alloc>::_Rep_empty
     374      __rc_string_base<_CharT, _Traits, _Alloc>::_S_empty_rep;
     375  
     376    template<typename _CharT, typename _Traits, typename _Alloc>
     377      typename __rc_string_base<_CharT, _Traits, _Alloc>::_Rep*
     378      __rc_string_base<_CharT, _Traits, _Alloc>::_Rep::
     379      _S_create(size_type __capacity, size_type __old_capacity,
     380  	      const _Alloc& __alloc)
     381      {
     382        // _GLIBCXX_RESOLVE_LIB_DEFECTS
     383        // 83.  String::npos vs. string::max_size()
     384        if (__capacity > size_type(_S_max_size))
     385  	std::__throw_length_error(__N("__rc_string_base::_Rep::_S_create"));
     386  
     387        // The standard places no restriction on allocating more memory
     388        // than is strictly needed within this layer at the moment or as
     389        // requested by an explicit application call to reserve().
     390  
     391        // Many malloc implementations perform quite poorly when an
     392        // application attempts to allocate memory in a stepwise fashion
     393        // growing each allocation size by only 1 char.  Additionally,
     394        // it makes little sense to allocate less linear memory than the
     395        // natural blocking size of the malloc implementation.
     396        // Unfortunately, we would need a somewhat low-level calculation
     397        // with tuned parameters to get this perfect for any particular
     398        // malloc implementation.  Fortunately, generalizations about
     399        // common features seen among implementations seems to suffice.
     400  
     401        // __pagesize need not match the actual VM page size for good
     402        // results in practice, thus we pick a common value on the low
     403        // side.  __malloc_header_size is an estimate of the amount of
     404        // overhead per memory allocation (in practice seen N * sizeof
     405        // (void*) where N is 0, 2 or 4).  According to folklore,
     406        // picking this value on the high side is better than
     407        // low-balling it (especially when this algorithm is used with
     408        // malloc implementations that allocate memory blocks rounded up
     409        // to a size which is a power of 2).
     410        const size_type __pagesize = 4096;
     411        const size_type __malloc_header_size = 4 * sizeof(void*);
     412  
     413        // The below implements an exponential growth policy, necessary to
     414        // meet amortized linear time requirements of the library: see
     415        // http://gcc.gnu.org/ml/libstdc++/2001-07/msg00085.html.
     416        if (__capacity > __old_capacity && __capacity < 2 * __old_capacity)
     417  	{
     418  	  __capacity = 2 * __old_capacity;
     419  	  // Never allocate a string bigger than _S_max_size.
     420  	  if (__capacity > size_type(_S_max_size))
     421  	    __capacity = size_type(_S_max_size);
     422  	}
     423  
     424        // NB: Need an array of char_type[__capacity], plus a terminating
     425        // null char_type() element, plus enough for the _Rep data structure,
     426        // plus sizeof(_Rep) - 1 to upper round to a size multiple of
     427        // sizeof(_Rep).
     428        // Whew. Seemingly so needy, yet so elemental.
     429        size_type __size = ((__capacity + 1) * sizeof(_CharT)
     430  			  + 2 * sizeof(_Rep) - 1);
     431  
     432        const size_type __adj_size = __size + __malloc_header_size;
     433        if (__adj_size > __pagesize && __capacity > __old_capacity)
     434  	{
     435  	  const size_type __extra = __pagesize - __adj_size % __pagesize;
     436  	  __capacity += __extra / sizeof(_CharT);
     437  	  if (__capacity > size_type(_S_max_size))
     438  	    __capacity = size_type(_S_max_size);
     439  	  __size = (__capacity + 1) * sizeof(_CharT) + 2 * sizeof(_Rep) - 1;
     440  	}
     441  
     442        // NB: Might throw, but no worries about a leak, mate: _Rep()
     443        // does not throw.
     444        _Rep* __place = _Rep_alloc_type(__alloc).allocate(__size / sizeof(_Rep));
     445        _Rep* __p = new (__place) _Rep;
     446        __p->_M_info._M_capacity = __capacity;
     447        return __p;
     448      }
     449  
     450    template<typename _CharT, typename _Traits, typename _Alloc>
     451      void
     452      __rc_string_base<_CharT, _Traits, _Alloc>::_Rep::
     453      _M_destroy(const _Alloc& __a) throw ()
     454      {
     455        const size_type __size = ((_M_info._M_capacity + 1) * sizeof(_CharT)
     456  				+ 2 * sizeof(_Rep) - 1);
     457        _Rep_alloc_type(__a).deallocate(this, __size / sizeof(_Rep));
     458      }
     459  
     460    template<typename _CharT, typename _Traits, typename _Alloc>
     461      _CharT*
     462      __rc_string_base<_CharT, _Traits, _Alloc>::_Rep::
     463      _M_clone(const _Alloc& __alloc, size_type __res)
     464      {
     465        // Requested capacity of the clone.
     466        const size_type __requested_cap = _M_info._M_length + __res;
     467        _Rep* __r = _Rep::_S_create(__requested_cap, _M_info._M_capacity,
     468  				  __alloc);
     469  
     470        if (_M_info._M_length)
     471  	__rc_string_base::_S_copy(__r->_M_refdata(), _M_refdata(), _M_info._M_length);
     472  
     473        __r->_M_set_length(_M_info._M_length);
     474        return __r->_M_refdata();
     475      }
     476  
     477    template<typename _CharT, typename _Traits, typename _Alloc>
     478      __rc_string_base<_CharT, _Traits, _Alloc>::
     479      __rc_string_base(const _Alloc& __a)
     480      : _M_dataplus(__a, _S_construct(size_type(), _CharT(), __a)) { }
     481  
     482    template<typename _CharT, typename _Traits, typename _Alloc>
     483      __rc_string_base<_CharT, _Traits, _Alloc>::
     484      __rc_string_base(const __rc_string_base& __rcs)
     485      : _M_dataplus(__rcs._M_get_allocator(),
     486  		  __rcs._M_grab(__rcs._M_get_allocator())) { }
     487  
     488    template<typename _CharT, typename _Traits, typename _Alloc>
     489      __rc_string_base<_CharT, _Traits, _Alloc>::
     490      __rc_string_base(size_type __n, _CharT __c, const _Alloc& __a)
     491      : _M_dataplus(__a, _S_construct(__n, __c, __a)) { }
     492  
     493    template<typename _CharT, typename _Traits, typename _Alloc>
     494      template<typename _InputIterator>
     495      __rc_string_base<_CharT, _Traits, _Alloc>::
     496      __rc_string_base(_InputIterator __beg, _InputIterator __end,
     497  		     const _Alloc& __a)
     498      : _M_dataplus(__a, _S_construct(__beg, __end, __a)) { }
     499  
     500    template<typename _CharT, typename _Traits, typename _Alloc>
     501      void
     502      __rc_string_base<_CharT, _Traits, _Alloc>::
     503      _M_leak_hard()
     504      {
     505        if (_M_is_shared())
     506  	_M_erase(0, 0);
     507        _M_set_leaked();
     508      }
     509  
     510    // NB: This is the special case for Input Iterators, used in
     511    // istreambuf_iterators, etc.
     512    // Input Iterators have a cost structure very different from
     513    // pointers, calling for a different coding style.
     514    template<typename _CharT, typename _Traits, typename _Alloc>
     515      template<typename _InIterator>
     516        _CharT*
     517        __rc_string_base<_CharT, _Traits, _Alloc>::
     518        _S_construct(_InIterator __beg, _InIterator __end, const _Alloc& __a,
     519  		   std::input_iterator_tag)
     520        {
     521  	if (__beg == __end && __a == _Alloc())
     522  	  return _S_empty_rep._M_refcopy();
     523  
     524  	// Avoid reallocation for common case.
     525  	_CharT __buf[128];
     526  	size_type __len = 0;
     527  	while (__beg != __end && __len < sizeof(__buf) / sizeof(_CharT))
     528  	  {
     529  	    __buf[__len++] = *__beg;
     530  	    ++__beg;
     531  	  }
     532  	_Rep* __r = _Rep::_S_create(__len, size_type(0), __a);
     533  	_S_copy(__r->_M_refdata(), __buf, __len);
     534  	__try
     535  	  {
     536  	    while (__beg != __end)
     537  	      {
     538  		if (__len == __r->_M_info._M_capacity)
     539  		  {
     540  		    // Allocate more space.
     541  		    _Rep* __another = _Rep::_S_create(__len + 1, __len, __a);
     542  		    _S_copy(__another->_M_refdata(), __r->_M_refdata(), __len);
     543  		    __r->_M_destroy(__a);
     544  		    __r = __another;
     545  		  }
     546  		__r->_M_refdata()[__len++] = *__beg;
     547  		++__beg;
     548  	      }
     549  	  }
     550  	__catch(...)
     551  	  {
     552  	    __r->_M_destroy(__a);
     553  	    __throw_exception_again;
     554  	  }
     555  	__r->_M_set_length(__len);
     556  	return __r->_M_refdata();
     557        }
     558  
     559    template<typename _CharT, typename _Traits, typename _Alloc>
     560      template<typename _InIterator>
     561        _CharT*
     562        __rc_string_base<_CharT, _Traits, _Alloc>::
     563        _S_construct(_InIterator __beg, _InIterator __end, const _Alloc& __a,
     564  		   std::forward_iterator_tag)
     565        {
     566  	if (__beg == __end && __a == _Alloc())
     567  	  return _S_empty_rep._M_refcopy();
     568  
     569  	// NB: Not required, but considered best practice.
     570  	if (__is_null_pointer(__beg) && __beg != __end)
     571  	  std::__throw_logic_error(__N("__rc_string_base::"
     572  				       "_S_construct null not valid"));
     573  
     574  	const size_type __dnew = static_cast<size_type>(std::distance(__beg,
     575  								      __end));
     576  	// Check for out_of_range and length_error exceptions.
     577  	_Rep* __r = _Rep::_S_create(__dnew, size_type(0), __a);
     578  	__try
     579  	  { __rc_string_base::_S_copy_chars(__r->_M_refdata(), __beg, __end); }
     580  	__catch(...)
     581  	  {
     582  	    __r->_M_destroy(__a);
     583  	    __throw_exception_again;
     584  	  }
     585  	__r->_M_set_length(__dnew);
     586  	return __r->_M_refdata();
     587        }
     588  
     589    template<typename _CharT, typename _Traits, typename _Alloc>
     590      _CharT*
     591      __rc_string_base<_CharT, _Traits, _Alloc>::
     592      _S_construct(size_type __n, _CharT __c, const _Alloc& __a)
     593      {
     594        if (__n == 0 && __a == _Alloc())
     595  	return _S_empty_rep._M_refcopy();
     596  
     597        // Check for out_of_range and length_error exceptions.
     598        _Rep* __r = _Rep::_S_create(__n, size_type(0), __a);
     599        if (__n)
     600  	__rc_string_base::_S_assign(__r->_M_refdata(), __n, __c);
     601  
     602        __r->_M_set_length(__n);
     603        return __r->_M_refdata();
     604      }
     605  
     606    template<typename _CharT, typename _Traits, typename _Alloc>
     607      void
     608      __rc_string_base<_CharT, _Traits, _Alloc>::
     609      _M_swap(__rc_string_base& __rcs)
     610      {
     611        if (_M_is_leaked())
     612  	_M_set_sharable();
     613        if (__rcs._M_is_leaked())
     614  	__rcs._M_set_sharable();
     615  
     616        _CharT* __tmp = _M_data();
     617        _M_data(__rcs._M_data());
     618        __rcs._M_data(__tmp);
     619  
     620        // _GLIBCXX_RESOLVE_LIB_DEFECTS
     621        // 431. Swapping containers with unequal allocators.
     622        std::__alloc_swap<allocator_type>::_S_do_it(_M_get_allocator(),
     623  						  __rcs._M_get_allocator());
     624      }
     625  
     626    template<typename _CharT, typename _Traits, typename _Alloc>
     627      void
     628      __rc_string_base<_CharT, _Traits, _Alloc>::
     629      _M_assign(const __rc_string_base& __rcs)
     630      {
     631        if (_M_rep() != __rcs._M_rep())
     632  	{
     633  	  _CharT* __tmp = __rcs._M_grab(_M_get_allocator());
     634  	  _M_dispose();
     635  	  _M_data(__tmp);
     636  	}
     637      }
     638  
     639    template<typename _CharT, typename _Traits, typename _Alloc>
     640      void
     641      __rc_string_base<_CharT, _Traits, _Alloc>::
     642      _M_reserve(size_type __res)
     643      {
     644        // Make sure we don't shrink below the current size.
     645        if (__res < _M_length())
     646  	__res = _M_length();
     647  
     648        if (__res != _M_capacity() || _M_is_shared())
     649  	{
     650  	  _CharT* __tmp = _M_rep()->_M_clone(_M_get_allocator(),
     651  					     __res - _M_length());
     652  	  _M_dispose();
     653  	  _M_data(__tmp);
     654  	}
     655      }
     656  
     657    template<typename _CharT, typename _Traits, typename _Alloc>
     658      void
     659      __rc_string_base<_CharT, _Traits, _Alloc>::
     660      _M_mutate(size_type __pos, size_type __len1, const _CharT* __s,
     661  	      size_type __len2)
     662      {
     663        const size_type __how_much = _M_length() - __pos - __len1;
     664  
     665        _Rep* __r = _Rep::_S_create(_M_length() + __len2 - __len1,
     666  				  _M_capacity(), _M_get_allocator());
     667  
     668        if (__pos)
     669  	this->_S_copy(__r->_M_refdata(), _M_data(), __pos);
     670        if (__s && __len2)
     671  	this->_S_copy(__r->_M_refdata() + __pos, __s, __len2);
     672        if (__how_much)
     673  	this->_S_copy(__r->_M_refdata() + __pos + __len2,
     674  		_M_data() + __pos + __len1, __how_much);
     675  
     676        _M_dispose();
     677        _M_data(__r->_M_refdata());
     678      }
     679  
     680    template<typename _CharT, typename _Traits, typename _Alloc>
     681      void
     682      __rc_string_base<_CharT, _Traits, _Alloc>::
     683      _M_erase(size_type __pos, size_type __n)
     684      {
     685        const size_type __new_size = _M_length() - __n;
     686        const size_type __how_much = _M_length() - __pos - __n;
     687  
     688        if (_M_is_shared())
     689  	{
     690  	  // Must reallocate.
     691  	  _Rep* __r = _Rep::_S_create(__new_size, _M_capacity(),
     692  				      _M_get_allocator());
     693  
     694  	  if (__pos)
     695  	    this->_S_copy(__r->_M_refdata(), _M_data(), __pos);
     696  	  if (__how_much)
     697  	    this->_S_copy(__r->_M_refdata() + __pos,
     698  		    _M_data() + __pos + __n, __how_much);
     699  
     700  	  _M_dispose();
     701  	  _M_data(__r->_M_refdata());
     702  	}
     703        else if (__how_much && __n)
     704  	{
     705  	  // Work in-place.
     706  	  this->_S_move(_M_data() + __pos,
     707  		  _M_data() + __pos + __n, __how_much);
     708  	}
     709  
     710        _M_rep()->_M_set_length(__new_size);
     711      }
     712  
     713    template<>
     714      inline bool
     715      __rc_string_base<char, std::char_traits<char>,
     716  		     std::allocator<char> >::
     717      _M_compare(const __rc_string_base& __rcs) const
     718      {
     719        if (_M_rep() == __rcs._M_rep())
     720  	return true;
     721        return false;
     722      }
     723  
     724    template<>
     725      inline bool
     726      __rc_string_base<wchar_t, std::char_traits<wchar_t>,
     727  		     std::allocator<wchar_t> >::
     728      _M_compare(const __rc_string_base& __rcs) const
     729      {
     730        if (_M_rep() == __rcs._M_rep())
     731  	return true;
     732        return false;
     733      }
     734  
     735  _GLIBCXX_END_NAMESPACE_VERSION
     736  } // namespace
     737  
     738  #endif /* _RC_STRING_BASE_H */