1 | // Components for manipulating sequences of characters -*- C++ -*- |
2 | |
3 | // Copyright (C) 1997-2022 Free Software Foundation, Inc. |
4 | // |
5 | // This file is part of the GNU ISO C++ Library. This library is free |
6 | // software; you can redistribute it and/or modify it under the |
7 | // terms of the GNU General Public License as published by the |
8 | // Free Software Foundation; either version 3, or (at your option) |
9 | // any later version. |
10 | |
11 | // This library is distributed in the hope that it will be useful, |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | // GNU General Public License for more details. |
15 | |
16 | // Under Section 7 of GPL version 3, you are granted additional |
17 | // permissions described in the GCC Runtime Library Exception, version |
18 | // 3.1, as published by the Free Software Foundation. |
19 | |
20 | // You should have received a copy of the GNU General Public License and |
21 | // a copy of the GCC Runtime Library Exception along with this program; |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
23 | // <http://www.gnu.org/licenses/>. |
24 | |
25 | /** @file bits/basic_string.tcc |
26 | * This is an internal header file, included by other library headers. |
27 | * Do not attempt to use it directly. @headername{string} |
28 | */ |
29 | |
30 | // |
31 | // ISO C++ 14882: 21 Strings library |
32 | // |
33 | |
34 | // Written by Jason Merrill based upon the specification by Takanori Adachi |
35 | // in ANSI X3J16/94-0013R2. Rewritten by Nathan Myers to ISO-14882. |
36 | // Non-reference-counted implementation written by Paolo Carlini and |
37 | // updated by Jonathan Wakely for ISO-14882-2011. |
38 | |
39 | #ifndef _BASIC_STRING_TCC |
40 | #define _BASIC_STRING_TCC 1 |
41 | |
42 | #pragma GCC system_header |
43 | |
44 | #include <bits/cxxabi_forced.h> |
45 | |
46 | namespace std _GLIBCXX_VISIBILITY(default) |
47 | { |
48 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
49 | |
50 | #if _GLIBCXX_USE_CXX11_ABI |
51 | |
52 | template<typename _CharT, typename _Traits, typename _Alloc> |
53 | const typename basic_string<_CharT, _Traits, _Alloc>::size_type |
54 | basic_string<_CharT, _Traits, _Alloc>::npos; |
55 | |
56 | template<typename _CharT, typename _Traits, typename _Alloc> |
57 | _GLIBCXX20_CONSTEXPR |
58 | void |
59 | basic_string<_CharT, _Traits, _Alloc>:: |
60 | swap(basic_string& __s) _GLIBCXX_NOEXCEPT |
61 | { |
62 | if (this == std::__addressof(__s)) |
63 | return; |
64 | |
65 | _Alloc_traits::_S_on_swap(_M_get_allocator(), __s._M_get_allocator()); |
66 | |
67 | if (_M_is_local()) |
68 | if (__s._M_is_local()) |
69 | { |
70 | if (length() && __s.length()) |
71 | { |
72 | _CharT __tmp_data[_S_local_capacity + 1]; |
73 | traits_type::copy(__tmp_data, __s._M_local_buf, |
74 | __s.length() + 1); |
75 | traits_type::copy(__s._M_local_buf, _M_local_buf, |
76 | length() + 1); |
77 | traits_type::copy(_M_local_buf, __tmp_data, |
78 | __s.length() + 1); |
79 | } |
80 | else if (__s.length()) |
81 | { |
82 | traits_type::copy(_M_local_buf, __s._M_local_buf, |
83 | __s.length() + 1); |
84 | _M_length(length: __s.length()); |
85 | __s._M_set_length(0); |
86 | return; |
87 | } |
88 | else if (length()) |
89 | { |
90 | traits_type::copy(__s._M_local_buf, _M_local_buf, |
91 | length() + 1); |
92 | __s._M_length(length()); |
93 | _M_set_length(n: 0); |
94 | return; |
95 | } |
96 | } |
97 | else |
98 | { |
99 | const size_type __tmp_capacity = __s._M_allocated_capacity; |
100 | traits_type::copy(__s._M_local_buf, _M_local_buf, |
101 | length() + 1); |
102 | _M_data(__s._M_data()); |
103 | __s._M_data(__s._M_local_buf); |
104 | _M_capacity(capacity: __tmp_capacity); |
105 | } |
106 | else |
107 | { |
108 | const size_type __tmp_capacity = _M_allocated_capacity; |
109 | if (__s._M_is_local()) |
110 | { |
111 | traits_type::copy(_M_local_buf, __s._M_local_buf, |
112 | __s.length() + 1); |
113 | __s._M_data(_M_data()); |
114 | _M_data(_M_local_buf); |
115 | } |
116 | else |
117 | { |
118 | pointer __tmp_ptr = _M_data(); |
119 | _M_data(__s._M_data()); |
120 | __s._M_data(__tmp_ptr); |
121 | _M_capacity(capacity: __s._M_allocated_capacity); |
122 | } |
123 | __s._M_capacity(__tmp_capacity); |
124 | } |
125 | |
126 | const size_type __tmp_length = length(); |
127 | _M_length(length: __s.length()); |
128 | __s._M_length(__tmp_length); |
129 | } |
130 | |
131 | template<typename _CharT, typename _Traits, typename _Alloc> |
132 | _GLIBCXX20_CONSTEXPR |
133 | typename basic_string<_CharT, _Traits, _Alloc>::pointer |
134 | basic_string<_CharT, _Traits, _Alloc>:: |
135 | _M_create(size_type& __capacity, size_type __old_capacity) |
136 | { |
137 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
138 | // 83. String::npos vs. string::max_size() |
139 | if (__capacity > max_size()) |
140 | std::__throw_length_error(__N("basic_string::_M_create" )); |
141 | |
142 | // The below implements an exponential growth policy, necessary to |
143 | // meet amortized linear time requirements of the library: see |
144 | // http://gcc.gnu.org/ml/libstdc++/2001-07/msg00085.html. |
145 | if (__capacity > __old_capacity && __capacity < 2 * __old_capacity) |
146 | { |
147 | __capacity = 2 * __old_capacity; |
148 | // Never allocate a string bigger than max_size. |
149 | if (__capacity > max_size()) |
150 | __capacity = max_size(); |
151 | } |
152 | |
153 | // NB: Need an array of char_type[__capacity], plus a terminating |
154 | // null char_type() element. |
155 | return _Alloc_traits::allocate(_M_get_allocator(), __capacity + 1); |
156 | } |
157 | |
158 | // NB: This is the special case for Input Iterators, used in |
159 | // istreambuf_iterators, etc. |
160 | // Input Iterators have a cost structure very different from |
161 | // pointers, calling for a different coding style. |
162 | template<typename _CharT, typename _Traits, typename _Alloc> |
163 | template<typename _InIterator> |
164 | _GLIBCXX20_CONSTEXPR |
165 | void |
166 | basic_string<_CharT, _Traits, _Alloc>:: |
167 | _M_construct(_InIterator __beg, _InIterator __end, |
168 | std::input_iterator_tag) |
169 | { |
170 | size_type __len = 0; |
171 | size_type __capacity = size_type(_S_local_capacity); |
172 | |
173 | pointer __p = _M_use_local_data(); |
174 | |
175 | while (__beg != __end && __len < __capacity) |
176 | { |
177 | __p[__len++] = *__beg; |
178 | ++__beg; |
179 | } |
180 | |
181 | struct _Guard |
182 | { |
183 | _GLIBCXX20_CONSTEXPR |
184 | explicit _Guard(basic_string* __s) : _M_guarded(__s) { } |
185 | |
186 | _GLIBCXX20_CONSTEXPR |
187 | ~_Guard() { if (_M_guarded) _M_guarded->_M_dispose(); } |
188 | |
189 | basic_string* _M_guarded; |
190 | } __guard(this); |
191 | |
192 | while (__beg != __end) |
193 | { |
194 | if (__len == __capacity) |
195 | { |
196 | // Allocate more space. |
197 | __capacity = __len + 1; |
198 | pointer __another = _M_create(__capacity, old_capacity: __len); |
199 | this->_S_copy(__another, _M_data(), __len); |
200 | _M_dispose(); |
201 | _M_data(__another); |
202 | _M_capacity(__capacity); |
203 | } |
204 | traits_type::assign(_M_data()[__len++], *__beg); |
205 | ++__beg; |
206 | } |
207 | |
208 | __guard._M_guarded = 0; |
209 | |
210 | _M_set_length(n: __len); |
211 | } |
212 | |
213 | template<typename _CharT, typename _Traits, typename _Alloc> |
214 | template<typename _InIterator> |
215 | _GLIBCXX20_CONSTEXPR |
216 | void |
217 | basic_string<_CharT, _Traits, _Alloc>:: |
218 | _M_construct(_InIterator __beg, _InIterator __end, |
219 | std::forward_iterator_tag) |
220 | { |
221 | size_type __dnew = static_cast<size_type>(std::distance(__beg, __end)); |
222 | |
223 | if (__dnew > size_type(_S_local_capacity)) |
224 | { |
225 | _M_data(_M_create(capacity&: __dnew, old_capacity: size_type(0))); |
226 | _M_capacity(capacity: __dnew); |
227 | } |
228 | else |
229 | _M_use_local_data(); |
230 | |
231 | // Check for out_of_range and length_error exceptions. |
232 | struct _Guard |
233 | { |
234 | _GLIBCXX20_CONSTEXPR |
235 | explicit _Guard(basic_string* __s) : _M_guarded(__s) { } |
236 | |
237 | _GLIBCXX20_CONSTEXPR |
238 | ~_Guard() { if (_M_guarded) _M_guarded->_M_dispose(); } |
239 | |
240 | basic_string* _M_guarded; |
241 | } __guard(this); |
242 | |
243 | this->_S_copy_chars(_M_data(), __beg, __end); |
244 | |
245 | __guard._M_guarded = 0; |
246 | |
247 | _M_set_length(n: __dnew); |
248 | } |
249 | |
250 | template<typename _CharT, typename _Traits, typename _Alloc> |
251 | _GLIBCXX20_CONSTEXPR |
252 | void |
253 | basic_string<_CharT, _Traits, _Alloc>:: |
254 | _M_construct(size_type __n, _CharT __c) |
255 | { |
256 | if (__n > size_type(_S_local_capacity)) |
257 | { |
258 | _M_data(_M_create(capacity&: __n, old_capacity: size_type(0))); |
259 | _M_capacity(capacity: __n); |
260 | } |
261 | else |
262 | _M_use_local_data(); |
263 | |
264 | if (__n) |
265 | this->_S_assign(_M_data(), __n, __c); |
266 | |
267 | _M_set_length(__n); |
268 | } |
269 | |
270 | template<typename _CharT, typename _Traits, typename _Alloc> |
271 | _GLIBCXX20_CONSTEXPR |
272 | void |
273 | basic_string<_CharT, _Traits, _Alloc>:: |
274 | _M_assign(const basic_string& __str) |
275 | { |
276 | if (this != std::__addressof(__str)) |
277 | { |
278 | const size_type __rsize = __str.length(); |
279 | const size_type __capacity = capacity(); |
280 | |
281 | if (__rsize > __capacity) |
282 | { |
283 | size_type __new_capacity = __rsize; |
284 | pointer __tmp = _M_create(capacity&: __new_capacity, old_capacity: __capacity); |
285 | _M_dispose(); |
286 | _M_data(__tmp); |
287 | _M_capacity(capacity: __new_capacity); |
288 | } |
289 | |
290 | if (__rsize) |
291 | this->_S_copy(_M_data(), __str._M_data(), __rsize); |
292 | |
293 | _M_set_length(n: __rsize); |
294 | } |
295 | } |
296 | |
297 | template<typename _CharT, typename _Traits, typename _Alloc> |
298 | _GLIBCXX20_CONSTEXPR |
299 | void |
300 | basic_string<_CharT, _Traits, _Alloc>:: |
301 | reserve(size_type __res) |
302 | { |
303 | const size_type __capacity = capacity(); |
304 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
305 | // 2968. Inconsistencies between basic_string reserve and |
306 | // vector/unordered_map/unordered_set reserve functions |
307 | // P0966 reserve should not shrink |
308 | if (__res <= __capacity) |
309 | return; |
310 | |
311 | pointer __tmp = _M_create(capacity&: __res, old_capacity: __capacity); |
312 | this->_S_copy(__tmp, _M_data(), length() + 1); |
313 | _M_dispose(); |
314 | _M_data(__tmp); |
315 | _M_capacity(capacity: __res); |
316 | } |
317 | |
318 | template<typename _CharT, typename _Traits, typename _Alloc> |
319 | _GLIBCXX20_CONSTEXPR |
320 | void |
321 | basic_string<_CharT, _Traits, _Alloc>:: |
322 | _M_mutate(size_type __pos, size_type __len1, const _CharT* __s, |
323 | size_type __len2) |
324 | { |
325 | const size_type __how_much = length() - __pos - __len1; |
326 | |
327 | size_type __new_capacity = length() + __len2 - __len1; |
328 | pointer __r = _M_create(capacity&: __new_capacity, old_capacity: capacity()); |
329 | |
330 | if (__pos) |
331 | this->_S_copy(__r, _M_data(), __pos); |
332 | if (__s && __len2) |
333 | this->_S_copy(__r + __pos, __s, __len2); |
334 | if (__how_much) |
335 | this->_S_copy(__r + __pos + __len2, |
336 | _M_data() + __pos + __len1, __how_much); |
337 | |
338 | _M_dispose(); |
339 | _M_data(__r); |
340 | _M_capacity(capacity: __new_capacity); |
341 | } |
342 | |
343 | template<typename _CharT, typename _Traits, typename _Alloc> |
344 | _GLIBCXX20_CONSTEXPR |
345 | void |
346 | basic_string<_CharT, _Traits, _Alloc>:: |
347 | _M_erase(size_type __pos, size_type __n) |
348 | { |
349 | const size_type __how_much = length() - __pos - __n; |
350 | |
351 | if (__how_much && __n) |
352 | this->_S_move(_M_data() + __pos, _M_data() + __pos + __n, __how_much); |
353 | |
354 | _M_set_length(n: length() - __n); |
355 | } |
356 | |
357 | template<typename _CharT, typename _Traits, typename _Alloc> |
358 | _GLIBCXX20_CONSTEXPR |
359 | void |
360 | basic_string<_CharT, _Traits, _Alloc>:: |
361 | reserve() |
362 | { |
363 | if (_M_is_local()) |
364 | return; |
365 | |
366 | const size_type __length = length(); |
367 | const size_type __capacity = _M_allocated_capacity; |
368 | |
369 | if (__length <= size_type(_S_local_capacity)) |
370 | { |
371 | this->_S_copy(_M_use_local_data(), _M_data(), __length + 1); |
372 | _M_destroy(size: __capacity); |
373 | _M_data(_M_local_data()); |
374 | } |
375 | #if __cpp_exceptions |
376 | else if (__length < __capacity) |
377 | try |
378 | { |
379 | pointer __tmp |
380 | = _Alloc_traits::allocate(_M_get_allocator(), __length + 1); |
381 | this->_S_copy(__tmp, _M_data(), __length + 1); |
382 | _M_dispose(); |
383 | _M_data(__tmp); |
384 | _M_capacity(capacity: __length); |
385 | } |
386 | catch (const __cxxabiv1::__forced_unwind&) |
387 | { throw; } |
388 | catch (...) |
389 | { /* swallow the exception */ } |
390 | #endif |
391 | } |
392 | |
393 | template<typename _CharT, typename _Traits, typename _Alloc> |
394 | _GLIBCXX20_CONSTEXPR |
395 | void |
396 | basic_string<_CharT, _Traits, _Alloc>:: |
397 | resize(size_type __n, _CharT __c) |
398 | { |
399 | const size_type __size = this->size(); |
400 | if (__size < __n) |
401 | this->append(__n - __size, __c); |
402 | else if (__n < __size) |
403 | this->_M_set_length(__n); |
404 | } |
405 | |
406 | template<typename _CharT, typename _Traits, typename _Alloc> |
407 | _GLIBCXX20_CONSTEXPR |
408 | basic_string<_CharT, _Traits, _Alloc>& |
409 | basic_string<_CharT, _Traits, _Alloc>:: |
410 | _M_append(const _CharT* __s, size_type __n) |
411 | { |
412 | const size_type __len = __n + this->size(); |
413 | |
414 | if (__len <= this->capacity()) |
415 | { |
416 | if (__n) |
417 | this->_S_copy(this->_M_data() + this->size(), __s, __n); |
418 | } |
419 | else |
420 | this->_M_mutate(this->size(), size_type(0), __s, __n); |
421 | |
422 | this->_M_set_length(__len); |
423 | return *this; |
424 | } |
425 | |
426 | template<typename _CharT, typename _Traits, typename _Alloc> |
427 | template<typename _InputIterator> |
428 | _GLIBCXX20_CONSTEXPR |
429 | basic_string<_CharT, _Traits, _Alloc>& |
430 | basic_string<_CharT, _Traits, _Alloc>:: |
431 | _M_replace_dispatch(const_iterator __i1, const_iterator __i2, |
432 | _InputIterator __k1, _InputIterator __k2, |
433 | std::__false_type) |
434 | { |
435 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
436 | // 2788. unintentionally require a default constructible allocator |
437 | const basic_string __s(__k1, __k2, this->get_allocator()); |
438 | const size_type __n1 = __i2 - __i1; |
439 | return _M_replace(pos: __i1 - begin(), len1: __n1, s: __s._M_data(), |
440 | len2: __s.size()); |
441 | } |
442 | |
443 | template<typename _CharT, typename _Traits, typename _Alloc> |
444 | _GLIBCXX20_CONSTEXPR |
445 | basic_string<_CharT, _Traits, _Alloc>& |
446 | basic_string<_CharT, _Traits, _Alloc>:: |
447 | _M_replace_aux(size_type __pos1, size_type __n1, size_type __n2, |
448 | _CharT __c) |
449 | { |
450 | _M_check_length(__n1, __n2, s: "basic_string::_M_replace_aux" ); |
451 | |
452 | const size_type __old_size = this->size(); |
453 | const size_type __new_size = __old_size + __n2 - __n1; |
454 | |
455 | if (__new_size <= this->capacity()) |
456 | { |
457 | pointer __p = this->_M_data() + __pos1; |
458 | |
459 | const size_type __how_much = __old_size - __pos1 - __n1; |
460 | if (__how_much && __n1 != __n2) |
461 | this->_S_move(__p + __n2, __p + __n1, __how_much); |
462 | } |
463 | else |
464 | this->_M_mutate(__pos1, __n1, 0, __n2); |
465 | |
466 | if (__n2) |
467 | this->_S_assign(this->_M_data() + __pos1, __n2, __c); |
468 | |
469 | this->_M_set_length(__new_size); |
470 | return *this; |
471 | } |
472 | |
473 | template<typename _CharT, typename _Traits, typename _Alloc> |
474 | _GLIBCXX20_CONSTEXPR |
475 | basic_string<_CharT, _Traits, _Alloc>& |
476 | basic_string<_CharT, _Traits, _Alloc>:: |
477 | _M_replace(size_type __pos, size_type __len1, const _CharT* __s, |
478 | const size_type __len2) |
479 | { |
480 | _M_check_length(n1: __len1, n2: __len2, s: "basic_string::_M_replace" ); |
481 | |
482 | const size_type __old_size = this->size(); |
483 | const size_type __new_size = __old_size + __len2 - __len1; |
484 | |
485 | if (__new_size <= this->capacity()) |
486 | { |
487 | pointer __p = this->_M_data() + __pos; |
488 | |
489 | const size_type __how_much = __old_size - __pos - __len1; |
490 | #if __cpp_lib_is_constant_evaluated |
491 | if (std::is_constant_evaluated()) |
492 | { |
493 | auto __newp = _Alloc_traits::allocate(_M_get_allocator(), |
494 | __new_size); |
495 | _S_copy(__newp, this->_M_data(), __pos); |
496 | _S_copy(__newp + __pos, __s, __len2); |
497 | _S_copy(__newp + __pos + __len2, __p + __len1, __how_much); |
498 | _S_copy(this->_M_data(), __newp, __new_size); |
499 | this->_M_get_allocator().deallocate(__newp, __new_size); |
500 | } |
501 | else |
502 | #endif |
503 | if (_M_disjunct(__s)) |
504 | { |
505 | if (__how_much && __len1 != __len2) |
506 | this->_S_move(__p + __len2, __p + __len1, __how_much); |
507 | if (__len2) |
508 | this->_S_copy(__p, __s, __len2); |
509 | } |
510 | else |
511 | { |
512 | // Work in-place. |
513 | if (__len2 && __len2 <= __len1) |
514 | this->_S_move(__p, __s, __len2); |
515 | if (__how_much && __len1 != __len2) |
516 | this->_S_move(__p + __len2, __p + __len1, __how_much); |
517 | if (__len2 > __len1) |
518 | { |
519 | if (__s + __len2 <= __p + __len1) |
520 | this->_S_move(__p, __s, __len2); |
521 | else if (__s >= __p + __len1) |
522 | { |
523 | // Hint to middle end that __p and __s overlap |
524 | // (PR 98465). |
525 | const size_type __poff = (__s - __p) + (__len2 - __len1); |
526 | this->_S_copy(__p, __p + __poff, __len2); |
527 | } |
528 | else |
529 | { |
530 | const size_type __nleft = (__p + __len1) - __s; |
531 | this->_S_move(__p, __s, __nleft); |
532 | this->_S_copy(__p + __nleft, __p + __len2, |
533 | __len2 - __nleft); |
534 | } |
535 | } |
536 | } |
537 | } |
538 | else |
539 | this->_M_mutate(__pos, __len1, __s, __len2); |
540 | |
541 | this->_M_set_length(__new_size); |
542 | return *this; |
543 | } |
544 | |
545 | template<typename _CharT, typename _Traits, typename _Alloc> |
546 | _GLIBCXX20_CONSTEXPR |
547 | typename basic_string<_CharT, _Traits, _Alloc>::size_type |
548 | basic_string<_CharT, _Traits, _Alloc>:: |
549 | copy(_CharT* __s, size_type __n, size_type __pos) const |
550 | { |
551 | _M_check(__pos, s: "basic_string::copy" ); |
552 | __n = _M_limit(__pos, off: __n); |
553 | __glibcxx_requires_string_len(__s, __n); |
554 | if (__n) |
555 | _S_copy(d: __s, s: _M_data() + __pos, __n); |
556 | // 21.3.5.7 par 3: do not append null. (good.) |
557 | return __n; |
558 | } |
559 | |
560 | #if __cplusplus > 202002L |
561 | template<typename _CharT, typename _Traits, typename _Alloc> |
562 | template<typename _Operation> |
563 | constexpr void |
564 | basic_string<_CharT, _Traits, _Alloc>:: |
565 | resize_and_overwrite(size_type __n, _Operation __op) |
566 | { |
567 | const size_type __capacity = capacity(); |
568 | _CharT* __p; |
569 | if (__n > __capacity) |
570 | { |
571 | __p = _M_create(__n, __capacity); |
572 | this->_S_copy(__p, _M_data(), length()); // exclude trailing null |
573 | #if __cpp_lib_is_constant_evaluated |
574 | if (std::is_constant_evaluated()) |
575 | traits_type::assign(__p + length(), __n - length(), _CharT()); |
576 | #endif |
577 | _M_dispose(); |
578 | _M_data(__p); |
579 | _M_capacity(__n); |
580 | } |
581 | else |
582 | __p = _M_data(); |
583 | struct _Terminator { |
584 | constexpr ~_Terminator() { _M_this->_M_set_length(_M_r); } |
585 | basic_string* _M_this; |
586 | size_type _M_r; |
587 | }; |
588 | _Terminator __term{this}; |
589 | const size_type __n2 [[maybe_unused]] = __n; |
590 | __term._M_r = std::move(__op)(__p, __n); |
591 | _GLIBCXX_DEBUG_ASSERT(__term._M_r >= 0 && __term._M_r <= __n2); |
592 | } |
593 | #endif // C++23 |
594 | |
595 | #endif // _GLIBCXX_USE_CXX11_ABI |
596 | |
597 | #if __cpp_lib_constexpr_string >= 201907L |
598 | # define _GLIBCXX_STRING_CONSTEXPR constexpr |
599 | #else |
600 | # define _GLIBCXX_STRING_CONSTEXPR |
601 | #endif |
602 | |
603 | template<typename _CharT, typename _Traits, typename _Alloc> |
604 | _GLIBCXX20_CONSTEXPR |
605 | basic_string<_CharT, _Traits, _Alloc> |
606 | operator+(const _CharT* __lhs, |
607 | const basic_string<_CharT, _Traits, _Alloc>& __rhs) |
608 | { |
609 | __glibcxx_requires_string(__lhs); |
610 | typedef basic_string<_CharT, _Traits, _Alloc> __string_type; |
611 | typedef typename __string_type::size_type __size_type; |
612 | typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template |
613 | rebind<_CharT>::other _Char_alloc_type; |
614 | typedef __gnu_cxx::__alloc_traits<_Char_alloc_type> _Alloc_traits; |
615 | const __size_type __len = _Traits::length(__lhs); |
616 | __string_type __str(_Alloc_traits::_S_select_on_copy( |
617 | __rhs.get_allocator())); |
618 | __str.reserve(__len + __rhs.size()); |
619 | __str.append(__lhs, __len); |
620 | __str.append(__rhs); |
621 | return __str; |
622 | } |
623 | |
624 | template<typename _CharT, typename _Traits, typename _Alloc> |
625 | _GLIBCXX20_CONSTEXPR |
626 | basic_string<_CharT, _Traits, _Alloc> |
627 | operator+(_CharT __lhs, const basic_string<_CharT, _Traits, _Alloc>& __rhs) |
628 | { |
629 | typedef basic_string<_CharT, _Traits, _Alloc> __string_type; |
630 | typedef typename __string_type::size_type __size_type; |
631 | typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template |
632 | rebind<_CharT>::other _Char_alloc_type; |
633 | typedef __gnu_cxx::__alloc_traits<_Char_alloc_type> _Alloc_traits; |
634 | __string_type __str(_Alloc_traits::_S_select_on_copy( |
635 | __rhs.get_allocator())); |
636 | const __size_type __len = __rhs.size(); |
637 | __str.reserve(__len + 1); |
638 | __str.append(__size_type(1), __lhs); |
639 | __str.append(__rhs); |
640 | return __str; |
641 | } |
642 | |
643 | template<typename _CharT, typename _Traits, typename _Alloc> |
644 | _GLIBCXX_STRING_CONSTEXPR |
645 | typename basic_string<_CharT, _Traits, _Alloc>::size_type |
646 | basic_string<_CharT, _Traits, _Alloc>:: |
647 | find(const _CharT* __s, size_type __pos, size_type __n) const |
648 | _GLIBCXX_NOEXCEPT |
649 | { |
650 | __glibcxx_requires_string_len(__s, __n); |
651 | const size_type __size = this->size(); |
652 | |
653 | if (__n == 0) |
654 | return __pos <= __size ? __pos : npos; |
655 | if (__pos >= __size) |
656 | return npos; |
657 | |
658 | const _CharT __elem0 = __s[0]; |
659 | const _CharT* const __data = data(); |
660 | const _CharT* __first = __data + __pos; |
661 | const _CharT* const __last = __data + __size; |
662 | size_type __len = __size - __pos; |
663 | |
664 | while (__len >= __n) |
665 | { |
666 | // Find the first occurrence of __elem0: |
667 | __first = traits_type::find(__first, __len - __n + 1, __elem0); |
668 | if (!__first) |
669 | return npos; |
670 | // Compare the full strings from the first occurrence of __elem0. |
671 | // We already know that __first[0] == __s[0] but compare them again |
672 | // anyway because __s is probably aligned, which helps memcmp. |
673 | if (traits_type::compare(__first, __s, __n) == 0) |
674 | return __first - __data; |
675 | __len = __last - ++__first; |
676 | } |
677 | return npos; |
678 | } |
679 | |
680 | template<typename _CharT, typename _Traits, typename _Alloc> |
681 | _GLIBCXX_STRING_CONSTEXPR |
682 | typename basic_string<_CharT, _Traits, _Alloc>::size_type |
683 | basic_string<_CharT, _Traits, _Alloc>:: |
684 | find(_CharT __c, size_type __pos) const _GLIBCXX_NOEXCEPT |
685 | { |
686 | size_type __ret = npos; |
687 | const size_type __size = this->size(); |
688 | if (__pos < __size) |
689 | { |
690 | const _CharT* __data = _M_data(); |
691 | const size_type __n = __size - __pos; |
692 | const _CharT* __p = traits_type::find(__data + __pos, __n, __c); |
693 | if (__p) |
694 | __ret = __p - __data; |
695 | } |
696 | return __ret; |
697 | } |
698 | |
699 | template<typename _CharT, typename _Traits, typename _Alloc> |
700 | _GLIBCXX_STRING_CONSTEXPR |
701 | typename basic_string<_CharT, _Traits, _Alloc>::size_type |
702 | basic_string<_CharT, _Traits, _Alloc>:: |
703 | rfind(const _CharT* __s, size_type __pos, size_type __n) const |
704 | _GLIBCXX_NOEXCEPT |
705 | { |
706 | __glibcxx_requires_string_len(__s, __n); |
707 | const size_type __size = this->size(); |
708 | if (__n <= __size) |
709 | { |
710 | __pos = std::min(size_type(__size - __n), __pos); |
711 | const _CharT* __data = _M_data(); |
712 | do |
713 | { |
714 | if (traits_type::compare(__data + __pos, __s, __n) == 0) |
715 | return __pos; |
716 | } |
717 | while (__pos-- > 0); |
718 | } |
719 | return npos; |
720 | } |
721 | |
722 | template<typename _CharT, typename _Traits, typename _Alloc> |
723 | _GLIBCXX_STRING_CONSTEXPR |
724 | typename basic_string<_CharT, _Traits, _Alloc>::size_type |
725 | basic_string<_CharT, _Traits, _Alloc>:: |
726 | rfind(_CharT __c, size_type __pos) const _GLIBCXX_NOEXCEPT |
727 | { |
728 | size_type __size = this->size(); |
729 | if (__size) |
730 | { |
731 | if (--__size > __pos) |
732 | __size = __pos; |
733 | for (++__size; __size-- > 0; ) |
734 | if (traits_type::eq(_M_data()[__size], __c)) |
735 | return __size; |
736 | } |
737 | return npos; |
738 | } |
739 | |
740 | template<typename _CharT, typename _Traits, typename _Alloc> |
741 | _GLIBCXX_STRING_CONSTEXPR |
742 | typename basic_string<_CharT, _Traits, _Alloc>::size_type |
743 | basic_string<_CharT, _Traits, _Alloc>:: |
744 | find_first_of(const _CharT* __s, size_type __pos, size_type __n) const |
745 | _GLIBCXX_NOEXCEPT |
746 | { |
747 | __glibcxx_requires_string_len(__s, __n); |
748 | for (; __n && __pos < this->size(); ++__pos) |
749 | { |
750 | const _CharT* __p = traits_type::find(__s, __n, _M_data()[__pos]); |
751 | if (__p) |
752 | return __pos; |
753 | } |
754 | return npos; |
755 | } |
756 | |
757 | template<typename _CharT, typename _Traits, typename _Alloc> |
758 | _GLIBCXX_STRING_CONSTEXPR |
759 | typename basic_string<_CharT, _Traits, _Alloc>::size_type |
760 | basic_string<_CharT, _Traits, _Alloc>:: |
761 | find_last_of(const _CharT* __s, size_type __pos, size_type __n) const |
762 | _GLIBCXX_NOEXCEPT |
763 | { |
764 | __glibcxx_requires_string_len(__s, __n); |
765 | size_type __size = this->size(); |
766 | if (__size && __n) |
767 | { |
768 | if (--__size > __pos) |
769 | __size = __pos; |
770 | do |
771 | { |
772 | if (traits_type::find(__s, __n, _M_data()[__size])) |
773 | return __size; |
774 | } |
775 | while (__size-- != 0); |
776 | } |
777 | return npos; |
778 | } |
779 | |
780 | template<typename _CharT, typename _Traits, typename _Alloc> |
781 | _GLIBCXX_STRING_CONSTEXPR |
782 | typename basic_string<_CharT, _Traits, _Alloc>::size_type |
783 | basic_string<_CharT, _Traits, _Alloc>:: |
784 | find_first_not_of(const _CharT* __s, size_type __pos, size_type __n) const |
785 | _GLIBCXX_NOEXCEPT |
786 | { |
787 | __glibcxx_requires_string_len(__s, __n); |
788 | for (; __pos < this->size(); ++__pos) |
789 | if (!traits_type::find(__s, __n, _M_data()[__pos])) |
790 | return __pos; |
791 | return npos; |
792 | } |
793 | |
794 | template<typename _CharT, typename _Traits, typename _Alloc> |
795 | _GLIBCXX_STRING_CONSTEXPR |
796 | typename basic_string<_CharT, _Traits, _Alloc>::size_type |
797 | basic_string<_CharT, _Traits, _Alloc>:: |
798 | find_first_not_of(_CharT __c, size_type __pos) const _GLIBCXX_NOEXCEPT |
799 | { |
800 | for (; __pos < this->size(); ++__pos) |
801 | if (!traits_type::eq(_M_data()[__pos], __c)) |
802 | return __pos; |
803 | return npos; |
804 | } |
805 | |
806 | template<typename _CharT, typename _Traits, typename _Alloc> |
807 | _GLIBCXX_STRING_CONSTEXPR |
808 | typename basic_string<_CharT, _Traits, _Alloc>::size_type |
809 | basic_string<_CharT, _Traits, _Alloc>:: |
810 | find_last_not_of(const _CharT* __s, size_type __pos, size_type __n) const |
811 | _GLIBCXX_NOEXCEPT |
812 | { |
813 | __glibcxx_requires_string_len(__s, __n); |
814 | size_type __size = this->size(); |
815 | if (__size) |
816 | { |
817 | if (--__size > __pos) |
818 | __size = __pos; |
819 | do |
820 | { |
821 | if (!traits_type::find(__s, __n, _M_data()[__size])) |
822 | return __size; |
823 | } |
824 | while (__size--); |
825 | } |
826 | return npos; |
827 | } |
828 | |
829 | template<typename _CharT, typename _Traits, typename _Alloc> |
830 | _GLIBCXX_STRING_CONSTEXPR |
831 | typename basic_string<_CharT, _Traits, _Alloc>::size_type |
832 | basic_string<_CharT, _Traits, _Alloc>:: |
833 | find_last_not_of(_CharT __c, size_type __pos) const _GLIBCXX_NOEXCEPT |
834 | { |
835 | size_type __size = this->size(); |
836 | if (__size) |
837 | { |
838 | if (--__size > __pos) |
839 | __size = __pos; |
840 | do |
841 | { |
842 | if (!traits_type::eq(_M_data()[__size], __c)) |
843 | return __size; |
844 | } |
845 | while (__size--); |
846 | } |
847 | return npos; |
848 | } |
849 | |
850 | template<typename _CharT, typename _Traits, typename _Alloc> |
851 | _GLIBCXX_STRING_CONSTEXPR |
852 | int |
853 | basic_string<_CharT, _Traits, _Alloc>:: |
854 | compare(size_type __pos, size_type __n, const basic_string& __str) const |
855 | { |
856 | _M_check(__pos, s: "basic_string::compare" ); |
857 | __n = _M_limit(__pos, off: __n); |
858 | const size_type __osize = __str.size(); |
859 | const size_type __len = std::min(__n, __osize); |
860 | int __r = traits_type::compare(_M_data() + __pos, __str.data(), __len); |
861 | if (!__r) |
862 | __r = _S_compare(n1: __n, n2: __osize); |
863 | return __r; |
864 | } |
865 | |
866 | template<typename _CharT, typename _Traits, typename _Alloc> |
867 | _GLIBCXX_STRING_CONSTEXPR |
868 | int |
869 | basic_string<_CharT, _Traits, _Alloc>:: |
870 | compare(size_type __pos1, size_type __n1, const basic_string& __str, |
871 | size_type __pos2, size_type __n2) const |
872 | { |
873 | _M_check(pos: __pos1, s: "basic_string::compare" ); |
874 | __str._M_check(__pos2, "basic_string::compare" ); |
875 | __n1 = _M_limit(pos: __pos1, off: __n1); |
876 | __n2 = __str._M_limit(__pos2, __n2); |
877 | const size_type __len = std::min(__n1, __n2); |
878 | int __r = traits_type::compare(_M_data() + __pos1, |
879 | __str.data() + __pos2, __len); |
880 | if (!__r) |
881 | __r = _S_compare(__n1, __n2); |
882 | return __r; |
883 | } |
884 | |
885 | template<typename _CharT, typename _Traits, typename _Alloc> |
886 | _GLIBCXX_STRING_CONSTEXPR |
887 | int |
888 | basic_string<_CharT, _Traits, _Alloc>:: |
889 | compare(const _CharT* __s) const _GLIBCXX_NOEXCEPT |
890 | { |
891 | __glibcxx_requires_string(__s); |
892 | const size_type __size = this->size(); |
893 | const size_type __osize = traits_type::length(__s); |
894 | const size_type __len = std::min(__size, __osize); |
895 | int __r = traits_type::compare(_M_data(), __s, __len); |
896 | if (!__r) |
897 | __r = _S_compare(n1: __size, n2: __osize); |
898 | return __r; |
899 | } |
900 | |
901 | template<typename _CharT, typename _Traits, typename _Alloc> |
902 | _GLIBCXX_STRING_CONSTEXPR |
903 | int |
904 | basic_string <_CharT, _Traits, _Alloc>:: |
905 | compare(size_type __pos, size_type __n1, const _CharT* __s) const |
906 | { |
907 | __glibcxx_requires_string(__s); |
908 | _M_check(__pos, s: "basic_string::compare" ); |
909 | __n1 = _M_limit(__pos, off: __n1); |
910 | const size_type __osize = traits_type::length(__s); |
911 | const size_type __len = std::min(__n1, __osize); |
912 | int __r = traits_type::compare(_M_data() + __pos, __s, __len); |
913 | if (!__r) |
914 | __r = _S_compare(__n1, n2: __osize); |
915 | return __r; |
916 | } |
917 | |
918 | template<typename _CharT, typename _Traits, typename _Alloc> |
919 | _GLIBCXX_STRING_CONSTEXPR |
920 | int |
921 | basic_string <_CharT, _Traits, _Alloc>:: |
922 | compare(size_type __pos, size_type __n1, const _CharT* __s, |
923 | size_type __n2) const |
924 | { |
925 | __glibcxx_requires_string_len(__s, __n2); |
926 | _M_check(__pos, s: "basic_string::compare" ); |
927 | __n1 = _M_limit(__pos, off: __n1); |
928 | const size_type __len = std::min(__n1, __n2); |
929 | int __r = traits_type::compare(_M_data() + __pos, __s, __len); |
930 | if (!__r) |
931 | __r = _S_compare(__n1, __n2); |
932 | return __r; |
933 | } |
934 | |
935 | #undef _GLIBCXX_STRING_CONSTEXPR |
936 | |
937 | // 21.3.7.9 basic_string::getline and operators |
938 | template<typename _CharT, typename _Traits, typename _Alloc> |
939 | basic_istream<_CharT, _Traits>& |
940 | operator>>(basic_istream<_CharT, _Traits>& __in, |
941 | basic_string<_CharT, _Traits, _Alloc>& __str) |
942 | { |
943 | typedef basic_istream<_CharT, _Traits> __istream_type; |
944 | typedef basic_string<_CharT, _Traits, _Alloc> __string_type; |
945 | typedef typename __istream_type::ios_base __ios_base; |
946 | typedef typename __istream_type::int_type __int_type; |
947 | typedef typename __string_type::size_type __size_type; |
948 | typedef ctype<_CharT> __ctype_type; |
949 | typedef typename __ctype_type::ctype_base __ctype_base; |
950 | |
951 | __size_type = 0; |
952 | typename __ios_base::iostate __err = __ios_base::goodbit; |
953 | typename __istream_type::sentry __cerb(__in, false); |
954 | if (__cerb) |
955 | { |
956 | __try |
957 | { |
958 | // Avoid reallocation for common case. |
959 | __str.erase(); |
960 | _CharT __buf[128]; |
961 | __size_type __len = 0; |
962 | const streamsize __w = __in.width(); |
963 | const __size_type __n = __w > 0 ? static_cast<__size_type>(__w) |
964 | : __str.max_size(); |
965 | const __ctype_type& __ct = use_facet<__ctype_type>(__in.getloc()); |
966 | const __int_type __eof = _Traits::eof(); |
967 | __int_type __c = __in.rdbuf()->sgetc(); |
968 | |
969 | while (__extracted < __n |
970 | && !_Traits::eq_int_type(__c, __eof) |
971 | && !__ct.is(__ctype_base::space, |
972 | _Traits::to_char_type(__c))) |
973 | { |
974 | if (__len == sizeof(__buf) / sizeof(_CharT)) |
975 | { |
976 | __str.append(__buf, sizeof(__buf) / sizeof(_CharT)); |
977 | __len = 0; |
978 | } |
979 | __buf[__len++] = _Traits::to_char_type(__c); |
980 | ++__extracted; |
981 | __c = __in.rdbuf()->snextc(); |
982 | } |
983 | __str.append(__buf, __len); |
984 | |
985 | if (__extracted < __n && _Traits::eq_int_type(__c, __eof)) |
986 | __err |= __ios_base::eofbit; |
987 | __in.width(0); |
988 | } |
989 | __catch(__cxxabiv1::__forced_unwind&) |
990 | { |
991 | __in._M_setstate(__ios_base::badbit); |
992 | __throw_exception_again; |
993 | } |
994 | __catch(...) |
995 | { |
996 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
997 | // 91. Description of operator>> and getline() for string<> |
998 | // might cause endless loop |
999 | __in._M_setstate(__ios_base::badbit); |
1000 | } |
1001 | } |
1002 | // 211. operator>>(istream&, string&) doesn't set failbit |
1003 | if (!__extracted) |
1004 | __err |= __ios_base::failbit; |
1005 | if (__err) |
1006 | __in.setstate(__err); |
1007 | return __in; |
1008 | } |
1009 | |
1010 | template<typename _CharT, typename _Traits, typename _Alloc> |
1011 | basic_istream<_CharT, _Traits>& |
1012 | getline(basic_istream<_CharT, _Traits>& __in, |
1013 | basic_string<_CharT, _Traits, _Alloc>& __str, _CharT __delim) |
1014 | { |
1015 | typedef basic_istream<_CharT, _Traits> __istream_type; |
1016 | typedef basic_string<_CharT, _Traits, _Alloc> __string_type; |
1017 | typedef typename __istream_type::ios_base __ios_base; |
1018 | typedef typename __istream_type::int_type __int_type; |
1019 | typedef typename __string_type::size_type __size_type; |
1020 | |
1021 | __size_type = 0; |
1022 | const __size_type __n = __str.max_size(); |
1023 | typename __ios_base::iostate __err = __ios_base::goodbit; |
1024 | typename __istream_type::sentry __cerb(__in, true); |
1025 | if (__cerb) |
1026 | { |
1027 | __try |
1028 | { |
1029 | __str.erase(); |
1030 | const __int_type __idelim = _Traits::to_int_type(__delim); |
1031 | const __int_type __eof = _Traits::eof(); |
1032 | __int_type __c = __in.rdbuf()->sgetc(); |
1033 | |
1034 | while (__extracted < __n |
1035 | && !_Traits::eq_int_type(__c, __eof) |
1036 | && !_Traits::eq_int_type(__c, __idelim)) |
1037 | { |
1038 | __str += _Traits::to_char_type(__c); |
1039 | ++__extracted; |
1040 | __c = __in.rdbuf()->snextc(); |
1041 | } |
1042 | |
1043 | if (_Traits::eq_int_type(__c, __eof)) |
1044 | __err |= __ios_base::eofbit; |
1045 | else if (_Traits::eq_int_type(__c, __idelim)) |
1046 | { |
1047 | ++__extracted; |
1048 | __in.rdbuf()->sbumpc(); |
1049 | } |
1050 | else |
1051 | __err |= __ios_base::failbit; |
1052 | } |
1053 | __catch(__cxxabiv1::__forced_unwind&) |
1054 | { |
1055 | __in._M_setstate(__ios_base::badbit); |
1056 | __throw_exception_again; |
1057 | } |
1058 | __catch(...) |
1059 | { |
1060 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
1061 | // 91. Description of operator>> and getline() for string<> |
1062 | // might cause endless loop |
1063 | __in._M_setstate(__ios_base::badbit); |
1064 | } |
1065 | } |
1066 | if (!__extracted) |
1067 | __err |= __ios_base::failbit; |
1068 | if (__err) |
1069 | __in.setstate(__err); |
1070 | return __in; |
1071 | } |
1072 | |
1073 | // Inhibit implicit instantiations for required instantiations, |
1074 | // which are defined via explicit instantiations elsewhere. |
1075 | #if _GLIBCXX_EXTERN_TEMPLATE |
1076 | // The explicit instantiation definitions in src/c++11/string-inst.cc and |
1077 | // src/c++17/string-inst.cc only instantiate the members required for C++17 |
1078 | // and earlier standards (so not C++20's starts_with and ends_with). |
1079 | // Suppress the explicit instantiation declarations for C++20, so C++20 |
1080 | // code will implicitly instantiate std::string and std::wstring as needed. |
1081 | # if __cplusplus <= 201703L && _GLIBCXX_EXTERN_TEMPLATE > 0 |
1082 | extern template class basic_string<char>; |
1083 | # elif ! _GLIBCXX_USE_CXX11_ABI |
1084 | // Still need to prevent implicit instantiation of the COW empty rep, |
1085 | // to ensure the definition in libstdc++.so is unique (PR 86138). |
1086 | extern template basic_string<char>::size_type |
1087 | basic_string<char>::_Rep::_S_empty_rep_storage[]; |
1088 | # endif |
1089 | |
1090 | extern template |
1091 | basic_istream<char>& |
1092 | operator>>(basic_istream<char>&, string&); |
1093 | extern template |
1094 | basic_ostream<char>& |
1095 | operator<<(basic_ostream<char>&, const string&); |
1096 | extern template |
1097 | basic_istream<char>& |
1098 | getline(basic_istream<char>&, string&, char); |
1099 | extern template |
1100 | basic_istream<char>& |
1101 | getline(basic_istream<char>&, string&); |
1102 | |
1103 | #ifdef _GLIBCXX_USE_WCHAR_T |
1104 | # if __cplusplus <= 201703L && _GLIBCXX_EXTERN_TEMPLATE > 0 |
1105 | extern template class basic_string<wchar_t>; |
1106 | # elif ! _GLIBCXX_USE_CXX11_ABI |
1107 | extern template basic_string<wchar_t>::size_type |
1108 | basic_string<wchar_t>::_Rep::_S_empty_rep_storage[]; |
1109 | # endif |
1110 | |
1111 | extern template |
1112 | basic_istream<wchar_t>& |
1113 | operator>>(basic_istream<wchar_t>&, wstring&); |
1114 | extern template |
1115 | basic_ostream<wchar_t>& |
1116 | operator<<(basic_ostream<wchar_t>&, const wstring&); |
1117 | extern template |
1118 | basic_istream<wchar_t>& |
1119 | getline(basic_istream<wchar_t>&, wstring&, wchar_t); |
1120 | extern template |
1121 | basic_istream<wchar_t>& |
1122 | getline(basic_istream<wchar_t>&, wstring&); |
1123 | #endif // _GLIBCXX_USE_WCHAR_T |
1124 | #endif // _GLIBCXX_EXTERN_TEMPLATE |
1125 | |
1126 | _GLIBCXX_END_NAMESPACE_VERSION |
1127 | } // namespace std |
1128 | |
1129 | #endif |
1130 | |