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 #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
42 namespace pw {
43
44 /// @brief `pw::InlineBasicString` is a fixed-capacity version of
45 /// `std::basic_string`. In brief:
46 ///
47 /// - It is always 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, size_t 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_t count,T ch)87 constexpr InlineBasicString(size_t count, T ch) : InlineBasicString() {
88 Fill(data(), ch, count);
89 }
90
91 template <size_t kOtherCapacity>
92 constexpr InlineBasicString(const InlineBasicString<T, kOtherCapacity>& other,
93 size_t index,
94 size_t count = npos)
InlineBasicString()95 : InlineBasicString() {
96 CopySubstr(data(), other.data(), other.size(), index, count);
97 }
98
InlineBasicString(const T * string,size_t count)99 constexpr InlineBasicString(const T* string, size_t 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 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>
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 // 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>
InlineBasicString(const StringViewLike & string)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>
InlineBasicString(const StringView & view)165 constexpr InlineBasicString(const StringView& view)
166 : InlineBasicString(view.data(), view.size()) {}
167
168 template <typename StringView,
169 typename = string_impl::EnableIfStringViewLike<T, StringView>>
InlineBasicString(const StringView & string,size_t index,size_t count)170 constexpr InlineBasicString(const StringView& string,
171 size_t index,
172 size_t count)
173 : InlineBasicString() {
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=(
188 const InlineBasicString<T, kOtherCapacity>& other) {
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+=(
224 const InlineBasicString<T, kOtherCapacity>& string) {
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.
data()260 constexpr pointer data() { return buffer_; }
data()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;
max_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.
296 template <typename T>
297 class 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.
data()319 constexpr pointer data() noexcept {
320 return static_cast<InlineBasicString<T, 0>*>(this)->data();
321 }
data()322 constexpr const_pointer data() const noexcept {
323 return static_cast<const InlineBasicString<T, 0>*>(this)->data();
324 }
325
size()326 constexpr size_t size() const noexcept { return length_; }
max_size()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:
InlineBasicString(size_t capacity)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
PopBack(T * data)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
set_size(size_t length)392 constexpr void set_size(size_t length) {
393 length_ = string_impl::CheckedCastToSize(length);
394 }
SetSizeAndTerminate(T * data,size_t length)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 //
437 template <typename T, size_t kCharArraySize>
438 InlineBasicString(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
447 template <typename T, size_t kLhsCapacity, size_t kRhsCapacity>
448 constexpr bool operator==(
449 const InlineBasicString<T, kLhsCapacity>& lhs,
450 const InlineBasicString<T, kRhsCapacity>& rhs) noexcept {
451 return lhs.compare(rhs) == 0;
452 }
453
454 template <typename T, size_t kLhsCapacity, size_t kRhsCapacity>
455 constexpr bool operator!=(
456 const InlineBasicString<T, kLhsCapacity>& lhs,
457 const InlineBasicString<T, kRhsCapacity>& rhs) noexcept {
458 return lhs.compare(rhs) != 0;
459 }
460
461 template <typename T, size_t kLhsCapacity, size_t kRhsCapacity>
462 constexpr bool operator<(
463 const InlineBasicString<T, kLhsCapacity>& lhs,
464 const InlineBasicString<T, kRhsCapacity>& rhs) noexcept {
465 return lhs.compare(rhs) < 0;
466 }
467
468 template <typename T, size_t kLhsCapacity, size_t 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, size_t kLhsCapacity, size_t kRhsCapacity>
476 constexpr bool operator>(
477 const InlineBasicString<T, kLhsCapacity>& lhs,
478 const InlineBasicString<T, kRhsCapacity>& rhs) noexcept {
479 return lhs.compare(rhs) > 0;
480 }
481
482 template <typename T, size_t kLhsCapacity, size_t kRhsCapacity>
483 constexpr bool operator>=(
484 const InlineBasicString<T, kLhsCapacity>& lhs,
485 const InlineBasicString<T, kRhsCapacity>& rhs) noexcept {
486 return lhs.compare(rhs) >= 0;
487 }
488
489 template <typename T, size_t kLhsCapacity>
490 constexpr bool operator==(const InlineBasicString<T, kLhsCapacity>& lhs,
491 const T* rhs) {
492 return lhs.compare(rhs) == 0;
493 }
494
495 template <typename T, size_t kRhsCapacity>
496 constexpr bool operator==(const T* lhs,
497 const InlineBasicString<T, kRhsCapacity>& rhs) {
498 return rhs.compare(lhs) == 0;
499 }
500
501 template <typename T, size_t kLhsCapacity>
502 constexpr bool operator!=(const InlineBasicString<T, kLhsCapacity>& lhs,
503 const T* rhs) {
504 return lhs.compare(rhs) != 0;
505 }
506
507 template <typename T, size_t kRhsCapacity>
508 constexpr bool operator!=(const T* lhs,
509 const InlineBasicString<T, kRhsCapacity>& rhs) {
510 return rhs.compare(lhs) != 0;
511 }
512
513 template <typename T, size_t kLhsCapacity>
514 constexpr bool operator<(const InlineBasicString<T, kLhsCapacity>& lhs,
515 const T* rhs) {
516 return lhs.compare(rhs) < 0;
517 }
518
519 template <typename T, size_t kRhsCapacity>
520 constexpr bool operator<(const T* lhs,
521 const InlineBasicString<T, kRhsCapacity>& rhs) {
522 return rhs.compare(lhs) >= 0;
523 }
524
525 template <typename T, size_t kLhsCapacity>
526 constexpr bool operator<=(const InlineBasicString<T, kLhsCapacity>& lhs,
527 const T* rhs) {
528 return lhs.compare(rhs) <= 0;
529 }
530
531 template <typename T, size_t kRhsCapacity>
532 constexpr bool operator<=(const T* lhs,
533 const InlineBasicString<T, kRhsCapacity>& rhs) {
534 return rhs.compare(lhs) >= 0;
535 }
536
537 template <typename T, size_t kLhsCapacity>
538 constexpr bool operator>(const InlineBasicString<T, kLhsCapacity>& lhs,
539 const T* rhs) {
540 return lhs.compare(rhs) > 0;
541 }
542
543 template <typename T, size_t kRhsCapacity>
544 constexpr bool operator>(const T* lhs,
545 const InlineBasicString<T, kRhsCapacity>& rhs) {
546 return rhs.compare(lhs) <= 0;
547 }
548
549 template <typename T, size_t kLhsCapacity>
550 constexpr bool operator>=(const InlineBasicString<T, kLhsCapacity>& lhs,
551 const T* rhs) {
552 return lhs.compare(rhs) >= 0;
553 }
554
555 template <typename T, size_t kRhsCapacity>
556 constexpr 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
565 /// @brief `pw::InlineString` is an alias of `pw::InlineBasicString<char>` and
566 /// is equivalent to `std::string`.
567 template <size_t kCapacity = string_impl::kGeneric>
568 using InlineString = InlineBasicString<char, kCapacity>;
569
570 /// @brief `pw::InlineByteString` is an alias of
571 /// `pw::InlineBasicString<std::byte>`. `InlineByteString` may be used as a
572 /// simple, efficient byte container.
573 template <size_t kCapacity = string_impl::kGeneric>
574 using InlineByteString = InlineBasicString<std::byte, kCapacity>;
575
576 // Function implementations
577
578 template <typename T>
PushBack(T * data,T ch)579 constexpr void InlineBasicString<T, string_impl::kGeneric>::PushBack(T* data,
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
586 template <typename T>
587 constexpr InlineBasicString<T, string_impl::kGeneric>&
Copy(T * data,const T * source,size_t new_size)588 InlineBasicString<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
597 template <typename T>
598 constexpr InlineBasicString<T, string_impl::kGeneric>&
CopySubstr(T * data,const T * source,size_t source_size,size_t index,size_t count)599 InlineBasicString<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
605 template <typename T>
606 constexpr InlineBasicString<T, string_impl::kGeneric>&
CopyExtend(T * data,size_t index,const T * source,size_t count)607 InlineBasicString<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
618 template <typename T>
619 constexpr InlineBasicString<T, string_impl::kGeneric>&
CopyExtendSubstr(T * data,size_t index,const T * source,size_t source_size,size_t source_index,size_t count)620 InlineBasicString<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
635 template <typename T>
636 template <typename InputIterator>
637 constexpr InlineBasicString<T, string_impl::kGeneric>&
CopyIterator(T * data,InputIterator begin,InputIterator end)638 InlineBasicString<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
647 template <typename T>
648 template <typename InputIterator>
649 constexpr InlineBasicString<T, string_impl::kGeneric>&
CopyIteratorExtend(T * data,size_t index,InputIterator begin,InputIterator end)650 InlineBasicString<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
658 template <typename T>
659 constexpr InlineBasicString<T, string_impl::kGeneric>&
Fill(T * data,T fill_char,size_t new_size)660 InlineBasicString<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
669 template <typename T>
670 constexpr InlineBasicString<T, string_impl::kGeneric>&
FillExtend(T * data,size_t index,T fill_char,size_t count)671 InlineBasicString<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
682 template <typename T>
683 constexpr InlineBasicString<T, string_impl::kGeneric>&
MoveExtend(T * data,size_t index,size_t new_index)684 InlineBasicString<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
696 template <typename T>
Resize(T * data,size_t new_size,T ch)697 constexpr 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
712