libstdc++
|
00001 // Reference-counted versatile string base -*- C++ -*- 00002 00003 // Copyright (C) 2005-2019 Free Software Foundation, Inc. 00004 // 00005 // This file is part of the GNU ISO C++ Library. This library is free 00006 // software; you can redistribute it and/or modify it under the 00007 // terms of the GNU General Public License as published by the 00008 // Free Software Foundation; either version 3, or (at your option) 00009 // any later version. 00010 00011 // This library is distributed in the hope that it will be useful, 00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 // GNU General Public License for more details. 00015 00016 // Under Section 7 of GPL version 3, you are granted additional 00017 // permissions described in the GCC Runtime Library Exception, version 00018 // 3.1, as published by the Free Software Foundation. 00019 00020 // You should have received a copy of the GNU General Public License and 00021 // a copy of the GCC Runtime Library Exception along with this program; 00022 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 00023 // <http://www.gnu.org/licenses/>. 00024 00025 /** @file ext/rc_string_base.h 00026 * This is an internal header file, included by other library headers. 00027 * Do not attempt to use it directly. @headername{ext/vstring.h} 00028 */ 00029 00030 #ifndef _RC_STRING_BASE_H 00031 #define _RC_STRING_BASE_H 1 00032 00033 #include <ext/atomicity.h> 00034 #include <bits/stl_iterator_base_funcs.h> 00035 00036 namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) 00037 { 00038 _GLIBCXX_BEGIN_NAMESPACE_VERSION 00039 00040 /** 00041 * Documentation? What's that? 00042 * Nathan Myers <ncm@cantrip.org>. 00043 * 00044 * A string looks like this: 00045 * 00046 * @code 00047 * [_Rep] 00048 * _M_length 00049 * [__rc_string_base<char_type>] _M_capacity 00050 * _M_dataplus _M_refcount 00051 * _M_p ----------------> unnamed array of char_type 00052 * @endcode 00053 * 00054 * Where the _M_p points to the first character in the string, and 00055 * you cast it to a pointer-to-_Rep and subtract 1 to get a 00056 * pointer to the header. 00057 * 00058 * This approach has the enormous advantage that a string object 00059 * requires only one allocation. All the ugliness is confined 00060 * within a single pair of inline functions, which each compile to 00061 * a single @a add instruction: _Rep::_M_refdata(), and 00062 * __rc_string_base::_M_rep(); and the allocation function which gets a 00063 * block of raw bytes and with room enough and constructs a _Rep 00064 * object at the front. 00065 * 00066 * The reason you want _M_data pointing to the character array and 00067 * not the _Rep is so that the debugger can see the string 00068 * contents. (Probably we should add a non-inline member to get 00069 * the _Rep for the debugger to use, so users can check the actual 00070 * string length.) 00071 * 00072 * Note that the _Rep object is a POD so that you can have a 00073 * static <em>empty string</em> _Rep object already @a constructed before 00074 * static constructors have run. The reference-count encoding is 00075 * chosen so that a 0 indicates one reference, so you never try to 00076 * destroy the empty-string _Rep object. 00077 * 00078 * All but the last paragraph is considered pretty conventional 00079 * for a C++ string implementation. 00080 */ 00081 template<typename _CharT, typename _Traits, typename _Alloc> 00082 class __rc_string_base 00083 : protected __vstring_utility<_CharT, _Traits, _Alloc> 00084 { 00085 public: 00086 typedef _Traits traits_type; 00087 typedef typename _Traits::char_type value_type; 00088 typedef _Alloc allocator_type; 00089 00090 typedef __vstring_utility<_CharT, _Traits, _Alloc> _Util_Base; 00091 typedef typename _Util_Base::_CharT_alloc_type _CharT_alloc_type; 00092 typedef typename _CharT_alloc_type::size_type size_type; 00093 00094 private: 00095 // _Rep: string representation 00096 // Invariants: 00097 // 1. String really contains _M_length + 1 characters: due to 21.3.4 00098 // must be kept null-terminated. 00099 // 2. _M_capacity >= _M_length 00100 // Allocated memory is always (_M_capacity + 1) * sizeof(_CharT). 00101 // 3. _M_refcount has three states: 00102 // -1: leaked, one reference, no ref-copies allowed, non-const. 00103 // 0: one reference, non-const. 00104 // n>0: n + 1 references, operations require a lock, const. 00105 // 4. All fields == 0 is an empty string, given the extra storage 00106 // beyond-the-end for a null terminator; thus, the shared 00107 // empty string representation needs no constructor. 00108 struct _Rep 00109 { 00110 union 00111 { 00112 struct 00113 { 00114 size_type _M_length; 00115 size_type _M_capacity; 00116 _Atomic_word _M_refcount; 00117 } _M_info; 00118 00119 // Only for alignment purposes. 00120 _CharT _M_align; 00121 }; 00122 00123 typedef typename _Alloc::template rebind<_Rep>::other _Rep_alloc_type; 00124 00125 _CharT* 00126 _M_refdata() throw() 00127 { return reinterpret_cast<_CharT*>(this + 1); } 00128 00129 _CharT* 00130 _M_refcopy() throw() 00131 { 00132 __atomic_add_dispatch(&_M_info._M_refcount, 1); 00133 return _M_refdata(); 00134 } // XXX MT 00135 00136 void 00137 _M_set_length(size_type __n) 00138 { 00139 _M_info._M_refcount = 0; // One reference. 00140 _M_info._M_length = __n; 00141 // grrr. (per 21.3.4) 00142 // You cannot leave those LWG people alone for a second. 00143 traits_type::assign(_M_refdata()[__n], _CharT()); 00144 } 00145 00146 // Create & Destroy 00147 static _Rep* 00148 _S_create(size_type, size_type, const _Alloc&); 00149 00150 void 00151 _M_destroy(const _Alloc&) throw(); 00152 00153 _CharT* 00154 _M_clone(const _Alloc&, size_type __res = 0); 00155 }; 00156 00157 struct _Rep_empty 00158 : public _Rep 00159 { 00160 _CharT _M_terminal; 00161 }; 00162 00163 static _Rep_empty _S_empty_rep; 00164 00165 // The maximum number of individual char_type elements of an 00166 // individual string is determined by _S_max_size. This is the 00167 // value that will be returned by max_size(). (Whereas npos 00168 // is the maximum number of bytes the allocator can allocate.) 00169 // If one was to divvy up the theoretical largest size string, 00170 // with a terminating character and m _CharT elements, it'd 00171 // look like this: 00172 // npos = sizeof(_Rep) + (m * sizeof(_CharT)) + sizeof(_CharT) 00173 // + sizeof(_Rep) - 1 00174 // (NB: last two terms for rounding reasons, see _M_create below) 00175 // Solving for m: 00176 // m = ((npos - 2 * sizeof(_Rep) + 1) / sizeof(_CharT)) - 1 00177 // In addition, this implementation halves this amount. 00178 enum { _S_max_size = (((static_cast<size_type>(-1) - 2 * sizeof(_Rep) 00179 + 1) / sizeof(_CharT)) - 1) / 2 }; 00180 00181 // Data Member (private): 00182 mutable typename _Util_Base::template _Alloc_hider<_Alloc> _M_dataplus; 00183 00184 void 00185 _M_data(_CharT* __p) 00186 { _M_dataplus._M_p = __p; } 00187 00188 _Rep* 00189 _M_rep() const 00190 { return &((reinterpret_cast<_Rep*>(_M_data()))[-1]); } 00191 00192 _CharT* 00193 _M_grab(const _Alloc& __alloc) const 00194 { 00195 return (!_M_is_leaked() && _M_get_allocator() == __alloc) 00196 ? _M_rep()->_M_refcopy() : _M_rep()->_M_clone(__alloc); 00197 } 00198 00199 void 00200 _M_dispose() 00201 { 00202 // Be race-detector-friendly. For more info see bits/c++config. 00203 _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&_M_rep()->_M_info. 00204 _M_refcount); 00205 if (__exchange_and_add_dispatch(&_M_rep()->_M_info._M_refcount, 00206 -1) <= 0) 00207 { 00208 _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&_M_rep()->_M_info. 00209 _M_refcount); 00210 _M_rep()->_M_destroy(_M_get_allocator()); 00211 } 00212 } // XXX MT 00213 00214 bool 00215 _M_is_leaked() const 00216 { return _M_rep()->_M_info._M_refcount < 0; } 00217 00218 void 00219 _M_set_sharable() 00220 { _M_rep()->_M_info._M_refcount = 0; } 00221 00222 void 00223 _M_leak_hard(); 00224 00225 // _S_construct_aux is used to implement the 21.3.1 para 15 which 00226 // requires special behaviour if _InIterator is an integral type 00227 template<typename _InIterator> 00228 static _CharT* 00229 _S_construct_aux(_InIterator __beg, _InIterator __end, 00230 const _Alloc& __a, std::__false_type) 00231 { 00232 typedef typename iterator_traits<_InIterator>::iterator_category _Tag; 00233 return _S_construct(__beg, __end, __a, _Tag()); 00234 } 00235 00236 // _GLIBCXX_RESOLVE_LIB_DEFECTS 00237 // 438. Ambiguity in the "do the right thing" clause 00238 template<typename _Integer> 00239 static _CharT* 00240 _S_construct_aux(_Integer __beg, _Integer __end, 00241 const _Alloc& __a, std::__true_type) 00242 { return _S_construct_aux_2(static_cast<size_type>(__beg), 00243 __end, __a); } 00244 00245 static _CharT* 00246 _S_construct_aux_2(size_type __req, _CharT __c, const _Alloc& __a) 00247 { return _S_construct(__req, __c, __a); } 00248 00249 template<typename _InIterator> 00250 static _CharT* 00251 _S_construct(_InIterator __beg, _InIterator __end, const _Alloc& __a) 00252 { 00253 typedef typename std::__is_integer<_InIterator>::__type _Integral; 00254 return _S_construct_aux(__beg, __end, __a, _Integral()); 00255 } 00256 00257 // For Input Iterators, used in istreambuf_iterators, etc. 00258 template<typename _InIterator> 00259 static _CharT* 00260 _S_construct(_InIterator __beg, _InIterator __end, const _Alloc& __a, 00261 std::input_iterator_tag); 00262 00263 // For forward_iterators up to random_access_iterators, used for 00264 // string::iterator, _CharT*, etc. 00265 template<typename _FwdIterator> 00266 static _CharT* 00267 _S_construct(_FwdIterator __beg, _FwdIterator __end, const _Alloc& __a, 00268 std::forward_iterator_tag); 00269 00270 static _CharT* 00271 _S_construct(size_type __req, _CharT __c, const _Alloc& __a); 00272 00273 public: 00274 size_type 00275 _M_max_size() const 00276 { return size_type(_S_max_size); } 00277 00278 _CharT* 00279 _M_data() const 00280 { return _M_dataplus._M_p; } 00281 00282 size_type 00283 _M_length() const 00284 { return _M_rep()->_M_info._M_length; } 00285 00286 size_type 00287 _M_capacity() const 00288 { return _M_rep()->_M_info._M_capacity; } 00289 00290 bool 00291 _M_is_shared() const 00292 { return _M_rep()->_M_info._M_refcount > 0; } 00293 00294 void 00295 _M_set_leaked() 00296 { _M_rep()->_M_info._M_refcount = -1; } 00297 00298 void 00299 _M_leak() // for use in begin() & non-const op[] 00300 { 00301 if (!_M_is_leaked()) 00302 _M_leak_hard(); 00303 } 00304 00305 void 00306 _M_set_length(size_type __n) 00307 { _M_rep()->_M_set_length(__n); } 00308 00309 __rc_string_base() 00310 : _M_dataplus(_S_empty_rep._M_refcopy()) { } 00311 00312 __rc_string_base(const _Alloc& __a); 00313 00314 __rc_string_base(const __rc_string_base& __rcs); 00315 00316 #if __cplusplus >= 201103L 00317 __rc_string_base(__rc_string_base&& __rcs) 00318 : _M_dataplus(__rcs._M_dataplus) 00319 { __rcs._M_data(_S_empty_rep._M_refcopy()); } 00320 #endif 00321 00322 __rc_string_base(size_type __n, _CharT __c, const _Alloc& __a); 00323 00324 template<typename _InputIterator> 00325 __rc_string_base(_InputIterator __beg, _InputIterator __end, 00326 const _Alloc& __a); 00327 00328 ~__rc_string_base() 00329 { _M_dispose(); } 00330 00331 allocator_type& 00332 _M_get_allocator() 00333 { return _M_dataplus; } 00334 00335 const allocator_type& 00336 _M_get_allocator() const 00337 { return _M_dataplus; } 00338 00339 void 00340 _M_swap(__rc_string_base& __rcs); 00341 00342 void 00343 _M_assign(const __rc_string_base& __rcs); 00344 00345 void 00346 _M_reserve(size_type __res); 00347 00348 void 00349 _M_mutate(size_type __pos, size_type __len1, const _CharT* __s, 00350 size_type __len2); 00351 00352 void 00353 _M_erase(size_type __pos, size_type __n); 00354 00355 void 00356 _M_clear() 00357 { 00358 _M_dispose(); 00359 _M_data(_S_empty_rep._M_refcopy()); 00360 } 00361 00362 bool 00363 _M_compare(const __rc_string_base&) const 00364 { return false; } 00365 }; 00366 00367 template<typename _CharT, typename _Traits, typename _Alloc> 00368 typename __rc_string_base<_CharT, _Traits, _Alloc>::_Rep_empty 00369 __rc_string_base<_CharT, _Traits, _Alloc>::_S_empty_rep; 00370 00371 template<typename _CharT, typename _Traits, typename _Alloc> 00372 typename __rc_string_base<_CharT, _Traits, _Alloc>::_Rep* 00373 __rc_string_base<_CharT, _Traits, _Alloc>::_Rep:: 00374 _S_create(size_type __capacity, size_type __old_capacity, 00375 const _Alloc& __alloc) 00376 { 00377 // _GLIBCXX_RESOLVE_LIB_DEFECTS 00378 // 83. String::npos vs. string::max_size() 00379 if (__capacity > size_type(_S_max_size)) 00380 std::__throw_length_error(__N("__rc_string_base::_Rep::_S_create")); 00381 00382 // The standard places no restriction on allocating more memory 00383 // than is strictly needed within this layer at the moment or as 00384 // requested by an explicit application call to reserve(). 00385 00386 // Many malloc implementations perform quite poorly when an 00387 // application attempts to allocate memory in a stepwise fashion 00388 // growing each allocation size by only 1 char. Additionally, 00389 // it makes little sense to allocate less linear memory than the 00390 // natural blocking size of the malloc implementation. 00391 // Unfortunately, we would need a somewhat low-level calculation 00392 // with tuned parameters to get this perfect for any particular 00393 // malloc implementation. Fortunately, generalizations about 00394 // common features seen among implementations seems to suffice. 00395 00396 // __pagesize need not match the actual VM page size for good 00397 // results in practice, thus we pick a common value on the low 00398 // side. __malloc_header_size is an estimate of the amount of 00399 // overhead per memory allocation (in practice seen N * sizeof 00400 // (void*) where N is 0, 2 or 4). According to folklore, 00401 // picking this value on the high side is better than 00402 // low-balling it (especially when this algorithm is used with 00403 // malloc implementations that allocate memory blocks rounded up 00404 // to a size which is a power of 2). 00405 const size_type __pagesize = 4096; 00406 const size_type __malloc_header_size = 4 * sizeof(void*); 00407 00408 // The below implements an exponential growth policy, necessary to 00409 // meet amortized linear time requirements of the library: see 00410 // http://gcc.gnu.org/ml/libstdc++/2001-07/msg00085.html. 00411 if (__capacity > __old_capacity && __capacity < 2 * __old_capacity) 00412 { 00413 __capacity = 2 * __old_capacity; 00414 // Never allocate a string bigger than _S_max_size. 00415 if (__capacity > size_type(_S_max_size)) 00416 __capacity = size_type(_S_max_size); 00417 } 00418 00419 // NB: Need an array of char_type[__capacity], plus a terminating 00420 // null char_type() element, plus enough for the _Rep data structure, 00421 // plus sizeof(_Rep) - 1 to upper round to a size multiple of 00422 // sizeof(_Rep). 00423 // Whew. Seemingly so needy, yet so elemental. 00424 size_type __size = ((__capacity + 1) * sizeof(_CharT) 00425 + 2 * sizeof(_Rep) - 1); 00426 00427 const size_type __adj_size = __size + __malloc_header_size; 00428 if (__adj_size > __pagesize && __capacity > __old_capacity) 00429 { 00430 const size_type __extra = __pagesize - __adj_size % __pagesize; 00431 __capacity += __extra / sizeof(_CharT); 00432 if (__capacity > size_type(_S_max_size)) 00433 __capacity = size_type(_S_max_size); 00434 __size = (__capacity + 1) * sizeof(_CharT) + 2 * sizeof(_Rep) - 1; 00435 } 00436 00437 // NB: Might throw, but no worries about a leak, mate: _Rep() 00438 // does not throw. 00439 _Rep* __place = _Rep_alloc_type(__alloc).allocate(__size / sizeof(_Rep)); 00440 _Rep* __p = new (__place) _Rep; 00441 __p->_M_info._M_capacity = __capacity; 00442 return __p; 00443 } 00444 00445 template<typename _CharT, typename _Traits, typename _Alloc> 00446 void 00447 __rc_string_base<_CharT, _Traits, _Alloc>::_Rep:: 00448 _M_destroy(const _Alloc& __a) throw () 00449 { 00450 const size_type __size = ((_M_info._M_capacity + 1) * sizeof(_CharT) 00451 + 2 * sizeof(_Rep) - 1); 00452 _Rep_alloc_type(__a).deallocate(this, __size / sizeof(_Rep)); 00453 } 00454 00455 template<typename _CharT, typename _Traits, typename _Alloc> 00456 _CharT* 00457 __rc_string_base<_CharT, _Traits, _Alloc>::_Rep:: 00458 _M_clone(const _Alloc& __alloc, size_type __res) 00459 { 00460 // Requested capacity of the clone. 00461 const size_type __requested_cap = _M_info._M_length + __res; 00462 _Rep* __r = _Rep::_S_create(__requested_cap, _M_info._M_capacity, 00463 __alloc); 00464 00465 if (_M_info._M_length) 00466 __rc_string_base::_S_copy(__r->_M_refdata(), _M_refdata(), _M_info._M_length); 00467 00468 __r->_M_set_length(_M_info._M_length); 00469 return __r->_M_refdata(); 00470 } 00471 00472 template<typename _CharT, typename _Traits, typename _Alloc> 00473 __rc_string_base<_CharT, _Traits, _Alloc>:: 00474 __rc_string_base(const _Alloc& __a) 00475 : _M_dataplus(__a, _S_construct(size_type(), _CharT(), __a)) { } 00476 00477 template<typename _CharT, typename _Traits, typename _Alloc> 00478 __rc_string_base<_CharT, _Traits, _Alloc>:: 00479 __rc_string_base(const __rc_string_base& __rcs) 00480 : _M_dataplus(__rcs._M_get_allocator(), 00481 __rcs._M_grab(__rcs._M_get_allocator())) { } 00482 00483 template<typename _CharT, typename _Traits, typename _Alloc> 00484 __rc_string_base<_CharT, _Traits, _Alloc>:: 00485 __rc_string_base(size_type __n, _CharT __c, const _Alloc& __a) 00486 : _M_dataplus(__a, _S_construct(__n, __c, __a)) { } 00487 00488 template<typename _CharT, typename _Traits, typename _Alloc> 00489 template<typename _InputIterator> 00490 __rc_string_base<_CharT, _Traits, _Alloc>:: 00491 __rc_string_base(_InputIterator __beg, _InputIterator __end, 00492 const _Alloc& __a) 00493 : _M_dataplus(__a, _S_construct(__beg, __end, __a)) { } 00494 00495 template<typename _CharT, typename _Traits, typename _Alloc> 00496 void 00497 __rc_string_base<_CharT, _Traits, _Alloc>:: 00498 _M_leak_hard() 00499 { 00500 if (_M_is_shared()) 00501 _M_erase(0, 0); 00502 _M_set_leaked(); 00503 } 00504 00505 // NB: This is the special case for Input Iterators, used in 00506 // istreambuf_iterators, etc. 00507 // Input Iterators have a cost structure very different from 00508 // pointers, calling for a different coding style. 00509 template<typename _CharT, typename _Traits, typename _Alloc> 00510 template<typename _InIterator> 00511 _CharT* 00512 __rc_string_base<_CharT, _Traits, _Alloc>:: 00513 _S_construct(_InIterator __beg, _InIterator __end, const _Alloc& __a, 00514 std::input_iterator_tag) 00515 { 00516 if (__beg == __end && __a == _Alloc()) 00517 return _S_empty_rep._M_refcopy(); 00518 00519 // Avoid reallocation for common case. 00520 _CharT __buf[128]; 00521 size_type __len = 0; 00522 while (__beg != __end && __len < sizeof(__buf) / sizeof(_CharT)) 00523 { 00524 __buf[__len++] = *__beg; 00525 ++__beg; 00526 } 00527 _Rep* __r = _Rep::_S_create(__len, size_type(0), __a); 00528 _S_copy(__r->_M_refdata(), __buf, __len); 00529 __try 00530 { 00531 while (__beg != __end) 00532 { 00533 if (__len == __r->_M_info._M_capacity) 00534 { 00535 // Allocate more space. 00536 _Rep* __another = _Rep::_S_create(__len + 1, __len, __a); 00537 _S_copy(__another->_M_refdata(), __r->_M_refdata(), __len); 00538 __r->_M_destroy(__a); 00539 __r = __another; 00540 } 00541 __r->_M_refdata()[__len++] = *__beg; 00542 ++__beg; 00543 } 00544 } 00545 __catch(...) 00546 { 00547 __r->_M_destroy(__a); 00548 __throw_exception_again; 00549 } 00550 __r->_M_set_length(__len); 00551 return __r->_M_refdata(); 00552 } 00553 00554 template<typename _CharT, typename _Traits, typename _Alloc> 00555 template<typename _InIterator> 00556 _CharT* 00557 __rc_string_base<_CharT, _Traits, _Alloc>:: 00558 _S_construct(_InIterator __beg, _InIterator __end, const _Alloc& __a, 00559 std::forward_iterator_tag) 00560 { 00561 if (__beg == __end && __a == _Alloc()) 00562 return _S_empty_rep._M_refcopy(); 00563 00564 // NB: Not required, but considered best practice. 00565 if (__is_null_pointer(__beg) && __beg != __end) 00566 std::__throw_logic_error(__N("__rc_string_base::" 00567 "_S_construct null not valid")); 00568 00569 const size_type __dnew = static_cast<size_type>(std::distance(__beg, 00570 __end)); 00571 // Check for out_of_range and length_error exceptions. 00572 _Rep* __r = _Rep::_S_create(__dnew, size_type(0), __a); 00573 __try 00574 { __rc_string_base::_S_copy_chars(__r->_M_refdata(), __beg, __end); } 00575 __catch(...) 00576 { 00577 __r->_M_destroy(__a); 00578 __throw_exception_again; 00579 } 00580 __r->_M_set_length(__dnew); 00581 return __r->_M_refdata(); 00582 } 00583 00584 template<typename _CharT, typename _Traits, typename _Alloc> 00585 _CharT* 00586 __rc_string_base<_CharT, _Traits, _Alloc>:: 00587 _S_construct(size_type __n, _CharT __c, const _Alloc& __a) 00588 { 00589 if (__n == 0 && __a == _Alloc()) 00590 return _S_empty_rep._M_refcopy(); 00591 00592 // Check for out_of_range and length_error exceptions. 00593 _Rep* __r = _Rep::_S_create(__n, size_type(0), __a); 00594 if (__n) 00595 __rc_string_base::_S_assign(__r->_M_refdata(), __n, __c); 00596 00597 __r->_M_set_length(__n); 00598 return __r->_M_refdata(); 00599 } 00600 00601 template<typename _CharT, typename _Traits, typename _Alloc> 00602 void 00603 __rc_string_base<_CharT, _Traits, _Alloc>:: 00604 _M_swap(__rc_string_base& __rcs) 00605 { 00606 if (_M_is_leaked()) 00607 _M_set_sharable(); 00608 if (__rcs._M_is_leaked()) 00609 __rcs._M_set_sharable(); 00610 00611 _CharT* __tmp = _M_data(); 00612 _M_data(__rcs._M_data()); 00613 __rcs._M_data(__tmp); 00614 00615 // _GLIBCXX_RESOLVE_LIB_DEFECTS 00616 // 431. Swapping containers with unequal allocators. 00617 std::__alloc_swap<allocator_type>::_S_do_it(_M_get_allocator(), 00618 __rcs._M_get_allocator()); 00619 } 00620 00621 template<typename _CharT, typename _Traits, typename _Alloc> 00622 void 00623 __rc_string_base<_CharT, _Traits, _Alloc>:: 00624 _M_assign(const __rc_string_base& __rcs) 00625 { 00626 if (_M_rep() != __rcs._M_rep()) 00627 { 00628 _CharT* __tmp = __rcs._M_grab(_M_get_allocator()); 00629 _M_dispose(); 00630 _M_data(__tmp); 00631 } 00632 } 00633 00634 template<typename _CharT, typename _Traits, typename _Alloc> 00635 void 00636 __rc_string_base<_CharT, _Traits, _Alloc>:: 00637 _M_reserve(size_type __res) 00638 { 00639 // Make sure we don't shrink below the current size. 00640 if (__res < _M_length()) 00641 __res = _M_length(); 00642 00643 if (__res != _M_capacity() || _M_is_shared()) 00644 { 00645 _CharT* __tmp = _M_rep()->_M_clone(_M_get_allocator(), 00646 __res - _M_length()); 00647 _M_dispose(); 00648 _M_data(__tmp); 00649 } 00650 } 00651 00652 template<typename _CharT, typename _Traits, typename _Alloc> 00653 void 00654 __rc_string_base<_CharT, _Traits, _Alloc>:: 00655 _M_mutate(size_type __pos, size_type __len1, const _CharT* __s, 00656 size_type __len2) 00657 { 00658 const size_type __how_much = _M_length() - __pos - __len1; 00659 00660 _Rep* __r = _Rep::_S_create(_M_length() + __len2 - __len1, 00661 _M_capacity(), _M_get_allocator()); 00662 00663 if (__pos) 00664 this->_S_copy(__r->_M_refdata(), _M_data(), __pos); 00665 if (__s && __len2) 00666 this->_S_copy(__r->_M_refdata() + __pos, __s, __len2); 00667 if (__how_much) 00668 this->_S_copy(__r->_M_refdata() + __pos + __len2, 00669 _M_data() + __pos + __len1, __how_much); 00670 00671 _M_dispose(); 00672 _M_data(__r->_M_refdata()); 00673 } 00674 00675 template<typename _CharT, typename _Traits, typename _Alloc> 00676 void 00677 __rc_string_base<_CharT, _Traits, _Alloc>:: 00678 _M_erase(size_type __pos, size_type __n) 00679 { 00680 const size_type __new_size = _M_length() - __n; 00681 const size_type __how_much = _M_length() - __pos - __n; 00682 00683 if (_M_is_shared()) 00684 { 00685 // Must reallocate. 00686 _Rep* __r = _Rep::_S_create(__new_size, _M_capacity(), 00687 _M_get_allocator()); 00688 00689 if (__pos) 00690 this->_S_copy(__r->_M_refdata(), _M_data(), __pos); 00691 if (__how_much) 00692 this->_S_copy(__r->_M_refdata() + __pos, 00693 _M_data() + __pos + __n, __how_much); 00694 00695 _M_dispose(); 00696 _M_data(__r->_M_refdata()); 00697 } 00698 else if (__how_much && __n) 00699 { 00700 // Work in-place. 00701 this->_S_move(_M_data() + __pos, 00702 _M_data() + __pos + __n, __how_much); 00703 } 00704 00705 _M_rep()->_M_set_length(__new_size); 00706 } 00707 00708 template<> 00709 inline bool 00710 __rc_string_base<char, std::char_traits<char>, 00711 std::allocator<char> >:: 00712 _M_compare(const __rc_string_base& __rcs) const 00713 { 00714 if (_M_rep() == __rcs._M_rep()) 00715 return true; 00716 return false; 00717 } 00718 00719 #ifdef _GLIBCXX_USE_WCHAR_T 00720 template<> 00721 inline bool 00722 __rc_string_base<wchar_t, std::char_traits<wchar_t>, 00723 std::allocator<wchar_t> >:: 00724 _M_compare(const __rc_string_base& __rcs) const 00725 { 00726 if (_M_rep() == __rcs._M_rep()) 00727 return true; 00728 return false; 00729 } 00730 #endif 00731 00732 _GLIBCXX_END_NAMESPACE_VERSION 00733 } // namespace 00734 00735 #endif /* _RC_STRING_BASE_H */