xref: /aosp_15_r20/external/pigweed/pw_string/public/pw_string/string.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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