• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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