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