libstdc++
|
00001 // Reference-counted versatile string base -*- C++ -*- 00002 00003 // Copyright (C) 2005-2013 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 { _M_erase(size_type(0), _M_length()); } 00358 00359 bool 00360 _M_compare(const __rc_string_base&) const 00361 { return false; } 00362 }; 00363 00364 template<typename _CharT, typename _Traits, typename _Alloc> 00365 typename __rc_string_base<_CharT, _Traits, _Alloc>::_Rep_empty 00366 __rc_string_base<_CharT, _Traits, _Alloc>::_S_empty_rep; 00367 00368 template<typename _CharT, typename _Traits, typename _Alloc> 00369 typename __rc_string_base<_CharT, _Traits, _Alloc>::_Rep* 00370 __rc_string_base<_CharT, _Traits, _Alloc>::_Rep:: 00371 _S_create(size_type __capacity, size_type __old_capacity, 00372 const _Alloc& __alloc) 00373 { 00374 // _GLIBCXX_RESOLVE_LIB_DEFECTS 00375 // 83. String::npos vs. string::max_size() 00376 if (__capacity > size_type(_S_max_size)) 00377 std::__throw_length_error(__N("__rc_string_base::_Rep::_S_create")); 00378 00379 // The standard places no restriction on allocating more memory 00380 // than is strictly needed within this layer at the moment or as 00381 // requested by an explicit application call to reserve(). 00382 00383 // Many malloc implementations perform quite poorly when an 00384 // application attempts to allocate memory in a stepwise fashion 00385 // growing each allocation size by only 1 char. Additionally, 00386 // it makes little sense to allocate less linear memory than the 00387 // natural blocking size of the malloc implementation. 00388 // Unfortunately, we would need a somewhat low-level calculation 00389 // with tuned parameters to get this perfect for any particular 00390 // malloc implementation. Fortunately, generalizations about 00391 // common features seen among implementations seems to suffice. 00392 00393 // __pagesize need not match the actual VM page size for good 00394 // results in practice, thus we pick a common value on the low 00395 // side. __malloc_header_size is an estimate of the amount of 00396 // overhead per memory allocation (in practice seen N * sizeof 00397 // (void*) where N is 0, 2 or 4). According to folklore, 00398 // picking this value on the high side is better than 00399 // low-balling it (especially when this algorithm is used with 00400 // malloc implementations that allocate memory blocks rounded up 00401 // to a size which is a power of 2). 00402 const size_type __pagesize = 4096; 00403 const size_type __malloc_header_size = 4 * sizeof(void*); 00404 00405 // The below implements an exponential growth policy, necessary to 00406 // meet amortized linear time requirements of the library: see 00407 // http://gcc.gnu.org/ml/libstdc++/2001-07/msg00085.html. 00408 if (__capacity > __old_capacity && __capacity < 2 * __old_capacity) 00409 { 00410 __capacity = 2 * __old_capacity; 00411 // Never allocate a string bigger than _S_max_size. 00412 if (__capacity > size_type(_S_max_size)) 00413 __capacity = size_type(_S_max_size); 00414 } 00415 00416 // NB: Need an array of char_type[__capacity], plus a terminating 00417 // null char_type() element, plus enough for the _Rep data structure, 00418 // plus sizeof(_Rep) - 1 to upper round to a size multiple of 00419 // sizeof(_Rep). 00420 // Whew. Seemingly so needy, yet so elemental. 00421 size_type __size = ((__capacity + 1) * sizeof(_CharT) 00422 + 2 * sizeof(_Rep) - 1); 00423 00424 const size_type __adj_size = __size + __malloc_header_size; 00425 if (__adj_size > __pagesize && __capacity > __old_capacity) 00426 { 00427 const size_type __extra = __pagesize - __adj_size % __pagesize; 00428 __capacity += __extra / sizeof(_CharT); 00429 if (__capacity > size_type(_S_max_size)) 00430 __capacity = size_type(_S_max_size); 00431 __size = (__capacity + 1) * sizeof(_CharT) + 2 * sizeof(_Rep) - 1; 00432 } 00433 00434 // NB: Might throw, but no worries about a leak, mate: _Rep() 00435 // does not throw. 00436 _Rep* __place = _Rep_alloc_type(__alloc).allocate(__size / sizeof(_Rep)); 00437 _Rep* __p = new (__place) _Rep; 00438 __p->_M_info._M_capacity = __capacity; 00439 return __p; 00440 } 00441 00442 template<typename _CharT, typename _Traits, typename _Alloc> 00443 void 00444 __rc_string_base<_CharT, _Traits, _Alloc>::_Rep:: 00445 _M_destroy(const _Alloc& __a) throw () 00446 { 00447 const size_type __size = ((_M_info._M_capacity + 1) * sizeof(_CharT) 00448 + 2 * sizeof(_Rep) - 1); 00449 _Rep_alloc_type(__a).deallocate(this, __size / sizeof(_Rep)); 00450 } 00451 00452 template<typename _CharT, typename _Traits, typename _Alloc> 00453 _CharT* 00454 __rc_string_base<_CharT, _Traits, _Alloc>::_Rep:: 00455 _M_clone(const _Alloc& __alloc, size_type __res) 00456 { 00457 // Requested capacity of the clone. 00458 const size_type __requested_cap = _M_info._M_length + __res; 00459 _Rep* __r = _Rep::_S_create(__requested_cap, _M_info._M_capacity, 00460 __alloc); 00461 00462 if (_M_info._M_length) 00463 __rc_string_base::_S_copy(__r->_M_refdata(), _M_refdata(), _M_info._M_length); 00464 00465 __r->_M_set_length(_M_info._M_length); 00466 return __r->_M_refdata(); 00467 } 00468 00469 template<typename _CharT, typename _Traits, typename _Alloc> 00470 __rc_string_base<_CharT, _Traits, _Alloc>:: 00471 __rc_string_base(const _Alloc& __a) 00472 : _M_dataplus(__a, _S_construct(size_type(), _CharT(), __a)) { } 00473 00474 template<typename _CharT, typename _Traits, typename _Alloc> 00475 __rc_string_base<_CharT, _Traits, _Alloc>:: 00476 __rc_string_base(const __rc_string_base& __rcs) 00477 : _M_dataplus(__rcs._M_get_allocator(), 00478 __rcs._M_grab(__rcs._M_get_allocator())) { } 00479 00480 template<typename _CharT, typename _Traits, typename _Alloc> 00481 __rc_string_base<_CharT, _Traits, _Alloc>:: 00482 __rc_string_base(size_type __n, _CharT __c, const _Alloc& __a) 00483 : _M_dataplus(__a, _S_construct(__n, __c, __a)) { } 00484 00485 template<typename _CharT, typename _Traits, typename _Alloc> 00486 template<typename _InputIterator> 00487 __rc_string_base<_CharT, _Traits, _Alloc>:: 00488 __rc_string_base(_InputIterator __beg, _InputIterator __end, 00489 const _Alloc& __a) 00490 : _M_dataplus(__a, _S_construct(__beg, __end, __a)) { } 00491 00492 template<typename _CharT, typename _Traits, typename _Alloc> 00493 void 00494 __rc_string_base<_CharT, _Traits, _Alloc>:: 00495 _M_leak_hard() 00496 { 00497 if (_M_is_shared()) 00498 _M_erase(0, 0); 00499 _M_set_leaked(); 00500 } 00501 00502 // NB: This is the special case for Input Iterators, used in 00503 // istreambuf_iterators, etc. 00504 // Input Iterators have a cost structure very different from 00505 // pointers, calling for a different coding style. 00506 template<typename _CharT, typename _Traits, typename _Alloc> 00507 template<typename _InIterator> 00508 _CharT* 00509 __rc_string_base<_CharT, _Traits, _Alloc>:: 00510 _S_construct(_InIterator __beg, _InIterator __end, const _Alloc& __a, 00511 std::input_iterator_tag) 00512 { 00513 if (__beg == __end && __a == _Alloc()) 00514 return _S_empty_rep._M_refcopy(); 00515 00516 // Avoid reallocation for common case. 00517 _CharT __buf[128]; 00518 size_type __len = 0; 00519 while (__beg != __end && __len < sizeof(__buf) / sizeof(_CharT)) 00520 { 00521 __buf[__len++] = *__beg; 00522 ++__beg; 00523 } 00524 _Rep* __r = _Rep::_S_create(__len, size_type(0), __a); 00525 _S_copy(__r->_M_refdata(), __buf, __len); 00526 __try 00527 { 00528 while (__beg != __end) 00529 { 00530 if (__len == __r->_M_info._M_capacity) 00531 { 00532 // Allocate more space. 00533 _Rep* __another = _Rep::_S_create(__len + 1, __len, __a); 00534 _S_copy(__another->_M_refdata(), __r->_M_refdata(), __len); 00535 __r->_M_destroy(__a); 00536 __r = __another; 00537 } 00538 __r->_M_refdata()[__len++] = *__beg; 00539 ++__beg; 00540 } 00541 } 00542 __catch(...) 00543 { 00544 __r->_M_destroy(__a); 00545 __throw_exception_again; 00546 } 00547 __r->_M_set_length(__len); 00548 return __r->_M_refdata(); 00549 } 00550 00551 template<typename _CharT, typename _Traits, typename _Alloc> 00552 template<typename _InIterator> 00553 _CharT* 00554 __rc_string_base<_CharT, _Traits, _Alloc>:: 00555 _S_construct(_InIterator __beg, _InIterator __end, const _Alloc& __a, 00556 std::forward_iterator_tag) 00557 { 00558 if (__beg == __end && __a == _Alloc()) 00559 return _S_empty_rep._M_refcopy(); 00560 00561 // NB: Not required, but considered best practice. 00562 if (__is_null_pointer(__beg) && __beg != __end) 00563 std::__throw_logic_error(__N("__rc_string_base::" 00564 "_S_construct null not valid")); 00565 00566 const size_type __dnew = static_cast<size_type>(std::distance(__beg, 00567 __end)); 00568 // Check for out_of_range and length_error exceptions. 00569 _Rep* __r = _Rep::_S_create(__dnew, size_type(0), __a); 00570 __try 00571 { __rc_string_base::_S_copy_chars(__r->_M_refdata(), __beg, __end); } 00572 __catch(...) 00573 { 00574 __r->_M_destroy(__a); 00575 __throw_exception_again; 00576 } 00577 __r->_M_set_length(__dnew); 00578 return __r->_M_refdata(); 00579 } 00580 00581 template<typename _CharT, typename _Traits, typename _Alloc> 00582 _CharT* 00583 __rc_string_base<_CharT, _Traits, _Alloc>:: 00584 _S_construct(size_type __n, _CharT __c, const _Alloc& __a) 00585 { 00586 if (__n == 0 && __a == _Alloc()) 00587 return _S_empty_rep._M_refcopy(); 00588 00589 // Check for out_of_range and length_error exceptions. 00590 _Rep* __r = _Rep::_S_create(__n, size_type(0), __a); 00591 if (__n) 00592 __rc_string_base::_S_assign(__r->_M_refdata(), __n, __c); 00593 00594 __r->_M_set_length(__n); 00595 return __r->_M_refdata(); 00596 } 00597 00598 template<typename _CharT, typename _Traits, typename _Alloc> 00599 void 00600 __rc_string_base<_CharT, _Traits, _Alloc>:: 00601 _M_swap(__rc_string_base& __rcs) 00602 { 00603 if (_M_is_leaked()) 00604 _M_set_sharable(); 00605 if (__rcs._M_is_leaked()) 00606 __rcs._M_set_sharable(); 00607 00608 _CharT* __tmp = _M_data(); 00609 _M_data(__rcs._M_data()); 00610 __rcs._M_data(__tmp); 00611 00612 // _GLIBCXX_RESOLVE_LIB_DEFECTS 00613 // 431. Swapping containers with unequal allocators. 00614 std::__alloc_swap<allocator_type>::_S_do_it(_M_get_allocator(), 00615 __rcs._M_get_allocator()); 00616 } 00617 00618 template<typename _CharT, typename _Traits, typename _Alloc> 00619 void 00620 __rc_string_base<_CharT, _Traits, _Alloc>:: 00621 _M_assign(const __rc_string_base& __rcs) 00622 { 00623 if (_M_rep() != __rcs._M_rep()) 00624 { 00625 _CharT* __tmp = __rcs._M_grab(_M_get_allocator()); 00626 _M_dispose(); 00627 _M_data(__tmp); 00628 } 00629 } 00630 00631 template<typename _CharT, typename _Traits, typename _Alloc> 00632 void 00633 __rc_string_base<_CharT, _Traits, _Alloc>:: 00634 _M_reserve(size_type __res) 00635 { 00636 // Make sure we don't shrink below the current size. 00637 if (__res < _M_length()) 00638 __res = _M_length(); 00639 00640 if (__res != _M_capacity() || _M_is_shared()) 00641 { 00642 _CharT* __tmp = _M_rep()->_M_clone(_M_get_allocator(), 00643 __res - _M_length()); 00644 _M_dispose(); 00645 _M_data(__tmp); 00646 } 00647 } 00648 00649 template<typename _CharT, typename _Traits, typename _Alloc> 00650 void 00651 __rc_string_base<_CharT, _Traits, _Alloc>:: 00652 _M_mutate(size_type __pos, size_type __len1, const _CharT* __s, 00653 size_type __len2) 00654 { 00655 const size_type __how_much = _M_length() - __pos - __len1; 00656 00657 _Rep* __r = _Rep::_S_create(_M_length() + __len2 - __len1, 00658 _M_capacity(), _M_get_allocator()); 00659 00660 if (__pos) 00661 this->_S_copy(__r->_M_refdata(), _M_data(), __pos); 00662 if (__s && __len2) 00663 this->_S_copy(__r->_M_refdata() + __pos, __s, __len2); 00664 if (__how_much) 00665 this->_S_copy(__r->_M_refdata() + __pos + __len2, 00666 _M_data() + __pos + __len1, __how_much); 00667 00668 _M_dispose(); 00669 _M_data(__r->_M_refdata()); 00670 } 00671 00672 template<typename _CharT, typename _Traits, typename _Alloc> 00673 void 00674 __rc_string_base<_CharT, _Traits, _Alloc>:: 00675 _M_erase(size_type __pos, size_type __n) 00676 { 00677 const size_type __new_size = _M_length() - __n; 00678 const size_type __how_much = _M_length() - __pos - __n; 00679 00680 if (_M_is_shared()) 00681 { 00682 // Must reallocate. 00683 _Rep* __r = _Rep::_S_create(__new_size, _M_capacity(), 00684 _M_get_allocator()); 00685 00686 if (__pos) 00687 this->_S_copy(__r->_M_refdata(), _M_data(), __pos); 00688 if (__how_much) 00689 this->_S_copy(__r->_M_refdata() + __pos, 00690 _M_data() + __pos + __n, __how_much); 00691 00692 _M_dispose(); 00693 _M_data(__r->_M_refdata()); 00694 } 00695 else if (__how_much && __n) 00696 { 00697 // Work in-place. 00698 this->_S_move(_M_data() + __pos, 00699 _M_data() + __pos + __n, __how_much); 00700 } 00701 00702 _M_rep()->_M_set_length(__new_size); 00703 } 00704 00705 template<> 00706 inline bool 00707 __rc_string_base<char, std::char_traits<char>, 00708 std::allocator<char> >:: 00709 _M_compare(const __rc_string_base& __rcs) const 00710 { 00711 if (_M_rep() == __rcs._M_rep()) 00712 return true; 00713 return false; 00714 } 00715 00716 #ifdef _GLIBCXX_USE_WCHAR_T 00717 template<> 00718 inline bool 00719 __rc_string_base<wchar_t, std::char_traits<wchar_t>, 00720 std::allocator<wchar_t> >:: 00721 _M_compare(const __rc_string_base& __rcs) const 00722 { 00723 if (_M_rep() == __rcs._M_rep()) 00724 return true; 00725 return false; 00726 } 00727 #endif 00728 00729 _GLIBCXX_END_NAMESPACE_VERSION 00730 } // namespace 00731 00732 #endif /* _RC_STRING_BASE_H */