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