Pigweed
C/C++ API Reference
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Loading...
Searching...
No Matches
string.h
Go to the documentation of this file.
1// Copyright 2022 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#pragma once
15
20
21#include <cstddef>
22#include <initializer_list>
23#include <iterator>
24#include <type_traits>
25
26#include "pw_assert/assert.h"
27#include "pw_containers/internal/traits.h"
28#include "pw_containers/ptr_iterator.h"
29#include "pw_preprocessor/compiler.h"
30#include "pw_string/internal/string_impl.h"
31
32// Messages to use in static_assert statements.
33#define _PW_STRING_CAPACITY_TOO_SMALL_FOR_ARRAY \
34 "The pw::InlineString's capacity is too small to hold the assigned string " \
35 "literal or character array. When assigning a literal or array to a " \
36 "pw::InlineString, the pw::InlineString's capacity must be large enough " \
37 "for the entire string, not counting the null terminator."
38
39#define _PW_STRING_CAPACITY_TOO_SMALL_FOR_STRING \
40 "When assigning one pw::InlineString with known capacity to another, the " \
41 "capacity of the destination pw::InlineString must be at least as large as " \
42 "the source string."
43
44namespace pw {
45
64template <typename T, size_t kCapacity = string_impl::kGeneric>
66 : public InlineBasicString<T, string_impl::kGeneric> {
67 public:
78 using
79 typename InlineBasicString<T,
80 string_impl::kGeneric>::const_reverse_iterator;
81
82 using InlineBasicString<T, string_impl::kGeneric>::npos;
83
84 // Constructors
85
86 constexpr InlineBasicString() noexcept
87 : InlineBasicString<T, string_impl::kGeneric>(kCapacity), buffer_() {}
88
89 constexpr InlineBasicString(size_t count, T ch) : InlineBasicString() {
90 Fill(data(), ch, count);
91 }
92
93 template <size_t kOtherCapacity>
95 size_t index,
96 size_t count = npos)
98 CopySubstr(data(), other.data(), other.size(), index, count);
99 }
100
101 constexpr InlineBasicString(const T* string, size_t count)
103 Copy(data(), string, count);
104 }
105
106 template <typename U,
107 typename = string_impl::EnableIfNonArrayCharPointer<T, U>>
108 constexpr InlineBasicString(U c_string)
110 c_string, string_impl::BoundedStringLength(c_string, kCapacity)) {}
111
112 template <size_t kCharArraySize>
113 constexpr InlineBasicString(const T (&array)[kCharArraySize])
115 static_assert(
116 string_impl::NullTerminatedArrayFitsInString(kCharArraySize, kCapacity),
117 _PW_STRING_CAPACITY_TOO_SMALL_FOR_ARRAY);
118 Copy(data(), array, string_impl::ArrayStringLength(array, max_size()));
119 }
120
121 template <typename Iterator,
122 typename = containers::internal::EnableIfInputIterator<Iterator>>
123 constexpr InlineBasicString(Iterator start, Iterator finish)
125 CopyIterator(data(), start, finish);
126 }
127
128 // Use the default copy for InlineBasicString with the same capacity.
129 constexpr InlineBasicString(const InlineBasicString&) = default;
130
131 // When copying from an InlineBasicString with a different capacity, check
132 // that the destination capacity is at least as large as the source capacity.
133 template <size_t kOtherCapacity>
135 : InlineBasicString(other.data(), other.size()) {
136 static_assert(
137 kOtherCapacity == string_impl::kGeneric || kOtherCapacity <= kCapacity,
138 _PW_STRING_CAPACITY_TOO_SMALL_FOR_STRING);
139 }
140
141 constexpr InlineBasicString(std::initializer_list<T> list)
142 : InlineBasicString(list.begin(), list.size()) {}
143
144 // Unlike std::string, pw::InlineString<> supports implicit conversions from
145 // std::string_view. However, explicit conversions are still required from
146 // types that convert to std::string_view, as with std::string.
147 //
148 // pw::InlineString<> allows implicit conversions from std::string_view
149 // because it can be cumbersome to specify the capacity parameter. In
150 // particular, this can make using aggregate initialization more difficult.
151 //
152 // This explicit constructor is enabled for an argument that converts to
153 // std::string_view, but is not a std::string_view.
154 template <
155 typename StringViewLike,
156 string_impl::EnableIfStringViewLikeButNotStringView<T, StringViewLike>* =
157 nullptr>
158 explicit constexpr InlineBasicString(const StringViewLike& string)
159 : InlineBasicString(string_impl::View<T>(string)) {}
160
161 // This converting constructor is enabled for std::string_view, but not types
162 // that convert to it.
163 template <
164 typename StringView,
165 std::enable_if_t<std::is_same<StringView, string_impl::View<T>>::value>* =
166 nullptr>
167 constexpr InlineBasicString(const StringView& view)
168 : InlineBasicString(view.data(), view.size()) {}
169
170 template <typename StringView,
171 typename = string_impl::EnableIfStringViewLike<T, StringView>>
172 constexpr InlineBasicString(const StringView& string,
173 size_t index,
174 size_t count)
176 const string_impl::View<T> view = string;
177 CopySubstr(data(), view.data(), view.size(), index, count);
178 }
179
180 InlineBasicString(std::nullptr_t) = delete; // Cannot construct from nullptr
181
182 // Assignment operators
183
184 constexpr InlineBasicString& operator=(const InlineBasicString& other) =
185 default;
186
187 // Checks capacity rather than current size.
188 template <size_t kOtherCapacity>
189 constexpr InlineBasicString& operator=(
191 return assign<kOtherCapacity>(other); // NOLINT
192 }
193
194 template <size_t kCharArraySize>
195 constexpr InlineBasicString& operator=(const T (&array)[kCharArraySize]) {
196 return assign<kCharArraySize>(array); // NOLINT
197 }
198
199 // Use SFINAE to avoid ambiguity with the array overload.
200 template <typename U,
201 typename = string_impl::EnableIfNonArrayCharPointer<T, U>>
202 constexpr InlineBasicString& operator=(U c_string) {
203 return assign(c_string); // NOLINT
204 }
205
206 constexpr InlineBasicString& operator=(T ch) {
207 static_assert(kCapacity != 0,
208 "Cannot assign a character to pw::InlineString<0>");
209 return assign(1, ch); // NOLINT
210 }
211
212 constexpr InlineBasicString& operator=(std::initializer_list<T> list) {
213 return assign(list); // NOLINT
214 }
215
216 template <typename StringView,
217 typename = string_impl::EnableIfStringViewLike<T, StringView>>
218 constexpr InlineBasicString& operator=(const StringView& string) {
219 return assign(string); // NOLINT
220 }
221
222 constexpr InlineBasicString& operator=(std::nullptr_t) = delete;
223
224 template <size_t kOtherCapacity>
225 constexpr InlineBasicString& operator+=(
227 return append(string);
228 }
229
230 constexpr InlineBasicString& operator+=(T character) {
231 push_back(character);
232 return *this;
233 }
234
235 template <size_t kCharArraySize>
236 constexpr InlineBasicString& operator+=(const T (&array)[kCharArraySize]) {
237 return append(array);
238 }
239
240 template <typename U,
241 typename = string_impl::EnableIfNonArrayCharPointer<T, U>>
242 constexpr InlineBasicString& operator+=(U c_string) {
243 return append(c_string);
244 }
245
246 constexpr InlineBasicString& operator+=(std::initializer_list<T> list) {
247 return append(list.begin(), list.size());
248 }
249
250 template <typename StringView,
251 typename = string_impl::EnableIfStringViewLike<T, StringView>>
252 constexpr InlineBasicString& operator+=(const StringView& string) {
253 return append(string);
254 }
255
256 // The data() and size() functions are defined differently for the generic and
257 // known-size specializations. This is to support using pw::InlineBasicString
258 // in constexpr statements. This data() implementation simply returns the
259 // underlying buffer. The generic-capacity data() function casts *this to
260 // InlineBasicString<T, 0>, so is only constexpr when the capacity is actually
261 // 0.
262 constexpr pointer data() { return buffer_; }
263 constexpr const_pointer data() const { return buffer_; }
264
265 // Use the size() function from the base, but define max_size() to return the
266 // kCapacity template parameter instead of reading the stored capacity value.
267 using InlineBasicString<T, string_impl::kGeneric>::size;
268 constexpr size_t max_size() const noexcept { return kCapacity; }
269
270 // Most string functions are defined in separate file so they can be shared
271 // between the known capacity and generic capacity versions of
272 // InlineBasicString.
273#include "pw_string/internal/string_common_functions.inc"
274
275 private:
276 using InlineBasicString<T, string_impl::kGeneric>::PushBack;
277 using InlineBasicString<T, string_impl::kGeneric>::PopBack;
278 using InlineBasicString<T, string_impl::kGeneric>::Copy;
279 using InlineBasicString<T, string_impl::kGeneric>::CopySubstr;
280 using InlineBasicString<T, string_impl::kGeneric>::Fill;
281 using InlineBasicString<T, string_impl::kGeneric>::CopyIterator;
282 using InlineBasicString<T, string_impl::kGeneric>::CopyExtend;
283 using InlineBasicString<T, string_impl::kGeneric>::CopyExtendSubstr;
284 using InlineBasicString<T, string_impl::kGeneric>::FillExtend;
285 using InlineBasicString<T, string_impl::kGeneric>::MoveExtend;
286 using InlineBasicString<T, string_impl::kGeneric>::CopyIteratorExtend;
287 using InlineBasicString<T, string_impl::kGeneric>::Resize;
288 using InlineBasicString<T, string_impl::kGeneric>::SetSizeAndTerminate;
289
290 // Store kCapacity + 1 bytes to reserve space for a null terminator.
291 // InlineBasicString<T, 0> only stores a null terminator.
292 T buffer_[kCapacity + 1];
293};
294
295// Generic-capacity version of pw::InlineBasicString. Generic-capacity strings
296// cannot be constructed; they can only be used as references to fixed-capacity
297// pw::InlineBasicString objects.
298template <typename T>
299class InlineBasicString<T, string_impl::kGeneric> {
300 public:
301 using value_type = T;
302 using size_type = string_impl::size_type;
303 using difference_type = std::ptrdiff_t;
304 using reference = value_type&;
305 using const_reference = const value_type&;
306 using pointer = value_type*;
307 using const_pointer = const value_type*;
308 using iterator =
310 using const_iterator =
312 using reverse_iterator = std::reverse_iterator<iterator>;
313 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
314
315 static constexpr size_t npos = string_impl::kGeneric;
316
317 InlineBasicString() = delete; // Must specify capacity to construct a string.
318
319 // For the generic-capacity pw::InlineBasicString, cast this object to a
320 // fixed-capacity class so the address of the data can be found. Even though
321 // the capacity isn't known at compile time, the location of the data never
322 // changes.
323 constexpr pointer data() noexcept {
324 return static_cast<InlineBasicString<T, 0>*>(this)->data();
325 }
326 constexpr const_pointer data() const noexcept {
327 return static_cast<const InlineBasicString<T, 0>*>(this)->data();
328 }
329
330 constexpr size_t size() const noexcept { return length_; }
331 constexpr size_t max_size() const noexcept { return capacity_; }
332
333 // Most string functions are defined in separate file so they can be shared
334 // between the known capacity and generic capacity versions of
335 // InlineBasicString.
336#include "pw_string/internal/string_common_functions.inc"
337
338 protected:
339 explicit constexpr InlineBasicString(size_t capacity)
340 : capacity_(string_impl::CheckedCastToSize(capacity)), length_(0) {}
341
342 // The generic-capacity InlineBasicString<T> is not copyable or movable, but
343 // BasicStrings can copied or assigned through a fixed capacity derived class.
344 InlineBasicString(const InlineBasicString&) = default;
345
346 InlineBasicString& operator=(const InlineBasicString&) = default;
347
348 // Allow derived fixed-length types to create iterators.
349 static constexpr iterator Iterator(T* data) { return iterator(data); }
350 static constexpr const_iterator Iterator(const T* data) {
351 return const_iterator(data);
352 }
353
354 constexpr void PushBack(T* data, T ch);
355
356 constexpr void PopBack(T* data) {
357 PW_ASSERT(!empty());
358 SetSizeAndTerminate(data, size() - 1);
359 }
360
361 constexpr InlineBasicString& Copy(T* data, const T* source, size_t new_size);
362
363 constexpr InlineBasicString& CopySubstr(
364 T* data, const T* source, size_t source_size, size_t index, size_t count);
365
366 constexpr InlineBasicString& Fill(T* data, T fill_char, size_t new_size);
367
368 template <typename InputIterator>
369 constexpr InlineBasicString& CopyIterator(T* data_start,
370 InputIterator begin,
371 InputIterator end);
372
373 constexpr InlineBasicString& CopyExtend(T* data,
374 size_t index,
375 const T* source,
376 size_t count);
377
378 constexpr InlineBasicString& CopyExtendSubstr(T* data,
379 size_t index,
380 const T* source,
381 size_t source_size,
382 size_t source_index,
383 size_t count);
384
385 constexpr InlineBasicString& FillExtend(T* data,
386 size_t index,
387 T fill_char,
388 size_t count);
389
390 template <typename InputIterator>
391 constexpr InlineBasicString& CopyIteratorExtend(T* data,
392 size_t index,
393 InputIterator begin,
394 InputIterator end);
395
396 constexpr InlineBasicString& MoveExtend(T* data,
397 size_t index,
398 size_t new_index);
399
400 constexpr void Resize(T* data, size_t new_size, T ch);
401
402 constexpr void set_size(size_t length) {
403 length_ = string_impl::CheckedCastToSize(length);
404 }
405 constexpr void SetSizeAndTerminate(T* data, size_t length) {
406 PW_ASSERT(length <= max_size());
407 string_impl::char_traits<T>::assign(data[length], T());
408 set_size(length);
409 }
410
411 private:
412 static_assert(std::is_same_v<char, T> || std::is_same_v<wchar_t, T> ||
413#ifdef __cpp_char8_t
414 std::is_same_v<char8_t, T> ||
415#endif // __cpp_char8_t
416 std::is_same_v<char16_t, T> ||
417 std::is_same_v<char32_t, T> || std::is_same_v<std::byte, T>,
418 "Only character types and std::byte are supported");
419
420 // Allow StringBuilder to directly set length_ when doing string operations.
421 friend class StringBuilder;
422
423 // Provide this constant for static_assert checks. If the capacity is unknown,
424 // use the maximum value so that compile-time capacity checks pass. If
425 // overflow occurs, the operation triggers a PW_ASSERT at runtime.
426 static constexpr size_t kCapacity = string_impl::kGeneric;
427
428 size_type capacity_;
429 size_type length_;
430};
431
432// Class template argument deduction guides
433
434#ifdef __cpp_deduction_guides
435
436// In C++17, the capacity of the string may be deduced from a string literal or
437// array. For example, the following deduces a character type of char and a
438// capacity of 4 (which does not include the null terminator).
439//
440// InlineBasicString my_string = "1234";
441//
442// In C++20, the template parameters for the pw::InlineString alias may be
443// deduced similarly:
444//
445// InlineString my_string = "abc"; // deduces capacity of 3.
446//
447template <typename T, size_t kCharArraySize>
448InlineBasicString(const T (&)[kCharArraySize])
449 -> InlineBasicString<T, kCharArraySize - 1>;
450
451#endif // __cpp_deduction_guides
452
453// Operators
454
455// TODO: b/239996007 - Implement operator+
456
457template <typename T, size_t kLhsCapacity, size_t kRhsCapacity>
458constexpr bool operator==(
460 const InlineBasicString<T, kRhsCapacity>& rhs) noexcept {
461 return lhs.compare(rhs) == 0;
462}
463
464template <typename T, size_t kLhsCapacity, size_t kRhsCapacity>
465constexpr bool operator!=(
466 const InlineBasicString<T, kLhsCapacity>& lhs,
467 const InlineBasicString<T, kRhsCapacity>& rhs) noexcept {
468 return lhs.compare(rhs) != 0;
469}
470
471template <typename T, size_t kLhsCapacity, size_t kRhsCapacity>
472constexpr bool operator<(
473 const InlineBasicString<T, kLhsCapacity>& lhs,
474 const InlineBasicString<T, kRhsCapacity>& rhs) noexcept {
475 return lhs.compare(rhs) < 0;
476}
477
478template <typename T, size_t kLhsCapacity, size_t kRhsCapacity>
479constexpr bool operator<=(
480 const InlineBasicString<T, kLhsCapacity>& lhs,
481 const InlineBasicString<T, kRhsCapacity>& rhs) noexcept {
482 return lhs.compare(rhs) <= 0;
483}
484
485template <typename T, size_t kLhsCapacity, size_t kRhsCapacity>
486constexpr bool operator>(
487 const InlineBasicString<T, kLhsCapacity>& lhs,
488 const InlineBasicString<T, kRhsCapacity>& rhs) noexcept {
489 return lhs.compare(rhs) > 0;
490}
491
492template <typename T, size_t kLhsCapacity, size_t kRhsCapacity>
493constexpr bool operator>=(
494 const InlineBasicString<T, kLhsCapacity>& lhs,
495 const InlineBasicString<T, kRhsCapacity>& rhs) noexcept {
496 return lhs.compare(rhs) >= 0;
497}
498
499template <typename T, size_t kLhsCapacity>
500constexpr bool operator==(const InlineBasicString<T, kLhsCapacity>& lhs,
501 const T* rhs) {
502 return lhs.compare(rhs) == 0;
503}
504
505template <typename T, size_t kRhsCapacity>
506constexpr bool operator==(const T* lhs,
507 const InlineBasicString<T, kRhsCapacity>& rhs) {
508 return rhs.compare(lhs) == 0;
509}
510
511template <typename T, size_t kLhsCapacity>
512constexpr bool operator!=(const InlineBasicString<T, kLhsCapacity>& lhs,
513 const T* rhs) {
514 return lhs.compare(rhs) != 0;
515}
516
517template <typename T, size_t kRhsCapacity>
518constexpr bool operator!=(const T* lhs,
519 const InlineBasicString<T, kRhsCapacity>& rhs) {
520 return rhs.compare(lhs) != 0;
521}
522
523template <typename T, size_t kLhsCapacity>
524constexpr bool operator<(const InlineBasicString<T, kLhsCapacity>& lhs,
525 const T* rhs) {
526 return lhs.compare(rhs) < 0;
527}
528
529template <typename T, size_t kRhsCapacity>
530constexpr bool operator<(const T* lhs,
531 const InlineBasicString<T, kRhsCapacity>& rhs) {
532 return rhs.compare(lhs) >= 0;
533}
534
535template <typename T, size_t kLhsCapacity>
536constexpr bool operator<=(const InlineBasicString<T, kLhsCapacity>& lhs,
537 const T* rhs) {
538 return lhs.compare(rhs) <= 0;
539}
540
541template <typename T, size_t kRhsCapacity>
542constexpr bool operator<=(const T* lhs,
543 const InlineBasicString<T, kRhsCapacity>& rhs) {
544 return rhs.compare(lhs) >= 0;
545}
546
547template <typename T, size_t kLhsCapacity>
548constexpr bool operator>(const InlineBasicString<T, kLhsCapacity>& lhs,
549 const T* rhs) {
550 return lhs.compare(rhs) > 0;
551}
552
553template <typename T, size_t kRhsCapacity>
554constexpr bool operator>(const T* lhs,
555 const InlineBasicString<T, kRhsCapacity>& rhs) {
556 return rhs.compare(lhs) <= 0;
557}
558
559template <typename T, size_t kLhsCapacity>
560constexpr bool operator>=(const InlineBasicString<T, kLhsCapacity>& lhs,
561 const T* rhs) {
562 return lhs.compare(rhs) >= 0;
563}
564
565template <typename T, size_t kRhsCapacity>
566constexpr bool operator>=(const T* lhs,
567 const InlineBasicString<T, kRhsCapacity>& rhs) {
568 return rhs.compare(lhs) <= 0;
569}
570
571// TODO: b/239996007 - Implement other comparison operator overloads.
572
573// Aliases
574
577template <size_t kCapacity = string_impl::kGeneric>
579
583template <size_t kCapacity = string_impl::kGeneric>
585
586// Function implementations
587
588template <typename T>
590 T ch) {
591 PW_ASSERT(size() < max_size());
592 string_impl::char_traits<T>::assign(data[size()], ch);
593 SetSizeAndTerminate(data, size() + 1);
594}
595
596template <typename T>
597constexpr InlineBasicString<T, string_impl::kGeneric>&
598InlineBasicString<T, string_impl::kGeneric>::Copy(T* data,
599 const T* source,
600 size_t new_size) {
601 PW_ASSERT(new_size <= max_size());
602 string_impl::char_traits<T>::copy(data, source, new_size);
603 SetSizeAndTerminate(data, new_size);
604 return *this;
605}
606
607template <typename T>
608constexpr InlineBasicString<T, string_impl::kGeneric>&
609InlineBasicString<T, string_impl::kGeneric>::CopySubstr(
610 T* data, const T* source, size_t source_size, size_t index, size_t count) {
611 PW_ASSERT(index <= source_size);
612 return Copy(data, source + index, std::min(count, source_size - index));
613}
614
615template <typename T>
616constexpr InlineBasicString<T, string_impl::kGeneric>&
617InlineBasicString<T, string_impl::kGeneric>::CopyExtend(T* data,
618 size_t index,
619 const T* source,
620 size_t count) {
621 PW_ASSERT(index <= size());
622 PW_ASSERT(count <= max_size() - index);
623 string_impl::char_traits<T>::copy(data + index, source, count);
624 SetSizeAndTerminate(data, std::max(size(), index + count));
625 return *this;
626}
627
628template <typename T>
629constexpr InlineBasicString<T, string_impl::kGeneric>&
630InlineBasicString<T, string_impl::kGeneric>::CopyExtendSubstr(
631 T* data,
632 size_t index,
633 const T* source,
634 size_t source_size,
635 size_t source_index,
636 size_t count) {
637 PW_ASSERT(source_index <= source_size);
638 return CopyExtend(data,
639 index,
640 source + source_index,
641 std::min(count, source_size - source_index));
642 return *this;
643}
644
645template <typename T>
646template <typename InputIterator>
647constexpr InlineBasicString<T, string_impl::kGeneric>&
648InlineBasicString<T, string_impl::kGeneric>::CopyIterator(T* data,
649 InputIterator begin,
650 InputIterator end) {
651 size_t length =
652 string_impl::IteratorCopy(begin, end, data, data + max_size());
653 SetSizeAndTerminate(data, length);
654 return *this;
655}
656
657template <typename T>
658template <typename InputIterator>
659constexpr InlineBasicString<T, string_impl::kGeneric>&
660InlineBasicString<T, string_impl::kGeneric>::CopyIteratorExtend(
661 T* data, size_t index, InputIterator begin, InputIterator end) {
662 size_t length =
663 string_impl::IteratorCopy(begin, end, data + index, data + max_size());
664 SetSizeAndTerminate(data, std::max(size(), index + length));
665 return *this;
666}
667
668template <typename T>
669constexpr InlineBasicString<T, string_impl::kGeneric>&
670InlineBasicString<T, string_impl::kGeneric>::Fill(T* data,
671 T fill_char,
672 size_t new_size) {
673 PW_ASSERT(new_size <= max_size());
674 string_impl::char_traits<T>::assign(data, new_size, fill_char);
675 SetSizeAndTerminate(data, new_size);
676 return *this;
677}
678
679template <typename T>
680constexpr InlineBasicString<T, string_impl::kGeneric>&
681InlineBasicString<T, string_impl::kGeneric>::FillExtend(T* data,
682 size_t index,
683 T fill_char,
684 size_t count) {
685 PW_ASSERT(index <= size());
686 PW_ASSERT(count <= max_size() - index);
687 string_impl::char_traits<T>::assign(data + index, count, fill_char);
688 SetSizeAndTerminate(data, std::max(size(), index + count));
689 return *this;
690}
691
692template <typename T>
693constexpr InlineBasicString<T, string_impl::kGeneric>&
694InlineBasicString<T, string_impl::kGeneric>::MoveExtend(T* data,
695 size_t index,
696 size_t new_index) {
697 PW_ASSERT(index <= size());
698 PW_ASSERT(new_index <= max_size());
699 PW_ASSERT(size() - index <= max_size() - new_index);
700 string_impl::char_traits<T>::move(
701 data + new_index, data + index, size() - index);
702 SetSizeAndTerminate(data, size() - index + new_index);
703 return *this;
704}
705
706template <typename T>
707constexpr void InlineBasicString<T, string_impl::kGeneric>::Resize(
708 T* data, size_t new_size, T ch) {
709 PW_ASSERT(new_size <= max_size());
710
711 if (new_size > size()) {
712 string_impl::char_traits<T>::assign(data + size(), new_size - size(), ch);
713 }
714
715 SetSizeAndTerminate(data, new_size);
716}
717
718} // namespace pw
719
720#undef _PW_STRING_CAPACITY_TOO_SMALL_FOR_ARRAY
721#undef _PW_STRING_CAPACITY_TOO_SMALL_FOR_STRING
pw::InlineBasicString is a fixed-capacity version of std::basic_string. In brief:
Definition: string.h:66
Definition: string_builder.h:87
Definition: ptr_iterator.h:159
Definition: ptr_iterator.h:137
Provides basic helpers for reading and writing UTF-8 encoded strings.
Definition: alignment.h:27
StatusWithSize Copy(std::string_view source, Span &&dest)
pw::string::Copy is a safer alternative to std::strncpy as it always null-terminates whenever the des...
Definition: util.h:120