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
16 /// @file pw_string/string.h
17 ///
18 /// @brief `pw::InlineBasicString` and `pw::InlineString` are safer alternatives
19 /// to `std::basic_string` and `std::string`.
20
21 #include <cstddef>
22 #include <initializer_list>
23 #include <iterator>
24
25 #include "pw_assert/assert.h"
26 #include "pw_polyfill/standard.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
42 namespace pw {
43
44 /// @brief `pw::InlineBasicString` is a fixed-capacity version of
45 /// `std::basic_string`. In brief:
46 ///
47 /// - It is C++14-compatible and null-terminated.
48 /// - It stores the string contents inline and uses no dynamic memory.
49 /// - It implements mostly the same API as `std::basic_string`, but the capacity
50 /// of the string is fixed at construction and cannot grow. Attempting to
51 /// increase the size beyond the capacity triggers an assert.
52 ///
53 /// `pw::InlineBasicString` is efficient and compact. The current size and
54 /// capacity are stored in a single word. Accessing its contents is a simple
55 /// array access within the object, with no pointer indirection, even when
56 /// working from a generic reference `pw::InlineBasicString<T>` where the
57 /// capacity is not specified as a template argument. A string object can be
58 /// used safely without the need to know its capacity.
59 ///
60 /// See also `pw::InlineString`, which is an alias of
61 /// `pw::InlineBasicString<char>` and is equivalent to `std::string`.
62 template <typename T, string_impl::size_type kCapacity = string_impl::kGeneric>
63 class InlineBasicString final
64 : public InlineBasicString<T, string_impl::kGeneric> {
65 public:
66 using typename InlineBasicString<T, string_impl::kGeneric>::value_type;
67 using typename InlineBasicString<T, string_impl::kGeneric>::size_type;
68 using typename InlineBasicString<T, string_impl::kGeneric>::difference_type;
69 using typename InlineBasicString<T, string_impl::kGeneric>::reference;
70 using typename InlineBasicString<T, string_impl::kGeneric>::const_reference;
71 using typename InlineBasicString<T, string_impl::kGeneric>::pointer;
72 using typename InlineBasicString<T, string_impl::kGeneric>::const_pointer;
73 using typename InlineBasicString<T, string_impl::kGeneric>::iterator;
74 using typename InlineBasicString<T, string_impl::kGeneric>::const_iterator;
75 using typename InlineBasicString<T, string_impl::kGeneric>::reverse_iterator;
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
InlineBasicString()84 constexpr InlineBasicString() noexcept
85 : InlineBasicString<T, string_impl::kGeneric>(kCapacity), buffer_() {}
86
InlineBasicString(size_type count,T ch)87 constexpr InlineBasicString(size_type count, T ch) : InlineBasicString() {
88 Fill(data(), ch, count);
89 }
90
91 template <size_type kOtherCapacity>
92 constexpr InlineBasicString(const InlineBasicString<T, kOtherCapacity>& other,
93 size_type index,
94 size_type count = npos)
InlineBasicString()95 : InlineBasicString() {
96 CopySubstr(data(), other.data(), other.size(), index, count);
97 }
98
InlineBasicString(const T * string,size_type count)99 constexpr InlineBasicString(const T* string, size_type count)
100 : InlineBasicString() {
101 Copy(data(), string, count);
102 }
103
104 template <typename U,
105 typename = string_impl::EnableIfNonArrayCharPointer<T, U>>
InlineBasicString(U c_string)106 constexpr InlineBasicString(U c_string)
107 : InlineBasicString(
108 c_string, string_impl::BoundedStringLength(c_string, kCapacity)) {}
109
110 template <size_t kCharArraySize>
InlineBasicString(const T (& array)[kCharArraySize])111 constexpr InlineBasicString(const T (&array)[kCharArraySize])
112 : InlineBasicString() {
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>>
InlineBasicString(InputIterator start,InputIterator finish)121 constexpr InlineBasicString(InputIterator start, InputIterator finish)
122 : InlineBasicString() {
123 IteratorCopy(start, finish, data(), data() + max_size());
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_type kOtherCapacity>
InlineBasicString(const InlineBasicString<T,kOtherCapacity> & other)132 constexpr InlineBasicString(const InlineBasicString<T, kOtherCapacity>& other)
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
InlineBasicString(std::initializer_list<T> list)139 constexpr InlineBasicString(std::initializer_list<T> list)
140 : InlineBasicString(list.begin(), list.size()) {}
141
142 #if PW_CXX_STANDARD_IS_SUPPORTED(17) // std::string_view is a C++17 feature
143 // Unlike std::string, pw::InlineString<> supports implicit conversions from
144 // std::string_view. However, explicit conversions are still required from
145 // types that convert to std::string_view, as with std::string.
146 //
147 // pw::InlineString<> allows implicit conversions from std::string_view
148 // because it can be cumbersome to specify the capacity parameter. In
149 // particular, this can make using aggregate initialization more difficult.
150 //
151 // This explicit constructor is enabled for an argument that converts to
152 // std::string_view, but is not a std::string_view.
153 template <
154 typename StringViewLike,
155 string_impl::EnableIfStringViewLikeButNotStringView<T, StringViewLike>* =
156 nullptr>
InlineBasicString(const StringViewLike & string)157 explicit constexpr InlineBasicString(const StringViewLike& string)
158 : InlineBasicString(std::basic_string_view<T>(string)) {}
159
160 // This converting constructor is enabled for std::string_view, but not types
161 // that convert to it.
162 template <typename StringView,
163 std::enable_if_t<
164 std::is_same<StringView, std::basic_string_view<T>>::value>* =
165 nullptr>
InlineBasicString(const StringView & view)166 constexpr InlineBasicString(const StringView& view)
167 : InlineBasicString(view.data(), view.size()) {}
168
169 template <typename StringView,
170 typename = string_impl::EnableIfStringViewLike<T, StringView>>
InlineBasicString(const StringView & string,size_type index,size_type count)171 constexpr InlineBasicString(const StringView& string,
172 size_type index,
173 size_type count)
174 : InlineBasicString() {
175 const std::basic_string_view<T> view = string;
176 CopySubstr(data(), view.data(), view.size(), index, count);
177 }
178 #endif // PW_CXX_STANDARD_IS_SUPPORTED(17)
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_type kOtherCapacity>
189 constexpr InlineBasicString& operator=(
190 const InlineBasicString<T, kOtherCapacity>& other) {
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 #if PW_CXX_STANDARD_IS_SUPPORTED(17) // std::string_view is a C++17 feature
217 template <typename StringView,
218 typename = string_impl::EnableIfStringViewLike<T, StringView>>
219 constexpr InlineBasicString& operator=(const StringView& string) {
220 return assign(string); // NOLINT
221 }
222 #endif // PW_CXX_STANDARD_IS_SUPPORTED(17)
223
224 constexpr InlineBasicString& operator=(std::nullptr_t) = delete;
225
226 template <size_type kOtherCapacity>
227 constexpr InlineBasicString& operator+=(
228 const InlineBasicString<T, kOtherCapacity>& string) {
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 #if PW_CXX_STANDARD_IS_SUPPORTED(17) // std::string_view is a C++17 feature
253 template <typename StringView,
254 typename = string_impl::EnableIfStringViewLike<T, StringView>>
255 constexpr InlineBasicString& operator+=(const StringView& string) {
256 return append(string);
257 }
258 #endif // PW_CXX_STANDARD_IS_SUPPORTED(17)
259
260 // The data() and size() functions are defined differently for the generic and
261 // known-size specializations. This is to support using pw::InlineBasicString
262 // in constexpr statements. This data() implementation simply returns the
263 // underlying buffer. The generic-capacity data() function casts *this to
264 // InlineBasicString<T, 0>, so is only constexpr when the capacity is actually
265 // 0.
data()266 constexpr pointer data() { return buffer_; }
data()267 constexpr const_pointer data() const { return buffer_; }
268
269 // Use the size() function from the base, but define max_size() to return the
270 // kCapacity template parameter instead of reading the stored capacity value.
271 using InlineBasicString<T, string_impl::kGeneric>::size;
max_size()272 constexpr size_type max_size() const noexcept { return kCapacity; }
273
274 // Most string functions are defined in separate file so they can be shared
275 // between the known capacity and generic capacity versions of
276 // InlineBasicString.
277 #include "pw_string/internal/string_common_functions.inc"
278
279 private:
280 using InlineBasicString<T, string_impl::kGeneric>::PushBack;
281 using InlineBasicString<T, string_impl::kGeneric>::PopBack;
282 using InlineBasicString<T, string_impl::kGeneric>::Copy;
283 using InlineBasicString<T, string_impl::kGeneric>::CopySubstr;
284 using InlineBasicString<T, string_impl::kGeneric>::Fill;
285 using InlineBasicString<T, string_impl::kGeneric>::IteratorCopy;
286 using InlineBasicString<T, string_impl::kGeneric>::CopyExtend;
287 using InlineBasicString<T, string_impl::kGeneric>::CopyExtendSubstr;
288 using InlineBasicString<T, string_impl::kGeneric>::FillExtend;
289 using InlineBasicString<T, string_impl::kGeneric>::IteratorExtend;
290 using InlineBasicString<T, string_impl::kGeneric>::Resize;
291 using InlineBasicString<T, string_impl::kGeneric>::SetSizeAndTerminate;
292
293 // Store kCapacity + 1 bytes to reserve space for a null terminator.
294 // InlineBasicString<T, 0> only stores a null terminator.
295 T buffer_[kCapacity + 1];
296 };
297
298 // Generic-capacity version of pw::InlineBasicString. Generic-capacity strings
299 // cannot be constructed; they can only be used as references to fixed-capacity
300 // pw::InlineBasicString objects.
301 template <typename T>
302 class InlineBasicString<T, string_impl::kGeneric> {
303 public:
304 using value_type = T;
305 using size_type = string_impl::size_type;
306 using difference_type = std::ptrdiff_t;
307 using reference = value_type&;
308 using const_reference = const value_type&;
309 using pointer = value_type*;
310 using const_pointer = const value_type*;
311 using iterator = value_type*;
312 using const_iterator = const value_type*;
313 using reverse_iterator = std::reverse_iterator<iterator>;
314 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
315
316 static constexpr size_type npos = string_impl::kGeneric;
317
318 InlineBasicString() = delete; // Must specify capacity to construct a string.
319
320 // For the generic-capacity pw::InlineBasicString, cast this object to a
321 // fixed-capacity class so the address of the data can be found. Even though
322 // the capacity isn't known at compile time, the location of the data never
323 // changes.
data()324 constexpr pointer data() noexcept {
325 return static_cast<InlineBasicString<T, 0>*>(this)->data();
326 }
data()327 constexpr const_pointer data() const noexcept {
328 return static_cast<const InlineBasicString<T, 0>*>(this)->data();
329 }
330
size()331 constexpr size_type size() const noexcept { return length_; }
max_size()332 constexpr size_type max_size() const noexcept { return capacity_; }
333
334 // Most string functions are defined in separate file so they can be shared
335 // between the known capacity and generic capacity versions of
336 // InlineBasicString.
337 #include "pw_string/internal/string_common_functions.inc"
338
339 protected:
InlineBasicString(size_type capacity)340 explicit constexpr InlineBasicString(size_type capacity)
341 : capacity_(capacity), length_(0) {}
342
343 // The generic-capacity InlineBasicString<T> is not copyable or movable, but
344 // BasicStrings can copied or assigned through a fixed capacity derived class.
345 InlineBasicString(const InlineBasicString&) = default;
346
347 InlineBasicString& operator=(const InlineBasicString&) = default;
348
349 constexpr void PushBack(T* data, T ch);
350
PopBack(T * data)351 constexpr void PopBack(T* data) {
352 PW_ASSERT(!empty());
353 SetSizeAndTerminate(data, size() - 1);
354 }
355
356 constexpr InlineBasicString& Copy(T* data,
357 const T* source,
358 size_type new_size);
359
360 constexpr InlineBasicString& CopySubstr(T* data,
361 const T* source,
362 size_type source_size,
363 size_type index,
364 size_type count);
365
366 constexpr InlineBasicString& Fill(T* data, T fill_char, size_type new_size);
367
368 template <typename InputIterator>
IteratorCopy(InputIterator start,InputIterator finish,T * data_start,const T * data_finish)369 constexpr InlineBasicString& IteratorCopy(InputIterator start,
370 InputIterator finish,
371 T* data_start,
372 const T* data_finish) {
373 set_size(string_impl::IteratorCopyAndTerminate(
374 start, finish, data_start, data_finish));
375 return *this;
376 }
377
378 constexpr InlineBasicString& CopyExtend(T* data,
379 const T* source,
380 size_type count);
381
382 constexpr InlineBasicString& CopyExtendSubstr(T* data,
383 const T* source,
384 size_type source_size,
385 size_type index,
386 size_type count);
387
388 constexpr InlineBasicString& FillExtend(T* data,
389 T fill_char,
390 size_type count);
391
392 template <typename InputIterator>
IteratorExtend(InputIterator start,InputIterator finish,T * data_start,const T * data_finish)393 constexpr InlineBasicString& IteratorExtend(InputIterator start,
394 InputIterator finish,
395 T* data_start,
396 const T* data_finish) {
397 length_ += string_impl::IteratorCopyAndTerminate(
398 start, finish, data_start, data_finish);
399 return *this;
400 }
401
402 constexpr void Resize(T* data, size_type new_size, T ch);
403
set_size(size_type length)404 constexpr void set_size(size_type length) { length_ = length; }
SetSizeAndTerminate(T * data,size_type length)405 constexpr void SetSizeAndTerminate(T* data, size_type length) {
406 string_impl::char_traits<T>::assign(data[length], T());
407 set_size(length);
408 }
409
410 private:
411 // Allow StringBuilder to directly set length_ when doing string operations.
412 friend class StringBuilder;
413
414 // Provide this constant for static_assert checks. If the capacity is unknown,
415 // use the maximum value so that compile-time capacity checks pass. If
416 // overflow occurs, the operation triggers a PW_ASSERT at runtime.
417 static constexpr size_type kCapacity = string_impl::kGeneric;
418
419 size_type capacity_;
420 size_type length_;
421 };
422
423 // Class template argument deduction guides
424
425 #ifdef __cpp_deduction_guides
426
427 // In C++17, the capacity of the string may be deduced from a string literal or
428 // array. For example, the following deduces a character type of char and a
429 // capacity of 4 (which does not include the null terminator).
430 //
431 // InlineBasicString my_string = "1234";
432 //
433 // In C++20, the template parameters for the pw::InlineString alias may be
434 // deduced similarly:
435 //
436 // InlineString my_string = "abc"; // deduces capacity of 3.
437 //
438 template <typename T, size_t kCharArraySize>
439 InlineBasicString(const T (&)[kCharArraySize])
440 -> InlineBasicString<T, kCharArraySize - 1>;
441
442 #endif // __cpp_deduction_guides
443
444 // Operators
445
446 // TODO(b/239996007): Implement operator+
447
448 template <typename T,
449 string_impl::size_type kLhsCapacity,
450 string_impl::size_type kRhsCapacity>
451 constexpr bool operator==(
452 const InlineBasicString<T, kLhsCapacity>& lhs,
453 const InlineBasicString<T, kRhsCapacity>& rhs) noexcept {
454 return lhs.compare(rhs) == 0;
455 }
456
457 template <typename T,
458 string_impl::size_type kLhsCapacity,
459 string_impl::size_type kRhsCapacity>
460 constexpr bool operator!=(
461 const InlineBasicString<T, kLhsCapacity>& lhs,
462 const InlineBasicString<T, kRhsCapacity>& rhs) noexcept {
463 return lhs.compare(rhs) != 0;
464 }
465
466 template <typename T,
467 string_impl::size_type kLhsCapacity,
468 string_impl::size_type kRhsCapacity>
469 constexpr bool operator<(
470 const InlineBasicString<T, kLhsCapacity>& lhs,
471 const InlineBasicString<T, kRhsCapacity>& rhs) noexcept {
472 return lhs.compare(rhs) < 0;
473 }
474
475 template <typename T,
476 string_impl::size_type kLhsCapacity,
477 string_impl::size_type kRhsCapacity>
478 constexpr bool operator<=(
479 const InlineBasicString<T, kLhsCapacity>& lhs,
480 const InlineBasicString<T, kRhsCapacity>& rhs) noexcept {
481 return lhs.compare(rhs) <= 0;
482 }
483
484 template <typename T,
485 string_impl::size_type kLhsCapacity,
486 string_impl::size_type kRhsCapacity>
487 constexpr bool operator>(
488 const InlineBasicString<T, kLhsCapacity>& lhs,
489 const InlineBasicString<T, kRhsCapacity>& rhs) noexcept {
490 return lhs.compare(rhs) > 0;
491 }
492
493 template <typename T,
494 string_impl::size_type kLhsCapacity,
495 string_impl::size_type kRhsCapacity>
496 constexpr bool operator>=(
497 const InlineBasicString<T, kLhsCapacity>& lhs,
498 const InlineBasicString<T, kRhsCapacity>& rhs) noexcept {
499 return lhs.compare(rhs) >= 0;
500 }
501
502 template <typename T, string_impl::size_type kLhsCapacity>
503 constexpr bool operator==(const InlineBasicString<T, kLhsCapacity>& lhs,
504 const T* rhs) {
505 return lhs.compare(rhs) == 0;
506 }
507
508 template <typename T, string_impl::size_type kRhsCapacity>
509 constexpr bool operator==(const T* lhs,
510 const InlineBasicString<T, kRhsCapacity>& rhs) {
511 return rhs.compare(lhs) == 0;
512 }
513
514 template <typename T, string_impl::size_type kLhsCapacity>
515 constexpr bool operator!=(const InlineBasicString<T, kLhsCapacity>& lhs,
516 const T* rhs) {
517 return lhs.compare(rhs) != 0;
518 }
519
520 template <typename T, string_impl::size_type kRhsCapacity>
521 constexpr bool operator!=(const T* lhs,
522 const InlineBasicString<T, kRhsCapacity>& rhs) {
523 return rhs.compare(lhs) != 0;
524 }
525
526 template <typename T, string_impl::size_type kLhsCapacity>
527 constexpr bool operator<(const InlineBasicString<T, kLhsCapacity>& lhs,
528 const T* rhs) {
529 return lhs.compare(rhs) < 0;
530 }
531
532 template <typename T, string_impl::size_type kRhsCapacity>
533 constexpr bool operator<(const T* lhs,
534 const InlineBasicString<T, kRhsCapacity>& rhs) {
535 return rhs.compare(lhs) >= 0;
536 }
537
538 template <typename T, string_impl::size_type kLhsCapacity>
539 constexpr bool operator<=(const InlineBasicString<T, kLhsCapacity>& lhs,
540 const T* rhs) {
541 return lhs.compare(rhs) <= 0;
542 }
543
544 template <typename T, string_impl::size_type kRhsCapacity>
545 constexpr bool operator<=(const T* lhs,
546 const InlineBasicString<T, kRhsCapacity>& rhs) {
547 return rhs.compare(lhs) >= 0;
548 }
549
550 template <typename T, string_impl::size_type kLhsCapacity>
551 constexpr bool operator>(const InlineBasicString<T, kLhsCapacity>& lhs,
552 const T* rhs) {
553 return lhs.compare(rhs) > 0;
554 }
555
556 template <typename T, string_impl::size_type kRhsCapacity>
557 constexpr bool operator>(const T* lhs,
558 const InlineBasicString<T, kRhsCapacity>& rhs) {
559 return rhs.compare(lhs) <= 0;
560 }
561
562 template <typename T, string_impl::size_type kLhsCapacity>
563 constexpr bool operator>=(const InlineBasicString<T, kLhsCapacity>& lhs,
564 const T* rhs) {
565 return lhs.compare(rhs) >= 0;
566 }
567
568 template <typename T, string_impl::size_type kRhsCapacity>
569 constexpr bool operator>=(const T* lhs,
570 const InlineBasicString<T, kRhsCapacity>& rhs) {
571 return rhs.compare(lhs) <= 0;
572 }
573
574 // TODO(b/239996007): Implement other comparison operator overloads.
575
576 // Aliases
577
578 /// @brief `pw::InlineString` is an alias of `pw::InlineBasicString<char>` and
579 /// is equivalent to `std::string`.
580 template <string_impl::size_type kCapacity = string_impl::kGeneric>
581 using InlineString = InlineBasicString<char, kCapacity>;
582
583 // Function implementations
584
585 template <typename T>
PushBack(T * data,T ch)586 constexpr void InlineBasicString<T, string_impl::kGeneric>::PushBack(T* data,
587 T ch) {
588 PW_ASSERT(size() < max_size());
589 string_impl::char_traits<T>::assign(data[size()], ch);
590 SetSizeAndTerminate(data, size() + 1);
591 }
592
593 template <typename T>
594 constexpr InlineBasicString<T, string_impl::kGeneric>&
Copy(T * data,const T * source,size_type new_size)595 InlineBasicString<T, string_impl::kGeneric>::Copy(T* data,
596 const T* source,
597 size_type new_size) {
598 PW_ASSERT(new_size <= max_size());
599 string_impl::char_traits<T>::copy(data, source, new_size);
600 SetSizeAndTerminate(data, new_size);
601 return *this;
602 }
603
604 template <typename T>
605 constexpr InlineBasicString<T, string_impl::kGeneric>&
CopySubstr(T * data,const T * source,size_type source_size,size_type index,size_type count)606 InlineBasicString<T, string_impl::kGeneric>::CopySubstr(T* data,
607 const T* source,
608 size_type source_size,
609 size_type index,
610 size_type count) {
611 PW_ASSERT(index <= source_size);
612 return Copy(data,
613 source + index,
614 std::min(count, static_cast<size_type>(source_size - index)));
615 }
616
617 template <typename T>
618 constexpr InlineBasicString<T, string_impl::kGeneric>&
Fill(T * data,T fill_char,size_type new_size)619 InlineBasicString<T, string_impl::kGeneric>::Fill(T* data,
620 T fill_char,
621 size_type new_size) {
622 PW_ASSERT(new_size <= max_size());
623 string_impl::char_traits<T>::assign(data, new_size, fill_char);
624 SetSizeAndTerminate(data, new_size);
625 return *this;
626 }
627
628 template <typename T>
629 constexpr InlineBasicString<T, string_impl::kGeneric>&
CopyExtend(T * data,const T * source,size_type count)630 InlineBasicString<T, string_impl::kGeneric>::CopyExtend(T* data,
631 const T* source,
632 size_type count) {
633 PW_ASSERT(count <= max_size() - size());
634 string_impl::char_traits<T>::copy(data + size(), source, count);
635 SetSizeAndTerminate(data, size() + count);
636 return *this;
637 }
638
639 template <typename T>
640 constexpr InlineBasicString<T, string_impl::kGeneric>&
CopyExtendSubstr(T * data,const T * source,size_type source_size,size_type index,size_type count)641 InlineBasicString<T, string_impl::kGeneric>::CopyExtendSubstr(
642 T* data,
643 const T* source,
644 size_type source_size,
645 size_type index,
646 size_type count) {
647 PW_ASSERT(index <= source_size);
648 return CopyExtend(
649 data,
650 source + index,
651 std::min(count, static_cast<size_type>(source_size - index)));
652 return *this;
653 }
654
655 template <typename T>
656 constexpr InlineBasicString<T, string_impl::kGeneric>&
FillExtend(T * data,T fill_char,size_type count)657 InlineBasicString<T, string_impl::kGeneric>::FillExtend(T* data,
658 T fill_char,
659 size_type count) {
660 PW_ASSERT(count <= max_size() - size());
661 string_impl::char_traits<T>::assign(data + size(), count, fill_char);
662 SetSizeAndTerminate(data, size() + count);
663 return *this;
664 }
665
666 template <typename T>
Resize(T * data,size_type new_size,T ch)667 constexpr void InlineBasicString<T, string_impl::kGeneric>::Resize(
668 T* data, size_type new_size, T ch) {
669 PW_ASSERT(new_size <= max_size());
670
671 if (new_size > size()) {
672 string_impl::char_traits<T>::assign(data + size(), new_size - size(), ch);
673 }
674
675 SetSizeAndTerminate(data, new_size);
676 }
677
678 } // namespace pw
679
680 #undef _PW_STRING_CAPACITY_TOO_SMALL_FOR_ARRAY
681 #undef _PW_STRING_CAPACITY_TOO_SMALL_FOR_STRING
682