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 : public InlineBasicString<T, string_impl::kGeneric> {
69 public:
80 using
81 typename InlineBasicString<T,
82 string_impl::kGeneric>::const_reverse_iterator;
83
84 using InlineBasicString<T, string_impl::kGeneric>::npos;
85
86 // Constructors
87
88 constexpr InlineBasicString() noexcept
89 : InlineBasicString<T, string_impl::kGeneric>(kCapacity), buffer_() {}
90
91 constexpr InlineBasicString(size_t count, T ch) : InlineBasicString() {
92 Fill(data(), ch, count);
93 }
94
95 template <size_t kOtherCapacity>
97 size_t index,
98 size_t count = npos)
100 CopySubstr(data(), other.data(), other.size(), index, count);
101 }
102
103 constexpr InlineBasicString(const T* string, size_t count)
105 Copy(data(), string, count);
106 }
107
108 template <typename U,
109 typename = string_impl::EnableIfNonArrayCharPointer<T, U>>
110 constexpr InlineBasicString(U c_string)
112 c_string, string_impl::BoundedStringLength(c_string, kCapacity)) {}
113
114 template <size_t kCharArraySize>
115 constexpr InlineBasicString(const T (&array)[kCharArraySize])
117 static_assert(
118 string_impl::NullTerminatedArrayFitsInString(kCharArraySize, kCapacity),
119 _PW_STRING_CAPACITY_TOO_SMALL_FOR_ARRAY);
120 Copy(data(), array, string_impl::ArrayStringLength(array, max_size()));
121 }
122
123 template <typename Iterator,
124 typename = containers::internal::EnableIfInputIterator<Iterator>>
125 constexpr InlineBasicString(Iterator start, Iterator finish)
127 CopyIterator(data(), start, finish);
128 }
129
130 // Use the default copy for InlineBasicString with the same capacity.
131 constexpr InlineBasicString(const InlineBasicString&) = default;
132
133 // When copying from an InlineBasicString with a different capacity, check
134 // that the destination capacity is at least as large as the source capacity.
135 template <size_t kOtherCapacity>
137 : InlineBasicString(other.data(), other.size()) {
138 static_assert(
139 kOtherCapacity == string_impl::kGeneric || kOtherCapacity <= kCapacity,
140 _PW_STRING_CAPACITY_TOO_SMALL_FOR_STRING);
141 }
142
143 constexpr InlineBasicString(std::initializer_list<T> list)
144 : InlineBasicString(list.begin(), list.size()) {}
145
146 // Unlike std::string, pw::InlineString<> supports implicit conversions from
147 // std::string_view. However, explicit conversions are still required from
148 // types that convert to std::string_view, as with std::string.
149 //
150 // pw::InlineString<> allows implicit conversions from std::string_view
151 // because it can be cumbersome to specify the capacity parameter. In
152 // particular, this can make using aggregate initialization more difficult.
153 //
154 // This explicit constructor is enabled for an argument that converts to
155 // std::string_view, but is not a std::string_view.
156 template <
157 typename StringViewLike,
158 string_impl::EnableIfStringViewLikeButNotStringView<T, StringViewLike>* =
159 nullptr>
160 explicit constexpr InlineBasicString(const StringViewLike& string)
161 : InlineBasicString(string_impl::View<T>(string)) {}
162
163 // This converting constructor is enabled for std::string_view, but not types
164 // that convert to it.
165 template <
166 typename StringView,
167 std::enable_if_t<std::is_same<StringView, string_impl::View<T>>::value>* =
168 nullptr>
169 constexpr InlineBasicString(const StringView& view)
170 : InlineBasicString(view.data(), view.size()) {}
171
172 template <typename StringView,
173 typename = string_impl::EnableIfStringViewLike<T, StringView>>
174 constexpr InlineBasicString(const StringView& string,
175 size_t index,
176 size_t count)
178 const string_impl::View<T> view = string;
179 CopySubstr(data(), view.data(), view.size(), index, count);
180 }
181
182 InlineBasicString(std::nullptr_t) = delete; // Cannot construct from nullptr
183
184 // Assignment operators
185
186 constexpr InlineBasicString& operator=(const InlineBasicString& other) =
187 default;
188
189 // Checks capacity rather than current size.
190 template <size_t kOtherCapacity>
191 constexpr InlineBasicString& operator=(
193 return assign<kOtherCapacity>(other); // NOLINT
194 }
195
196 template <size_t kCharArraySize>
197 constexpr InlineBasicString& operator=(const T (&array)[kCharArraySize]) {
198 return assign<kCharArraySize>(array); // NOLINT
199 }
200
201 // Use SFINAE to avoid ambiguity with the array overload.
202 template <typename U,
203 typename = string_impl::EnableIfNonArrayCharPointer<T, U>>
204 constexpr InlineBasicString& operator=(U c_string) {
205 return assign(c_string); // NOLINT
206 }
207
208 constexpr InlineBasicString& operator=(T ch) {
209 static_assert(kCapacity != 0,
210 "Cannot assign a character to pw::InlineString<0>");
211 return assign(1, ch); // NOLINT
212 }
213
214 constexpr InlineBasicString& operator=(std::initializer_list<T> list) {
215 return assign(list); // NOLINT
216 }
217
218 template <typename StringView,
219 typename = string_impl::EnableIfStringViewLike<T, StringView>>
220 constexpr InlineBasicString& operator=(const StringView& string) {
221 return assign(string); // NOLINT
222 }
223
224 constexpr InlineBasicString& operator=(std::nullptr_t) = delete;
225
226 template <size_t kOtherCapacity>
227 constexpr InlineBasicString& operator+=(
229 return append(string);
230 }
231
232 constexpr InlineBasicString& operator+=(T character) {
233 push_back(character);
234 return *this;
235 }
236
237 template <size_t kCharArraySize>
238 constexpr InlineBasicString& operator+=(const T (&array)[kCharArraySize]) {
239 return append(array);
240 }
241
242 template <typename U,
243 typename = string_impl::EnableIfNonArrayCharPointer<T, U>>
244 constexpr InlineBasicString& operator+=(U c_string) {
245 return append(c_string);
246 }
247
248 constexpr InlineBasicString& operator+=(std::initializer_list<T> list) {
249 return append(list.begin(), list.size());
250 }
251
252 template <typename StringView,
253 typename = string_impl::EnableIfStringViewLike<T, StringView>>
254 constexpr InlineBasicString& operator+=(const StringView& string) {
255 return append(string);
256 }
257
258 // The data() and size() functions are defined differently for the generic and
259 // known-size specializations. This is to support using pw::InlineBasicString
260 // in constexpr statements. This data() implementation simply returns the
261 // underlying buffer. The generic-capacity data() function casts *this to
262 // InlineBasicString<T, 0>, so is only constexpr when the capacity is actually
263 // 0.
264 constexpr pointer data() { return buffer_; }
265 constexpr const_pointer data() const { return buffer_; }
266
267 // Use the size() function from the base, but define max_size() to return the
268 // kCapacity template parameter instead of reading the stored capacity value.
269 using InlineBasicString<T, string_impl::kGeneric>::size;
270 constexpr size_t max_size() const noexcept { return kCapacity; }
271
272 // Most string functions are defined in separate file so they can be shared
273 // between the known capacity and generic capacity versions of
274 // InlineBasicString.
275#include "pw_string/internal/string_common_functions.inc"
276
277 private:
278 using InlineBasicString<T, string_impl::kGeneric>::PushBack;
279 using InlineBasicString<T, string_impl::kGeneric>::PopBack;
280 using InlineBasicString<T, string_impl::kGeneric>::Copy;
281 using InlineBasicString<T, string_impl::kGeneric>::CopySubstr;
282 using InlineBasicString<T, string_impl::kGeneric>::Fill;
283 using InlineBasicString<T, string_impl::kGeneric>::CopyIterator;
284 using InlineBasicString<T, string_impl::kGeneric>::CopyExtend;
285 using InlineBasicString<T, string_impl::kGeneric>::CopyExtendSubstr;
286 using InlineBasicString<T, string_impl::kGeneric>::FillExtend;
287 using InlineBasicString<T, string_impl::kGeneric>::MoveExtend;
288 using InlineBasicString<T, string_impl::kGeneric>::CopyIteratorExtend;
289 using InlineBasicString<T, string_impl::kGeneric>::Resize;
290 using InlineBasicString<T, string_impl::kGeneric>::SetSizeAndTerminate;
291
292 // Store kCapacity + 1 bytes to reserve space for a null terminator.
293 // InlineBasicString<T, 0> only stores a null terminator.
294 T buffer_[kCapacity + 1];
295};
296
297// Generic-capacity version of pw::InlineBasicString. Generic-capacity strings
298// cannot be constructed; they can only be used as references to fixed-capacity
299// pw::InlineBasicString objects.
300template <typename T>
301class InlineBasicString<T, string_impl::kGeneric> {
302 public:
303 using value_type = T;
304 using size_type = string_impl::size_type;
305 using difference_type = std::ptrdiff_t;
306 using reference = value_type&;
307 using const_reference = const value_type&;
308 using pointer = value_type*;
309 using const_pointer = const value_type*;
310 using iterator =
312 using const_iterator =
314 using reverse_iterator = std::reverse_iterator<iterator>;
315 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
316
317 static constexpr size_t npos = string_impl::kGeneric;
318
319 InlineBasicString() = delete; // Must specify capacity to construct a string.
320
321 // For the generic-capacity pw::InlineBasicString, cast this object to a
322 // fixed-capacity class so the address of the data can be found. Even though
323 // the capacity isn't known at compile time, the location of the data never
324 // changes.
325 constexpr pointer data() noexcept {
326 return static_cast<InlineBasicString<T, 0>*>(this)->data();
327 }
328 constexpr const_pointer data() const noexcept {
329 return static_cast<const InlineBasicString<T, 0>*>(this)->data();
330 }
331
332 constexpr size_t size() const noexcept { return length_; }
333 constexpr size_t max_size() const noexcept { return capacity_; }
334
335 // Most string functions are defined in separate file so they can be shared
336 // between the known capacity and generic capacity versions of
337 // InlineBasicString.
338#include "pw_string/internal/string_common_functions.inc"
339
340 protected:
341 explicit constexpr InlineBasicString(size_t capacity)
342 : capacity_(string_impl::CheckedCastToSize(capacity)), length_(0) {}
343
344 // The generic-capacity InlineBasicString<T> is not copyable or movable, but
345 // BasicStrings can copied or assigned through a fixed capacity derived class.
346 InlineBasicString(const InlineBasicString&) = default;
347
348 InlineBasicString& operator=(const InlineBasicString&) = default;
349
350 // Allow derived fixed-length types to create iterators.
351 static constexpr iterator Iterator(T* data) { return iterator(data); }
352 static constexpr const_iterator Iterator(const T* data) {
353 return const_iterator(data);
354 }
355
356 constexpr void PushBack(T* data, T ch);
357
358 constexpr void PopBack(T* data) {
359 PW_ASSERT(!empty());
360 SetSizeAndTerminate(data, size() - 1);
361 }
362
363 constexpr InlineBasicString& Copy(T* data, const T* source, size_t new_size);
364
365 constexpr InlineBasicString& CopySubstr(
366 T* data, const T* source, size_t source_size, size_t index, size_t count);
367
368 constexpr InlineBasicString& Fill(T* data, T fill_char, size_t new_size);
369
370 template <typename InputIterator>
371 constexpr InlineBasicString& CopyIterator(T* data_start,
372 InputIterator begin,
373 InputIterator end);
374
375 constexpr InlineBasicString& CopyExtend(T* data,
376 size_t index,
377 const T* source,
378 size_t count);
379
380 constexpr InlineBasicString& CopyExtendSubstr(T* data,
381 size_t index,
382 const T* source,
383 size_t source_size,
384 size_t source_index,
385 size_t count);
386
387 constexpr InlineBasicString& FillExtend(T* data,
388 size_t index,
389 T fill_char,
390 size_t count);
391
392 template <typename InputIterator>
393 constexpr InlineBasicString& CopyIteratorExtend(T* data,
394 size_t index,
395 InputIterator begin,
396 InputIterator end);
397
398 constexpr InlineBasicString& MoveExtend(T* data,
399 size_t index,
400 size_t new_index);
401
402 constexpr void Resize(T* data, size_t new_size, T ch);
403
404 constexpr void set_size(size_t length) {
405 length_ = string_impl::CheckedCastToSize(length);
406 }
407 constexpr void SetSizeAndTerminate(T* data, size_t length) {
408 PW_ASSERT(length <= max_size());
409 string_impl::char_traits<T>::assign(data[length], T());
410 set_size(length);
411 }
412
413 private:
414 static_assert(std::is_same_v<char, T> || std::is_same_v<wchar_t, T> ||
415#ifdef __cpp_char8_t
416 std::is_same_v<char8_t, T> ||
417#endif // __cpp_char8_t
418 std::is_same_v<char16_t, T> ||
419 std::is_same_v<char32_t, T> || std::is_same_v<std::byte, T>,
420 "Only character types and std::byte are supported");
421
422 // Allow StringBuilder to directly set length_ when doing string operations.
423 friend class StringBuilder;
424
425 // Provide this constant for static_assert checks. If the capacity is unknown,
426 // use the maximum value so that compile-time capacity checks pass. If
427 // overflow occurs, the operation triggers a PW_ASSERT at runtime.
428 static constexpr size_t kCapacity = string_impl::kGeneric;
429
430 size_type capacity_;
431 size_type length_;
432};
433
434// Class template argument deduction guides
435
436#ifdef __cpp_deduction_guides
437
438// In C++17, the capacity of the string may be deduced from a string literal or
439// array. For example, the following deduces a character type of char and a
440// capacity of 4 (which does not include the null terminator).
441//
442// InlineBasicString my_string = "1234";
443//
444// In C++20, the template parameters for the pw::InlineString alias may be
445// deduced similarly:
446//
447// InlineString my_string = "abc"; // deduces capacity of 3.
448//
449template <typename T, size_t kCharArraySize>
450InlineBasicString(const T (&)[kCharArraySize])
451 -> InlineBasicString<T, kCharArraySize - 1>;
452
453#endif // __cpp_deduction_guides
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:68
Definition: string_builder.h:89
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:122
The Pigweed namespace.
Definition: alignment.h:27