basic_string.tcc revision 102782
1250323Sdteske// Components for manipulating sequences of characters -*- C++ -*- 2250323Sdteske 3250323Sdteske// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 4250323Sdteske// Free Software Foundation, Inc. 5250323Sdteske// 6250323Sdteske// This file is part of the GNU ISO C++ Library. This library is free 7250323Sdteske// software; you can redistribute it and/or modify it under the 8250323Sdteske// terms of the GNU General Public License as published by the 9250323Sdteske// Free Software Foundation; either version 2, or (at your option) 10250323Sdteske// any later version. 11250323Sdteske 12250323Sdteske// This library is distributed in the hope that it will be useful, 13250323Sdteske// but WITHOUT ANY WARRANTY; without even the implied warranty of 14250323Sdteske// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15250323Sdteske// GNU General Public License for more details. 16250323Sdteske 17250323Sdteske// You should have received a copy of the GNU General Public License along 18250323Sdteske// with this library; see the file COPYING. If not, write to the Free 19250323Sdteske// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, 20250323Sdteske// USA. 21250323Sdteske 22250323Sdteske// As a special exception, you may use this file as part of a free software 23250323Sdteske// library without restriction. Specifically, if other files instantiate 24250323Sdteske// templates or use macros or inline functions from this file, or you compile 25250323Sdteske// this file and link it with other files to produce an executable, this 26250323Sdteske// file does not by itself cause the resulting executable to be covered by 27250323Sdteske// the GNU General Public License. This exception does not however 28250323Sdteske// invalidate any other reasons why the executable file might be covered by 29250323Sdteske// the GNU General Public License. 30250323Sdteske 31250323Sdteske// 32250323Sdteske// ISO C++ 14882: 21 Strings library 33250323Sdteske// 34250323Sdteske 35250323Sdteske// This file is included by <string>. It is not meant to be included 36250323Sdteske// separately. 37250323Sdteske 38250323Sdteske// Written by Jason Merrill based upon the specification by Takanori Adachi 39250323Sdteske// in ANSI X3J16/94-0013R2. Rewritten by Nathan Myers to ISO-14882. 40250323Sdteske 41250323Sdteske#ifndef _CPP_BITS_STRING_TCC 42250323Sdteske#define _CPP_BITS_STRING_TCC 1 43250323Sdteske 44250323Sdteske#pragma GCC system_header 45250323Sdteske 46250323Sdteskenamespace std 47250323Sdteske{ 48250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 49250323Sdteske const typename basic_string<_CharT, _Traits, _Alloc>::size_type 50250323Sdteske basic_string<_CharT, _Traits, _Alloc>:: 51250323Sdteske _Rep::_S_max_size = (((npos - sizeof(_Rep))/sizeof(_CharT)) - 1) / 4; 52250323Sdteske 53250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 54250323Sdteske const _CharT 55250323Sdteske basic_string<_CharT, _Traits, _Alloc>:: 56250323Sdteske _Rep::_S_terminal = _CharT(); 57250323Sdteske 58250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 59250323Sdteske const typename basic_string<_CharT, _Traits, _Alloc>::size_type 60250323Sdteske basic_string<_CharT, _Traits, _Alloc>::npos; 61250323Sdteske 62250323Sdteske // Linker sets _S_empty_rep_storage to all 0s (one reference, empty string) 63250323Sdteske // at static init time (before static ctors are run). 64250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 65250323Sdteske typename basic_string<_CharT, _Traits, _Alloc>::size_type 66250323Sdteske basic_string<_CharT, _Traits, _Alloc>::_S_empty_rep_storage[ 67250323Sdteske (sizeof(_Rep) + sizeof(_CharT) + sizeof(size_type) - 1)/sizeof(size_type)]; 68250323Sdteske 69250323Sdteske // NB: This is the special case for Input Iterators, used in 70250323Sdteske // istreambuf_iterators, etc. 71250323Sdteske // Input Iterators have a cost structure very different from 72250323Sdteske // pointers, calling for a different coding style. 73250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 74250323Sdteske template<typename _InIter> 75250323Sdteske _CharT* 76250323Sdteske basic_string<_CharT, _Traits, _Alloc>:: 77250323Sdteske _S_construct(_InIter __beg, _InIter __end, const _Alloc& __a, 78250323Sdteske input_iterator_tag) 79250323Sdteske { 80250323Sdteske if (__beg == __end && __a == _Alloc()) 81250323Sdteske return _S_empty_rep()._M_refcopy(); 82250538Sdteske // Avoid reallocation for common case. 83250538Sdteske _CharT __buf[100]; 84250323Sdteske size_type __i = 0; 85250323Sdteske while (__beg != __end && __i < sizeof(__buf) / sizeof(_CharT)) 86250323Sdteske { 87250538Sdteske __buf[__i++] = *__beg; 88250538Sdteske ++__beg; 89250538Sdteske } 90250538Sdteske _Rep* __r = _Rep::_S_create(__i, __a); 91250538Sdteske traits_type::copy(__r->_M_refdata(), __buf, __i); 92250323Sdteske __r->_M_length = __i; 93250323Sdteske try 94250323Sdteske { 95250538Sdteske // NB: this loop looks precisely this way because 96250538Sdteske // it avoids comparing __beg != __end any more 97250538Sdteske // than strictly necessary; != might be expensive! 98250538Sdteske for (;;) 99250538Sdteske { 100250323Sdteske _CharT* __p = __r->_M_refdata() + __r->_M_length; 101250538Sdteske _CharT* __last = __r->_M_refdata() + __r->_M_capacity; 102250538Sdteske for (;;) 103250538Sdteske { 104250323Sdteske if (__beg == __end) 105250323Sdteske { 106250323Sdteske __r->_M_length = __p - __r->_M_refdata(); 107250323Sdteske *__p = _Rep::_S_terminal; // grrr. 108250323Sdteske return __r->_M_refdata(); 109250323Sdteske } 110250323Sdteske if (__p == __last) 111250323Sdteske break; 112250323Sdteske *__p++ = *__beg; 113250323Sdteske ++__beg; 114250323Sdteske } 115250323Sdteske // Allocate more space. 116250323Sdteske size_type __len = __p - __r->_M_refdata(); 117250323Sdteske _Rep* __another = _Rep::_S_create(__len + 1, __a); 118250323Sdteske traits_type::copy(__another->_M_refdata(), 119250323Sdteske __r->_M_refdata(), __len); 120250323Sdteske __r->_M_destroy(__a); 121250323Sdteske __r = __another; 122250323Sdteske __r->_M_length = __len; 123250323Sdteske } 124250323Sdteske } 125250323Sdteske catch(...) 126250323Sdteske { 127250323Sdteske __r->_M_destroy(__a); 128250323Sdteske __throw_exception_again; 129250323Sdteske } 130250323Sdteske return 0; 131250323Sdteske } 132250323Sdteske 133250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 134250323Sdteske template <class _InIter> 135250323Sdteske _CharT* 136250323Sdteske basic_string<_CharT, _Traits, _Alloc>:: 137250323Sdteske _S_construct(_InIter __beg, _InIter __end, const _Alloc& __a, 138250323Sdteske forward_iterator_tag) 139250323Sdteske { 140250323Sdteske size_type __dnew = static_cast<size_type>(distance(__beg, __end)); 141250323Sdteske 142250323Sdteske // NB: Not required, but considered best practice. 143250323Sdteske if (__builtin_expect(__beg == _InIter(), 0)) 144250323Sdteske __throw_logic_error("attempt to create string with null pointer"); 145250323Sdteske 146250323Sdteske if (__beg == __end && __a == _Alloc()) 147250323Sdteske return _S_empty_rep()._M_refcopy(); 148250323Sdteske 149250323Sdteske // Check for out_of_range and length_error exceptions. 150250323Sdteske _Rep* __r = _Rep::_S_create(__dnew, __a); 151250323Sdteske try 152250323Sdteske { _S_copy_chars(__r->_M_refdata(), __beg, __end); } 153250323Sdteske catch(...) 154250323Sdteske { 155250323Sdteske __r->_M_destroy(__a); 156250323Sdteske __throw_exception_again; 157250323Sdteske } 158250323Sdteske __r->_M_length = __dnew; 159250323Sdteske 160250323Sdteske __r->_M_refdata()[__dnew] = _Rep::_S_terminal; // grrr. 161250323Sdteske return __r->_M_refdata(); 162250323Sdteske } 163250323Sdteske 164250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 165250323Sdteske _CharT* 166250323Sdteske basic_string<_CharT, _Traits, _Alloc>:: 167250323Sdteske _S_construct(size_type __n, _CharT __c, const _Alloc& __a) 168250323Sdteske { 169250323Sdteske if (__n == 0 && __a == _Alloc()) 170250323Sdteske return _S_empty_rep()._M_refcopy(); 171250323Sdteske 172250323Sdteske // Check for out_of_range and length_error exceptions. 173250323Sdteske _Rep* __r = _Rep::_S_create(__n, __a); 174250323Sdteske try 175250323Sdteske { 176250323Sdteske if (__n) 177250323Sdteske traits_type::assign(__r->_M_refdata(), __n, __c); 178250323Sdteske } 179250323Sdteske catch(...) 180250323Sdteske { 181250323Sdteske __r->_M_destroy(__a); 182250323Sdteske __throw_exception_again; 183250323Sdteske } 184250323Sdteske __r->_M_length = __n; 185250323Sdteske __r->_M_refdata()[__n] = _Rep::_S_terminal; // grrr 186250323Sdteske return __r->_M_refdata(); 187250323Sdteske } 188250323Sdteske 189250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 190250323Sdteske basic_string<_CharT, _Traits, _Alloc>:: 191250323Sdteske basic_string(const basic_string& __str) 192250323Sdteske : _M_dataplus(__str._M_rep()->_M_grab(_Alloc(), __str.get_allocator()), 193250323Sdteske __str.get_allocator()) 194250323Sdteske { } 195250323Sdteske 196250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 197250323Sdteske basic_string<_CharT, _Traits, _Alloc>:: 198250323Sdteske basic_string(const _Alloc& __a) 199250323Sdteske : _M_dataplus(_S_construct(size_type(), _CharT(), __a), __a) 200250323Sdteske { } 201250323Sdteske 202250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 203250323Sdteske basic_string<_CharT, _Traits, _Alloc>:: 204250323Sdteske basic_string(const basic_string& __str, size_type __pos, size_type __n) 205250323Sdteske : _M_dataplus(_S_construct(__str._M_check(__pos), 206250323Sdteske __str._M_fold(__pos, __n), _Alloc()), _Alloc()) 207250323Sdteske { } 208250323Sdteske 209250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 210250323Sdteske basic_string<_CharT, _Traits, _Alloc>:: 211250323Sdteske basic_string(const basic_string& __str, size_type __pos, 212250323Sdteske size_type __n, const _Alloc& __a) 213250323Sdteske : _M_dataplus(_S_construct(__str._M_check(__pos), 214250323Sdteske __str._M_fold(__pos, __n), __a), __a) 215250323Sdteske { } 216250323Sdteske 217250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 218250323Sdteske basic_string<_CharT, _Traits, _Alloc>:: 219250323Sdteske basic_string(const _CharT* __s, size_type __n, const _Alloc& __a) 220250323Sdteske : _M_dataplus(_S_construct(__s, __s + __n, __a), __a) 221250323Sdteske { } 222250323Sdteske 223250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 224250323Sdteske basic_string<_CharT, _Traits, _Alloc>:: 225250323Sdteske basic_string(const _CharT* __s, const _Alloc& __a) 226250323Sdteske : _M_dataplus(_S_construct(__s, __s ? __s + traits_type::length(__s) : 0, 227250323Sdteske __a), __a) 228250323Sdteske { } 229250323Sdteske 230250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 231250323Sdteske basic_string<_CharT, _Traits, _Alloc>:: 232250323Sdteske basic_string(size_type __n, _CharT __c, const _Alloc& __a) 233250323Sdteske : _M_dataplus(_S_construct(__n, __c, __a), __a) 234250323Sdteske { } 235250323Sdteske 236250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 237250323Sdteske template<typename _InputIter> 238250323Sdteske basic_string<_CharT, _Traits, _Alloc>:: 239250323Sdteske basic_string(_InputIter __beg, _InputIter __end, const _Alloc& __a) 240250323Sdteske : _M_dataplus(_S_construct(__beg, __end, __a), __a) 241250323Sdteske { } 242250323Sdteske 243250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 244250323Sdteske basic_string<_CharT, _Traits, _Alloc>& 245250323Sdteske basic_string<_CharT, _Traits, _Alloc>::assign(const basic_string& __str) 246250323Sdteske { 247250323Sdteske if (_M_rep() != __str._M_rep()) 248250323Sdteske { 249250323Sdteske // XXX MT 250250323Sdteske allocator_type __a = this->get_allocator(); 251250323Sdteske _CharT* __tmp = __str._M_rep()->_M_grab(__a, __str.get_allocator()); 252250323Sdteske _M_rep()->_M_dispose(__a); 253250323Sdteske _M_data(__tmp); 254250323Sdteske } 255250323Sdteske return *this; 256250323Sdteske } 257250323Sdteske 258250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 259250323Sdteske void 260250323Sdteske basic_string<_CharT, _Traits, _Alloc>::_Rep:: 261250323Sdteske _M_destroy(const _Alloc& __a) throw () 262250323Sdteske { 263250323Sdteske size_type __size = sizeof(_Rep) + (_M_capacity + 1) * sizeof(_CharT); 264250323Sdteske _Raw_bytes_alloc(__a).deallocate(reinterpret_cast<char*>(this), __size); 265250323Sdteske } 266250323Sdteske 267250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 268250323Sdteske void 269250323Sdteske basic_string<_CharT, _Traits, _Alloc>::_M_leak_hard() 270250323Sdteske { 271250323Sdteske if (_M_rep()->_M_is_shared()) 272250323Sdteske _M_mutate(0, 0, 0); 273250323Sdteske _M_rep()->_M_set_leaked(); 274250323Sdteske } 275251236Sdteske 276251236Sdteske // _M_mutate and, below, _M_clone, include, in the same form, an exponential 277250323Sdteske // growth policy, necessary to meet amortized linear time requirements of 278250323Sdteske // the library: see http://gcc.gnu.org/ml/libstdc++/2001-07/msg00085.html. 279250323Sdteske // The policy is active for allocations requiring an amount of memory above 280251264Sdteske // system pagesize. This is consistent with the requirements of the standard: 281251264Sdteske // see, f.i., http://gcc.gnu.org/ml/libstdc++/2001-07/msg00130.html 282251264Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 283251264Sdteske void 284251264Sdteske basic_string<_CharT, _Traits, _Alloc>:: 285251264Sdteske _M_mutate(size_type __pos, size_type __len1, size_type __len2) 286250323Sdteske { 287250323Sdteske size_type __old_size = this->size(); 288250323Sdteske const size_type __new_size = __old_size + __len2 - __len1; 289250323Sdteske const _CharT* __src = _M_data() + __pos + __len1; 290250323Sdteske const size_type __how_much = __old_size - __pos - __len1; 291250323Sdteske 292251264Sdteske if (_M_rep()->_M_is_shared() || __new_size > capacity()) 293250323Sdteske { 294250323Sdteske // Must reallocate. 295250323Sdteske allocator_type __a = get_allocator(); 296250323Sdteske // See below (_S_create) for the meaning and value of these 297250323Sdteske // constants. 298251264Sdteske const size_type __pagesize = 4096; 299251264Sdteske const size_type __malloc_header_size = 4 * sizeof (void*); 300250323Sdteske // The biggest string which fits in a memory page 301251236Sdteske const size_type __page_capacity = (__pagesize - __malloc_header_size 302251232Sdteske - sizeof(_Rep) - sizeof(_CharT)) 303251232Sdteske / sizeof(_CharT); 304251232Sdteske _Rep* __r; 305251232Sdteske if (__new_size > capacity() && __new_size > __page_capacity) 306251232Sdteske // Growing exponentially. 307251232Sdteske __r = _Rep::_S_create(__new_size > 2*capacity() ? 308251236Sdteske __new_size : 2*capacity(), __a); 309251236Sdteske else 310251266Sdteske __r = _Rep::_S_create(__new_size, __a); 311251266Sdteske try 312251266Sdteske { 313251266Sdteske if (__pos) 314251266Sdteske traits_type::copy(__r->_M_refdata(), _M_data(), __pos); 315251266Sdteske if (__how_much) 316251266Sdteske traits_type::copy(__r->_M_refdata() + __pos + __len2, 317251266Sdteske __src, __how_much); 318251266Sdteske } 319251266Sdteske catch(...) 320251266Sdteske { 321251266Sdteske __r->_M_dispose(get_allocator()); 322250323Sdteske __throw_exception_again; 323251236Sdteske } 324250323Sdteske _M_rep()->_M_dispose(__a); 325250323Sdteske _M_data(__r->_M_refdata()); 326250323Sdteske } 327250323Sdteske else if (__how_much && __len1 != __len2) 328250323Sdteske { 329250323Sdteske // Work in-place 330250323Sdteske traits_type::move(_M_data() + __pos + __len2, __src, __how_much); 331250323Sdteske } 332250323Sdteske _M_rep()->_M_set_sharable(); 333250323Sdteske _M_rep()->_M_length = __new_size; 334250323Sdteske _M_data()[__new_size] = _Rep::_S_terminal; // grrr. (per 21.3.4) 335250323Sdteske // You cannot leave those LWG people alone for a second. 336250323Sdteske } 337250323Sdteske 338250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 339250323Sdteske void 340250323Sdteske basic_string<_CharT, _Traits, _Alloc>::reserve(size_type __res) 341250323Sdteske { 342250323Sdteske if (__res > this->capacity() || _M_rep()->_M_is_shared()) 343250323Sdteske { 344250323Sdteske if (__res > this->max_size()) 345250323Sdteske __throw_length_error("basic_string::reserve"); 346250323Sdteske // Make sure we don't shrink below the current size 347250323Sdteske if (__res < this->size()) 348250323Sdteske __res = this->size(); 349250323Sdteske allocator_type __a = get_allocator(); 350250323Sdteske _CharT* __tmp = _M_rep()->_M_clone(__a, __res - this->size()); 351250323Sdteske _M_rep()->_M_dispose(__a); 352250323Sdteske _M_data(__tmp); 353250323Sdteske } 354250323Sdteske } 355250323Sdteske 356251266Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 357250323Sdteske void basic_string<_CharT, _Traits, _Alloc>::swap(basic_string& __s) 358250323Sdteske { 359250323Sdteske if (_M_rep()->_M_is_leaked()) 360250323Sdteske _M_rep()->_M_set_sharable(); 361250323Sdteske if (__s._M_rep()->_M_is_leaked()) 362250323Sdteske __s._M_rep()->_M_set_sharable(); 363250323Sdteske if (this->get_allocator() == __s.get_allocator()) 364250323Sdteske { 365251236Sdteske _CharT* __tmp = _M_data(); 366250323Sdteske _M_data(__s._M_data()); 367250323Sdteske __s._M_data(__tmp); 368250323Sdteske } 369251264Sdteske // The code below can usually be optimized away. 370251264Sdteske else 371251264Sdteske { 372251264Sdteske basic_string __tmp1(_M_ibegin(), _M_iend(), __s.get_allocator()); 373251264Sdteske basic_string __tmp2(__s._M_ibegin(), __s._M_iend(), 374250323Sdteske this->get_allocator()); 375250323Sdteske *this = __tmp2; 376250323Sdteske __s = __tmp1; 377251264Sdteske } 378250323Sdteske } 379250323Sdteske 380250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 381251264Sdteske typename basic_string<_CharT, _Traits, _Alloc>::_Rep* 382250323Sdteske basic_string<_CharT, _Traits, _Alloc>::_Rep:: 383250538Sdteske _S_create(size_t __capacity, const _Alloc& __alloc) 384250323Sdteske { 385250323Sdteske typedef basic_string<_CharT, _Traits, _Alloc> __string_type; 386250323Sdteske#ifdef _GLIBCPP_RESOLVE_LIB_DEFECTS 387250323Sdteske // 83. String::npos vs. string::max_size() 388251264Sdteske if (__capacity > _S_max_size) 389250323Sdteske#else 390250323Sdteske if (__capacity == npos) 391250323Sdteske#endif 392250323Sdteske __throw_length_error("basic_string::_S_create"); 393250323Sdteske 394250323Sdteske // NB: Need an array of char_type[__capacity], plus a 395250323Sdteske // terminating null char_type() element, plus enough for the 396250323Sdteske // _Rep data structure. Whew. Seemingly so needy, yet so elemental. 397250323Sdteske size_t __size = (__capacity + 1) * sizeof(_CharT) + sizeof(_Rep); 398250323Sdteske 399250323Sdteske // The standard places no restriction on allocating more memory 400250323Sdteske // than is strictly needed within this layer at the moment or as 401250323Sdteske // requested by an explicit application call to reserve(). Many 402250323Sdteske // malloc implementations perform quite poorly when an 403250323Sdteske // application attempts to allocate memory in a stepwise fashion 404250323Sdteske // growing each allocation size by only 1 char. Additionally, 405250323Sdteske // it makes little sense to allocate less linear memory than the 406250323Sdteske // natural blocking size of the malloc implementation. 407250323Sdteske // Unfortunately, we would need a somewhat low-level calculation 408250323Sdteske // with tuned parameters to get this perfect for any particular 409250323Sdteske // malloc implementation. Fortunately, generalizations about 410250323Sdteske // common features seen among implementations seems to suffice. 411250323Sdteske 412250323Sdteske // __pagesize need not match the actual VM page size for good 413250323Sdteske // results in practice, thus we pick a common value on the low 414250323Sdteske // side. __malloc_header_size is an estimate of the amount of 415251264Sdteske // overhead per memory allocation (in practice seen N * sizeof 416251264Sdteske // (void*) where N is 0, 2 or 4). According to folklore, 417251264Sdteske // picking this value on the high side is better than 418250323Sdteske // low-balling it (especially when this algorithm is used with 419250323Sdteske // malloc implementations that allocate memory blocks rounded up 420250323Sdteske // to a size which is a power of 2). 421250323Sdteske const size_t __pagesize = 4096; // must be 2^i * __subpagesize 422250323Sdteske const size_t __subpagesize = 128; // should be >> __malloc_header_size 423250323Sdteske const size_t __malloc_header_size = 4 * sizeof (void*); 424250323Sdteske if ((__size + __malloc_header_size) > __pagesize) 425250323Sdteske { 426250323Sdteske size_t __extra = 427250323Sdteske (__pagesize - ((__size + __malloc_header_size) % __pagesize)) 428250323Sdteske % __pagesize; 429250323Sdteske __capacity += __extra / sizeof(_CharT); 430250323Sdteske __size = (__capacity + 1) * sizeof(_CharT) + sizeof(_Rep); 431250323Sdteske } 432250323Sdteske else if (__size > __subpagesize) 433250323Sdteske { 434250323Sdteske size_t __extra = 435250323Sdteske (__subpagesize - ((__size + __malloc_header_size) % __subpagesize)) 436250323Sdteske % __subpagesize; 437250323Sdteske __capacity += __extra / sizeof(_CharT); 438250323Sdteske __size = (__capacity + 1) * sizeof(_CharT) + sizeof(_Rep); 439250323Sdteske } 440250323Sdteske 441250323Sdteske // NB: Might throw, but no worries about a leak, mate: _Rep() 442250323Sdteske // does not throw. 443250323Sdteske void* __place = _Raw_bytes_alloc(__alloc).allocate(__size); 444250323Sdteske _Rep *__p = new (__place) _Rep; 445250323Sdteske __p->_M_capacity = __capacity; 446250323Sdteske __p->_M_set_sharable(); // One reference. 447250323Sdteske __p->_M_length = 0; 448250323Sdteske return __p; 449250323Sdteske } 450250323Sdteske 451250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 452250323Sdteske _CharT* 453250323Sdteske basic_string<_CharT, _Traits, _Alloc>::_Rep:: 454250323Sdteske _M_clone(const _Alloc& __alloc, size_type __res) 455250323Sdteske { 456250323Sdteske // Requested capacity of the clone. 457250538Sdteske const size_type __requested_cap = _M_length + __res; 458250538Sdteske // See above (_S_create) for the meaning and value of these constants. 459250538Sdteske const size_type __pagesize = 4096; 460250538Sdteske const size_type __malloc_header_size = 4 * sizeof (void*); 461250538Sdteske // The biggest string which fits in a memory page. 462250538Sdteske const size_type __page_capacity = 463250323Sdteske (__pagesize - __malloc_header_size - sizeof(_Rep) - sizeof(_CharT)) 464250323Sdteske / sizeof(_CharT); 465250323Sdteske _Rep* __r; 466251232Sdteske if (__requested_cap > _M_capacity && __requested_cap > __page_capacity) 467251232Sdteske // Growing exponentially. 468251232Sdteske __r = _Rep::_S_create(__requested_cap > 2*_M_capacity ? 469251232Sdteske __requested_cap : 2*_M_capacity, __alloc); 470251232Sdteske else 471251232Sdteske __r = _Rep::_S_create(__requested_cap, __alloc); 472251232Sdteske 473251232Sdteske if (_M_length) 474251236Sdteske { 475251236Sdteske try 476251236Sdteske { traits_type::copy(__r->_M_refdata(), _M_refdata(), _M_length); } 477250323Sdteske catch(...) 478250323Sdteske { 479250323Sdteske __r->_M_destroy(__alloc); 480250323Sdteske __throw_exception_again; 481250323Sdteske } 482250323Sdteske } 483250323Sdteske __r->_M_length = _M_length; 484250323Sdteske return __r->_M_refdata(); 485251232Sdteske } 486251232Sdteske 487250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 488250323Sdteske void 489250323Sdteske basic_string<_CharT, _Traits, _Alloc>::resize(size_type __n, _CharT __c) 490251232Sdteske { 491251232Sdteske if (__n > max_size()) 492250323Sdteske __throw_length_error("basic_string::resize"); 493250323Sdteske size_type __size = this->size(); 494250323Sdteske if (__size < __n) 495251236Sdteske this->append(__n - __size, __c); 496251236Sdteske else if (__n < __size) 497250323Sdteske this->erase(__n); 498250323Sdteske // else nothing (in particular, avoid calling _M_mutate() unnecessarily.) 499251236Sdteske } 500250323Sdteske 501251236Sdteske 502250323Sdteske // This is the general replace helper, which currently gets instantiated both 503250323Sdteske // for input iterators and reverse iterators. It buffers internally and then 504250323Sdteske // calls _M_replace_safe. 505250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 506250323Sdteske template<typename _InputIter> 507250323Sdteske basic_string<_CharT, _Traits, _Alloc>& 508250323Sdteske basic_string<_CharT, _Traits, _Alloc>:: 509250323Sdteske _M_replace(iterator __i1, iterator __i2, _InputIter __k1, 510250323Sdteske _InputIter __k2, input_iterator_tag) 511250323Sdteske { 512250323Sdteske // Save concerned source string data in a temporary. 513250323Sdteske basic_string __s(__k1, __k2); 514251236Sdteske return _M_replace_safe(__i1, __i2, __s._M_ibegin(), __s._M_iend()); 515250323Sdteske } 516250323Sdteske 517250323Sdteske // This is a special replace helper, which does not buffer internally 518251264Sdteske // and can be used in "safe" situations involving forward iterators, 519251264Sdteske // i.e., when source and destination ranges are known to not overlap. 520251264Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 521250323Sdteske template<typename _ForwardIter> 522250323Sdteske basic_string<_CharT, _Traits, _Alloc>& 523250323Sdteske basic_string<_CharT, _Traits, _Alloc>:: 524250323Sdteske _M_replace_safe(iterator __i1, iterator __i2, _ForwardIter __k1, 525251264Sdteske _ForwardIter __k2) 526251232Sdteske { 527251264Sdteske size_type __dnew = static_cast<size_type>(distance(__k1, __k2)); 528251264Sdteske size_type __dold = __i2 - __i1; 529251232Sdteske size_type __dmax = this->max_size(); 530251232Sdteske 531251232Sdteske if (__dmax <= __dnew) 532251232Sdteske __throw_length_error("basic_string::_M_replace"); 533251232Sdteske size_type __off = __i1 - _M_ibegin(); 534251232Sdteske _M_mutate(__off, __dold, __dnew); 535251232Sdteske 536251236Sdteske // Invalidated __i1, __i2 537251236Sdteske if (__dnew) 538250323Sdteske _S_copy_chars(_M_data() + __off, __k1, __k2); 539250323Sdteske 540250323Sdteske return *this; 541250323Sdteske } 542250323Sdteske 543251232Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 544251232Sdteske basic_string<_CharT, _Traits, _Alloc>& 545250323Sdteske basic_string<_CharT, _Traits, _Alloc>:: 546250323Sdteske replace(size_type __pos1, size_type __n1, const basic_string& __str, 547250323Sdteske size_type __pos2, size_type __n2) 548250323Sdteske { 549251236Sdteske const size_type __strsize = __str.size(); 550250323Sdteske if (__pos2 > __strsize) 551250323Sdteske __throw_out_of_range("basic_string::replace"); 552250323Sdteske const bool __testn2 = __n2 < __strsize - __pos2; 553250323Sdteske const size_type __foldn2 = __testn2 ? __n2 : __strsize - __pos2; 554250323Sdteske return this->replace(__pos1, __n1, 555250323Sdteske __str._M_data() + __pos2, __foldn2); 556250323Sdteske } 557250323Sdteske 558250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 559250323Sdteske basic_string<_CharT, _Traits, _Alloc>& 560250323Sdteske basic_string<_CharT, _Traits, _Alloc>:: 561250323Sdteske append(const basic_string& __str) 562251264Sdteske { 563251264Sdteske // Iff appending itself, string needs to pre-reserve the 564250323Sdteske // correct size so that _M_mutate does not clobber the 565251264Sdteske // iterators formed here. 566250323Sdteske size_type __size = __str.size(); 567250323Sdteske size_type __len = __size + this->size(); 568251264Sdteske if (__len > this->capacity()) 569251264Sdteske this->reserve(__len); 570251264Sdteske return _M_replace_safe(_M_iend(), _M_iend(), __str._M_ibegin(), 571251264Sdteske __str._M_iend()); 572250323Sdteske } 573250323Sdteske 574250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 575250323Sdteske basic_string<_CharT, _Traits, _Alloc>& 576250323Sdteske basic_string<_CharT, _Traits, _Alloc>:: 577250323Sdteske append(const basic_string& __str, size_type __pos, size_type __n) 578250323Sdteske { 579250323Sdteske // Iff appending itself, string needs to pre-reserve the 580250323Sdteske // correct size so that _M_mutate does not clobber the 581250323Sdteske // iterators formed here. 582250323Sdteske size_type __len = min(__str.size() - __pos, __n) + this->size(); 583250323Sdteske if (__len > this->capacity()) 584250323Sdteske this->reserve(__len); 585250323Sdteske return _M_replace_safe(_M_iend(), _M_iend(), __str._M_check(__pos), 586251232Sdteske __str._M_fold(__pos, __n)); 587251232Sdteske } 588251232Sdteske 589251232Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 590251232Sdteske basic_string<_CharT, _Traits, _Alloc>& 591251232Sdteske basic_string<_CharT, _Traits, _Alloc>:: 592251232Sdteske append(const _CharT* __s, size_type __n) 593251232Sdteske { 594251232Sdteske size_type __len = __n + this->size(); 595251236Sdteske if (__len > this->capacity()) 596251236Sdteske this->reserve(__len); 597250323Sdteske return _M_replace_safe(_M_iend(), _M_iend(), __s, __s + __n); 598250323Sdteske } 599250323Sdteske 600250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 601250323Sdteske basic_string<_CharT, _Traits, _Alloc>& 602251232Sdteske basic_string<_CharT, _Traits, _Alloc>:: 603251232Sdteske append(size_type __n, _CharT __c) 604250323Sdteske { 605251236Sdteske size_type __len = __n + this->size(); 606250323Sdteske if (__len > this->capacity()) 607250323Sdteske this->reserve(__len); 608250323Sdteske return this->replace(_M_iend(), _M_iend(), __n, __c); 609250323Sdteske } 610250323Sdteske 611250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 612250323Sdteske basic_string<_CharT, _Traits, _Alloc> 613250323Sdteske operator+(const _CharT* __lhs, 614250323Sdteske const basic_string<_CharT, _Traits, _Alloc>& __rhs) 615250323Sdteske { 616250323Sdteske typedef basic_string<_CharT, _Traits, _Alloc> __string_type; 617250323Sdteske typedef typename __string_type::size_type __size_type; 618250323Sdteske __size_type __len = _Traits::length(__lhs); 619250323Sdteske __string_type __str; 620250323Sdteske __str.reserve(__len + __rhs.size()); 621250323Sdteske __str.append(__lhs, __lhs + __len); 622250323Sdteske __str.append(__rhs); 623250323Sdteske return __str; 624250323Sdteske } 625250323Sdteske 626250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 627250323Sdteske basic_string<_CharT, _Traits, _Alloc> 628250323Sdteske operator+(_CharT __lhs, const basic_string<_CharT, _Traits, _Alloc>& __rhs) 629250323Sdteske { 630250323Sdteske typedef basic_string<_CharT, _Traits, _Alloc> __string_type; 631250323Sdteske typedef typename __string_type::size_type __size_type; 632250323Sdteske __string_type __str; 633250323Sdteske __size_type __len = __rhs.size(); 634250323Sdteske __str.reserve(__len + 1); 635250323Sdteske __str.append(__size_type(1), __lhs); 636250323Sdteske __str.append(__rhs); 637250323Sdteske return __str; 638250323Sdteske } 639250323Sdteske 640250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 641250323Sdteske basic_string<_CharT, _Traits, _Alloc>& 642250323Sdteske basic_string<_CharT, _Traits, _Alloc>:: 643250323Sdteske replace(iterator __i1, iterator __i2, size_type __n2, _CharT __c) 644251236Sdteske { 645250323Sdteske size_type __n1 = __i2 - __i1; 646250323Sdteske size_type __off1 = __i1 - _M_ibegin(); 647250323Sdteske if (max_size() - (this->size() - __n1) <= __n2) 648250323Sdteske __throw_length_error("basic_string::replace"); 649250323Sdteske _M_mutate (__off1, __n1, __n2); 650250323Sdteske // Invalidated __i1, __i2 651250323Sdteske if (__n2) 652250323Sdteske traits_type::assign(_M_data() + __off1, __n2, __c); 653250323Sdteske return *this; 654250323Sdteske } 655250323Sdteske 656250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 657250323Sdteske typename basic_string<_CharT, _Traits, _Alloc>::size_type 658250323Sdteske basic_string<_CharT, _Traits, _Alloc>:: 659250323Sdteske copy(_CharT* __s, size_type __n, size_type __pos) const 660250323Sdteske { 661250323Sdteske if (__pos > this->size()) 662250323Sdteske __throw_out_of_range("basic_string::copy"); 663250323Sdteske 664250323Sdteske if (__n > this->size() - __pos) 665250323Sdteske __n = this->size() - __pos; 666251236Sdteske 667250323Sdteske traits_type::copy(__s, _M_data() + __pos, __n); 668250323Sdteske // 21.3.5.7 par 3: do not append null. (good.) 669250323Sdteske return __n; 670250323Sdteske } 671250323Sdteske 672250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 673250323Sdteske typename basic_string<_CharT, _Traits, _Alloc>::size_type 674250323Sdteske basic_string<_CharT, _Traits, _Alloc>:: 675251236Sdteske find(const _CharT* __s, size_type __pos, size_type __n) const 676251236Sdteske { 677250323Sdteske size_type __size = this->size(); 678250323Sdteske size_t __xpos = __pos; 679250323Sdteske const _CharT* __data = _M_data(); 680250323Sdteske for (; __xpos + __n <= __size; ++__xpos) 681250323Sdteske if (traits_type::compare(__data + __xpos, __s, __n) == 0) 682250323Sdteske return __xpos; 683250323Sdteske return npos; 684251236Sdteske } 685250323Sdteske 686250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 687250323Sdteske typename basic_string<_CharT, _Traits, _Alloc>::size_type 688250323Sdteske basic_string<_CharT, _Traits, _Alloc>:: 689251236Sdteske find(_CharT __c, size_type __pos) const 690250323Sdteske { 691250323Sdteske size_type __size = this->size(); 692250323Sdteske size_type __ret = npos; 693251236Sdteske if (__pos < __size) 694250323Sdteske { 695250323Sdteske const _CharT* __data = _M_data(); 696250323Sdteske size_type __n = __size - __pos; 697251236Sdteske const _CharT* __p = traits_type::find(__data + __pos, __n, __c); 698250323Sdteske if (__p) 699250323Sdteske __ret = __p - __data; 700250323Sdteske } 701251236Sdteske return __ret; 702250323Sdteske } 703250323Sdteske 704250323Sdteske 705250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 706250323Sdteske typename basic_string<_CharT, _Traits, _Alloc>::size_type 707250323Sdteske basic_string<_CharT, _Traits, _Alloc>:: 708250323Sdteske rfind(const _CharT* __s, size_type __pos, size_type __n) const 709250323Sdteske { 710250323Sdteske size_type __size = this->size(); 711250323Sdteske if (__n <= __size) 712250323Sdteske { 713250323Sdteske __pos = std::min(__size - __n, __pos); 714250323Sdteske const _CharT* __data = _M_data(); 715250323Sdteske do 716250323Sdteske { 717250323Sdteske if (traits_type::compare(__data + __pos, __s, __n) == 0) 718250323Sdteske return __pos; 719250323Sdteske } 720250323Sdteske while (__pos-- > 0); 721250323Sdteske } 722250323Sdteske return npos; 723250323Sdteske } 724250323Sdteske 725250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 726250323Sdteske typename basic_string<_CharT, _Traits, _Alloc>::size_type 727250323Sdteske basic_string<_CharT, _Traits, _Alloc>:: 728250323Sdteske rfind(_CharT __c, size_type __pos) const 729250323Sdteske { 730250323Sdteske size_type __size = this->size(); 731250323Sdteske if (__size) 732250323Sdteske { 733250323Sdteske size_t __xpos = __size - 1; 734250323Sdteske if (__xpos > __pos) 735250323Sdteske __xpos = __pos; 736250323Sdteske 737250323Sdteske for (++__xpos; __xpos-- > 0; ) 738250323Sdteske if (traits_type::eq(_M_data()[__xpos], __c)) 739250323Sdteske return __xpos; 740251236Sdteske } 741250323Sdteske return npos; 742250323Sdteske } 743250323Sdteske 744250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 745250323Sdteske typename basic_string<_CharT, _Traits, _Alloc>::size_type 746250323Sdteske basic_string<_CharT, _Traits, _Alloc>:: 747250323Sdteske find_first_of(const _CharT* __s, size_type __pos, size_type __n) const 748250323Sdteske { 749250323Sdteske for (; __n && __pos < this->size(); ++__pos) 750250323Sdteske { 751250323Sdteske const _CharT* __p = traits_type::find(__s, __n, _M_data()[__pos]); 752250323Sdteske if (__p) 753250323Sdteske return __pos; 754250323Sdteske } 755250323Sdteske return npos; 756251236Sdteske } 757251236Sdteske 758250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 759250323Sdteske typename basic_string<_CharT, _Traits, _Alloc>::size_type 760250323Sdteske basic_string<_CharT, _Traits, _Alloc>:: 761250323Sdteske find_last_of(const _CharT* __s, size_type __pos, size_type __n) const 762250323Sdteske { 763250323Sdteske size_type __size = this->size(); 764250323Sdteske if (__size && __n) 765250323Sdteske { 766250323Sdteske if (--__size > __pos) 767250323Sdteske __size = __pos; 768250323Sdteske do 769250323Sdteske { 770250323Sdteske if (traits_type::find(__s, __n, _M_data()[__size])) 771250323Sdteske return __size; 772250323Sdteske } 773250323Sdteske while (__size-- != 0); 774250323Sdteske } 775250323Sdteske return npos; 776250323Sdteske } 777250323Sdteske 778250323Sdteske template<typename _CharT, typename _Traits, typename _Alloc> 779250323Sdteske typename basic_string<_CharT, _Traits, _Alloc>::size_type 780250323Sdteske basic_string<_CharT, _Traits, _Alloc>:: 781250323Sdteske find_first_not_of(const _CharT* __s, size_type __pos, size_type __n) const 782250323Sdteske { 783250323Sdteske size_t __xpos = __pos; 784 for (; __xpos < this->size(); ++__xpos) 785 if (!traits_type::find(__s, __n, _M_data()[__xpos])) 786 return __xpos; 787 return npos; 788 } 789 790 template<typename _CharT, typename _Traits, typename _Alloc> 791 typename basic_string<_CharT, _Traits, _Alloc>::size_type 792 basic_string<_CharT, _Traits, _Alloc>:: 793 find_first_not_of(_CharT __c, size_type __pos) const 794 { 795 size_t __xpos = __pos; 796 for (; __xpos < this->size(); ++__xpos) 797 if (!traits_type::eq(_M_data()[__xpos], __c)) 798 return __xpos; 799 return npos; 800 } 801 802 template<typename _CharT, typename _Traits, typename _Alloc> 803 typename basic_string<_CharT, _Traits, _Alloc>::size_type 804 basic_string<_CharT, _Traits, _Alloc>:: 805 find_last_not_of(const _CharT* __s, size_type __pos, size_type __n) const 806 { 807 size_type __size = this->size(); 808 if (__size) 809 { 810 if (--__size > __pos) 811 __size = __pos; 812 do 813 { 814 if (!traits_type::find(__s, __n, _M_data()[__size])) 815 return __size; 816 } 817 while (__size--); 818 } 819 return npos; 820 } 821 822 template<typename _CharT, typename _Traits, typename _Alloc> 823 typename basic_string<_CharT, _Traits, _Alloc>::size_type 824 basic_string<_CharT, _Traits, _Alloc>:: 825 find_last_not_of(_CharT __c, size_type __pos) const 826 { 827 size_type __size = this->size(); 828 if (__size) 829 { 830 if (--__size > __pos) 831 __size = __pos; 832 do 833 { 834 if (!traits_type::eq(_M_data()[__size], __c)) 835 return __size; 836 } 837 while (__size--); 838 } 839 return npos; 840 } 841 842 template<typename _CharT, typename _Traits, typename _Alloc> 843 int 844 basic_string<_CharT, _Traits, _Alloc>:: 845 compare(size_type __pos, size_type __n, const basic_string& __str) const 846 { 847 size_type __size = this->size(); 848 size_type __osize = __str.size(); 849 if (__pos > __size) 850 __throw_out_of_range("basic_string::compare"); 851 852 size_type __rsize= min(__size - __pos, __n); 853 size_type __len = min(__rsize, __osize); 854 int __r = traits_type::compare(_M_data() + __pos, __str.data(), __len); 855 if (!__r) 856 __r = __rsize - __osize; 857 return __r; 858 } 859 860 template<typename _CharT, typename _Traits, typename _Alloc> 861 int 862 basic_string<_CharT, _Traits, _Alloc>:: 863 compare(size_type __pos1, size_type __n1, const basic_string& __str, 864 size_type __pos2, size_type __n2) const 865 { 866 size_type __size = this->size(); 867 size_type __osize = __str.size(); 868 if (__pos1 > __size || __pos2 > __osize) 869 __throw_out_of_range("basic_string::compare"); 870 871 size_type __rsize = min(__size - __pos1, __n1); 872 size_type __rosize = min(__osize - __pos2, __n2); 873 size_type __len = min(__rsize, __rosize); 874 int __r = traits_type::compare(_M_data() + __pos1, 875 __str.data() + __pos2, __len); 876 if (!__r) 877 __r = __rsize - __rosize; 878 return __r; 879 } 880 881 882 template<typename _CharT, typename _Traits, typename _Alloc> 883 int 884 basic_string<_CharT, _Traits, _Alloc>:: 885 compare(const _CharT* __s) const 886 { 887 size_type __size = this->size(); 888 int __r = traits_type::compare(_M_data(), __s, __size); 889 if (!__r) 890 __r = __size - traits_type::length(__s); 891 return __r; 892 } 893 894 895 template<typename _CharT, typename _Traits, typename _Alloc> 896 int 897 basic_string <_CharT, _Traits, _Alloc>:: 898 compare(size_type __pos, size_type __n1, const _CharT* __s) const 899 { 900 size_type __size = this->size(); 901 if (__pos > __size) 902 __throw_out_of_range("basic_string::compare"); 903 904 size_type __osize = traits_type::length(__s); 905 size_type __rsize = min(__size - __pos, __n1); 906 size_type __len = min(__rsize, __osize); 907 int __r = traits_type::compare(_M_data() + __pos, __s, __len); 908 if (!__r) 909 __r = __rsize - __osize; 910 return __r; 911 } 912 913 template<typename _CharT, typename _Traits, typename _Alloc> 914 int 915 basic_string <_CharT, _Traits, _Alloc>:: 916 compare(size_type __pos, size_type __n1, const _CharT* __s, 917 size_type __n2) const 918 { 919 size_type __size = this->size(); 920 if (__pos > __size) 921 __throw_out_of_range("basic_string::compare"); 922 923 size_type __osize = min(traits_type::length(__s), __n2); 924 size_type __rsize = min(__size - __pos, __n1); 925 size_type __len = min(__rsize, __osize); 926 int __r = traits_type::compare(_M_data() + __pos, __s, __len); 927 if (!__r) 928 __r = __rsize - __osize; 929 return __r; 930 } 931 932 template <class _CharT, class _Traits, class _Alloc> 933 void 934 _S_string_copy(const basic_string<_CharT, _Traits, _Alloc>& __str, 935 _CharT* __buf, typename _Alloc::size_type __bufsiz) 936 { 937 typedef typename _Alloc::size_type size_type; 938 size_type __strsize = __str.size(); 939 size_type __bytes = min(__strsize, __bufsiz - 1); 940 _Traits::copy(__buf, __str.data(), __bytes); 941 __buf[__bytes] = _CharT(); 942 } 943 944 // Inhibit implicit instantiations for required instantiations, 945 // which are defined via explicit instantiations elsewhere. 946 // NB: This syntax is a GNU extension. 947 extern template class basic_string<char>; 948 extern template 949 basic_istream<char>& 950 operator>>(basic_istream<char>&, string&); 951 extern template 952 basic_ostream<char>& 953 operator<<(basic_ostream<char>&, const string&); 954 extern template 955 basic_istream<char>& 956 getline(basic_istream<char>&, string&, char); 957 extern template 958 basic_istream<char>& 959 getline(basic_istream<char>&, string&); 960 961 extern template class basic_string<wchar_t>; 962 extern template 963 basic_istream<wchar_t>& 964 operator>>(basic_istream<wchar_t>&, wstring&); 965 extern template 966 basic_ostream<wchar_t>& 967 operator<<(basic_ostream<wchar_t>&, const wstring&); 968 extern template 969 basic_istream<wchar_t>& 970 getline(basic_istream<wchar_t>&, wstring&, wchar_t); 971 extern template 972 basic_istream<wchar_t>& 973 getline(basic_istream<wchar_t>&, wstring&); 974} // namespace std 975 976#endif 977