• 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
15// This file contains the definitions of most pw::InlineBasicString functions.
16// The file is included inline in the fixed-capacity pw::InlineBasicString<T,
17// kCapacity> and generic-capacity pw::InlineBasicString<T> specialization
18// classes.
19//
20// These functions cannot simply be defined in the pw::InlineBasicString<T> base
21// class because:
22//
23//   1. Many functions return a *this reference. The functions should to return
24//      a reference to the exact type they are called on rather than the
25//      generic-capacity base class.
26//   2. Operations on the generic base class cannot be constexpr unless the
27//      class is an InlineBasicString<T, 0>. The functions must be defined in
28//      the fixed-capacity dervied classes to support constexpr operations.
29//
30// These functions have no logic and simply defer to shared, length-agnostic
31// implementations so they do not increase code size.
32
33PW_MODIFY_DIAGNOSTICS_PUSH();
34PW_MODIFY_DIAGNOSTIC_GCC(ignored, "-Wtype-limits");
35
36// Assignment functions
37
38constexpr InlineBasicString& assign(size_t count, T ch) {
39  return static_cast<InlineBasicString&>(Fill(data(), ch, count));
40}
41
42// Checks capacity rather than current size.
43template <size_t kOtherCapacity>
44constexpr InlineBasicString& assign(
45    const InlineBasicString<T, kOtherCapacity>& other) {
46  static_assert(
47      kOtherCapacity == string_impl::kGeneric || kOtherCapacity <= kCapacity,
48      _PW_STRING_CAPACITY_TOO_SMALL_FOR_STRING);
49  return static_cast<InlineBasicString&>(
50      Copy(data(), other.data(), other.size()));
51}
52
53constexpr InlineBasicString& assign(const InlineBasicString& other,
54                                    size_t index,
55                                    size_t count = npos) {
56  return static_cast<InlineBasicString&>(
57      CopySubstr(data(), other.data(), other.size(), index, count));
58}
59
60constexpr InlineBasicString& assign(const T* string, size_t count) {
61  return static_cast<InlineBasicString&>(Copy(data(), string, count));
62}
63
64template <typename U, typename = string_impl::EnableIfNonArrayCharPointer<T, U>>
65constexpr InlineBasicString& assign(U c_string) {
66  return assign(c_string,
67                string_impl::BoundedStringLength(c_string, max_size()));
68}
69
70// Assignment from character array or string literal. For known-size strings,
71// the capacity is checked against the string/array size at compile time.
72template <size_t kCharArraySize>
73constexpr InlineBasicString& assign(const T (&array)[kCharArraySize]) {
74  static_assert(
75      string_impl::NullTerminatedArrayFitsInString(kCharArraySize, kCapacity),
76      _PW_STRING_CAPACITY_TOO_SMALL_FOR_ARRAY);
77  return static_cast<InlineBasicString&>(
78      Copy(data(), array, string_impl::ArrayStringLength(array, max_size())));
79}
80
81template <typename InputIterator,
82          typename = string_impl::EnableIfInputIterator<InputIterator>>
83constexpr InlineBasicString& assign(InputIterator start, InputIterator finish) {
84  return static_cast<InlineBasicString&>(CopyIterator(data(), start, finish));
85}
86
87constexpr InlineBasicString& assign(std::initializer_list<T> list) {
88  return assign(list.begin(), list.size());
89}
90
91template <typename StringView,
92          typename = string_impl::EnableIfStringViewLike<T, StringView>>
93constexpr InlineBasicString& assign(const StringView& string) {
94  const string_impl::View<T> view = string;
95  PW_ASSERT(view.size() < npos);
96  return assign(view.data(), view.size());
97}
98
99template <typename StringView,
100          typename = string_impl::EnableIfStringViewLike<T, StringView>>
101constexpr InlineBasicString& assign(const StringView& string,
102                                    size_t index,
103                                    size_t count = npos) {
104  const string_impl::View<T> view = string;
105  PW_ASSERT(view.size() < npos);
106  return static_cast<InlineBasicString&>(
107      CopySubstr(data(), view.data(), view.size(), index, count));
108}
109
110constexpr InlineBasicString& assign(std::nullptr_t) = delete;
111
112// Element access
113
114constexpr reference at(size_t index) {
115  PW_ASSERT(index < length());
116  return data()[index];
117}
118constexpr const_reference at(size_t index) const {
119  PW_ASSERT(index < length());
120  return data()[index];
121}
122
123constexpr reference operator[](size_t index) { return data()[index]; }
124constexpr const_reference operator[](size_t index) const {
125  return data()[index];
126}
127
128constexpr reference front() { return data()[0]; }
129constexpr const_reference front() const { return data()[0]; }
130
131constexpr reference back() { return data()[size() - 1]; }
132constexpr const_reference back() const { return data()[size() - 1]; }
133
134constexpr const_pointer c_str() const noexcept { return data(); }
135
136constexpr operator string_impl::View<T>() const noexcept {
137  return string_impl::View<T>(data(), size());
138}
139
140// Iterators
141
142constexpr iterator begin() noexcept { return &data()[0]; }
143constexpr const_iterator begin() const noexcept { return &data()[0]; }
144constexpr const_iterator cbegin() const noexcept { return &data()[0]; }
145
146constexpr iterator end() noexcept { return &data()[size()]; }
147constexpr const_iterator end() const noexcept { return &data()[size()]; }
148constexpr const_iterator cend() const noexcept { return &data()[size()]; }
149
150constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
151constexpr const_reverse_iterator rbegin() const noexcept {
152  return const_reverse_iterator(end());
153}
154constexpr const_reverse_iterator crbegin() const noexcept {
155  return const_reverse_iterator(cend());
156}
157
158constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
159constexpr const_reverse_iterator rend() const noexcept {
160  return const_reverse_iterator(begin());
161}
162constexpr const_reverse_iterator crend() const noexcept {
163  return const_reverse_iterator(cbegin());
164}
165
166// Capacity
167
168[[nodiscard]] constexpr bool empty() const noexcept { return size() == 0u; }
169
170// The number of characters in the string.
171constexpr size_t length() const noexcept { return size(); }
172
173constexpr size_t capacity() const noexcept { return max_size(); }
174
175// Operations
176
177constexpr void clear() { SetSizeAndTerminate(data(), 0); }
178
179constexpr InlineBasicString& insert(size_t index, size_t count, T ch) {
180  MoveExtend(data(), index, index + count);
181  return static_cast<InlineBasicString&>(FillExtend(data(), index, ch, count));
182}
183
184constexpr InlineBasicString& insert(size_t index,
185                                    const T* string,
186                                    size_t count) {
187  MoveExtend(data(), index, index + count);
188  return static_cast<InlineBasicString&>(
189      CopyExtend(data(), index, string, count));
190}
191
192template <size_t kCharArraySize>
193constexpr InlineBasicString& insert(size_t index,
194                                    const T (&array)[kCharArraySize]) {
195  return insert(
196      index, array, string_impl::ArrayStringLength(array, max_size()));
197}
198
199template <typename U, typename = string_impl::EnableIfNonArrayCharPointer<T, U>>
200constexpr InlineBasicString& insert(size_t index, U c_string) {
201  return insert(
202      index, c_string, string_impl::BoundedStringLength(c_string, max_size()));
203}
204
205template <size_t kOtherCapacity>
206constexpr InlineBasicString& insert(
207    size_t index, const InlineBasicString<T, kOtherCapacity>& string) {
208  return insert(index, string.data(), string.size());
209}
210
211template <size_t kOtherCapacity>
212constexpr InlineBasicString& insert(
213    size_t index,
214    const InlineBasicString<T, kOtherCapacity>& other,
215    size_t other_index,
216    size_t count = npos) {
217  PW_ASSERT(other_index <= other.size());
218  if (count == npos || count > other.size() - other_index) {
219    count = other.size() - other_index;
220  }
221  PW_ASSERT(index <= index + count);
222  MoveExtend(data(), index, index + count);
223  return static_cast<InlineBasicString&>(CopyExtendSubstr(
224      data(), index, other.data(), other.size(), other_index, count));
225}
226
227// Use a templated type rather than `const_iterator` to convince the compiler
228// to prefer `0` as an index rather than as a `nullptr`.
229template <typename U>
230constexpr iterator insert(const U* pos, size_t count, T ch) {
231  PW_ASSERT(cbegin() <= pos && pos <= cend());
232  size_t index = static_cast<size_t>(pos - cbegin());
233  PW_ASSERT(index <= index + count);
234  MoveExtend(data(), index, index + count);
235  FillExtend(data(), index, ch, count);
236  return begin() + index;
237}
238
239template <typename U>
240constexpr iterator insert(const U* pos, T ch) {
241  return insert(pos, 1, ch);
242}
243
244template <typename U, class InputIt>
245constexpr iterator insert(const U* pos, InputIt first, InputIt last) {
246  PW_ASSERT(cbegin() <= pos && pos <= cend());
247  size_t index = static_cast<size_t>(pos - cbegin());
248  size_t count = 0;
249  for (auto tmp = first; tmp != last; ++tmp) {
250    PW_ASSERT(count < max_size());
251    ++count;
252  }
253  PW_ASSERT(index <= index + count);
254  MoveExtend(data(), index, index + count);
255  CopyIteratorExtend(data(), index, first, last);
256  return begin() + index;
257}
258
259template <typename U>
260constexpr iterator insert(const U* pos, std::initializer_list<T> list) {
261  return insert(pos, list.begin(), list.end());
262}
263
264template <typename StringView,
265          typename = string_impl::EnableIfStringViewLike<T, StringView>>
266constexpr InlineBasicString& insert(size_t index,
267                                    const StringView& string,
268                                    size_t string_index,
269                                    size_t count = npos) {
270  const string_impl::View<T> view = string;
271  PW_ASSERT(view.size() < npos);
272  PW_ASSERT(string_index <= view.size());
273  if (count == npos || count > view.size() - string_index) {
274    count = view.size() - string_index;
275  }
276  PW_ASSERT(index <= index + count);
277  MoveExtend(data(), index, index + count);
278  return static_cast<InlineBasicString&>(CopyExtendSubstr(
279      data(), index, view.data(), view.size(), string_index, count));
280}
281
282template <typename StringView,
283          typename = string_impl::EnableIfStringViewLike<T, StringView>>
284constexpr InlineBasicString& insert(size_t index, const StringView& string) {
285  return insert(index, string, 0);
286}
287
288constexpr InlineBasicString& erase(size_t index = 0, size_t count = npos) {
289  PW_ASSERT(index <= size());
290  size_t old_index =
291      index + std::min(count == npos ? size() : count, size() - index);
292  return static_cast<InlineBasicString&>(MoveExtend(data(), old_index, index));
293}
294
295// Use a templated type rather than `const_iterator` to convince the compiler
296// to prefer `0` as an index rather than as a `nullptr`.
297template <typename U>
298constexpr iterator erase(const U* pos) {
299  PW_ASSERT(cbegin() <= pos && pos <= cend());
300  size_t index = static_cast<size_t>(pos - cbegin());
301  size_t old_index = index + 1;
302  if (old_index <= size()) {
303    MoveExtend(data(), old_index, index);
304  }
305  return old_index <= size() ? begin() + index : end();
306}
307
308template <typename U>
309constexpr iterator erase(const U* first, const U* last) {
310  PW_ASSERT(cbegin() <= first && first <= cend());
311  size_t old_index =
312      first == cend() ? size() : static_cast<size_t>(first - cbegin());
313  size_t index = old_index;
314  for (auto tmp = first; tmp != last; ++tmp) {
315    PW_ASSERT(index < size());
316    ++old_index;
317  }
318  MoveExtend(data(), old_index, index);
319  return old_index <= size() ? begin() + index : end();
320}
321
322constexpr void push_back(value_type ch) {
323  static_assert(kCapacity != 0,
324                "Cannot add a character to pw::InlineString<0>");
325  PushBack(data(), ch);
326}
327
328constexpr void pop_back() {
329  static_assert(kCapacity != 0,
330                "Cannot remove a character from pw::InlineString<0>");
331  PopBack(data());
332}
333
334constexpr InlineBasicString& append(size_t count, T ch) {
335  return static_cast<InlineBasicString&>(FillExtend(data(), size(), ch, count));
336}
337
338template <size_t kOtherCapacity>
339constexpr InlineBasicString& append(
340    const InlineBasicString<T, kOtherCapacity>& string) {
341  static_assert(
342      kOtherCapacity == string_impl::kGeneric || kOtherCapacity <= kCapacity,
343      _PW_STRING_CAPACITY_TOO_SMALL_FOR_STRING);
344  return append(string.data(), string.size());
345}
346
347template <size_t kOtherCapacity>
348constexpr InlineBasicString& append(
349    const InlineBasicString<T, kOtherCapacity>& other,
350    size_t index,
351    size_t count = npos) {
352  return static_cast<InlineBasicString&>(CopyExtendSubstr(
353      data(), size(), other.data(), other.size(), index, count));
354}
355
356constexpr InlineBasicString& append(const T* string, size_t count) {
357  return static_cast<InlineBasicString&>(
358      CopyExtend(data(), size(), string, count));
359}
360
361template <size_t kCharArraySize>
362constexpr InlineBasicString& append(const T (&array)[kCharArraySize]) {
363  static_assert(
364      string_impl::NullTerminatedArrayFitsInString(kCharArraySize, kCapacity),
365      _PW_STRING_CAPACITY_TOO_SMALL_FOR_ARRAY);
366  return append(array, string_impl::ArrayStringLength(array, max_size()));
367}
368
369template <typename U, typename = string_impl::EnableIfNonArrayCharPointer<T, U>>
370constexpr InlineBasicString& append(U c_string) {
371  return append(c_string,
372                string_impl::BoundedStringLength(c_string, max_size()));
373}
374
375template <typename InputIterator,
376          typename = string_impl::EnableIfInputIterator<InputIterator>>
377constexpr InlineBasicString& append(InputIterator first, InputIterator last) {
378  return static_cast<InlineBasicString&>(
379      CopyIteratorExtend(data(), size(), first, last));
380}
381
382constexpr InlineBasicString& append(std::initializer_list<T> list) {
383  return append(list.begin(), list.size());
384}
385
386template <typename StringView,
387          typename = string_impl::EnableIfStringViewLike<T, StringView>>
388constexpr InlineBasicString& append(const StringView& string) {
389  const string_impl::View<T> view = string;
390  PW_ASSERT(view.size() < npos);
391  return append(view.data(), view.size());
392}
393
394template <typename StringView,
395          typename = string_impl::EnableIfStringViewLike<T, StringView>>
396constexpr InlineBasicString& append(const StringView& string,
397                                    size_t index,
398                                    size_t count = npos) {
399  const string_impl::View<T> view = string;
400  PW_ASSERT(view.size() < npos);
401  return static_cast<InlineBasicString&>(
402      CopyExtendSubstr(data(), size(), view.data(), view.size(), index, count));
403}
404
405template <size_t kOtherCapacity>
406constexpr int compare(
407    const InlineBasicString<T, kOtherCapacity>& other) const noexcept {
408  return string_impl::Compare(data(), size(), other.data(), other.size());
409}
410
411constexpr int compare(const T* other) const {
412  return string_impl::Compare(
413      data(),
414      size(),
415      other,
416      string_impl::BoundedStringLength(other, max_size()));
417}
418
419// TODO: b/239996007 - Implement other compare overloads.
420
421// TODO: b/239996007 - Implement other std::string functions:
422//
423//   - starts_with
424//   - ends_with
425//   - replace
426//   - substr
427//   - copy
428
429constexpr void resize(size_t new_size) { resize(new_size, T()); }
430
431constexpr void resize(size_t new_size, T ch) {
432  return Resize(data(), new_size, ch);
433}
434
435// resize_and_overwrite() only takes the callable object since the underlying
436// buffer has a fixed size.
437template <typename Operation>
438constexpr void resize_and_overwrite(Operation operation) {
439  const auto new_size =
440      static_cast<size_t>(std::move(operation)(data(), max_size()));
441  PW_ASSERT(new_size <= max_size());
442  SetSizeAndTerminate(data(), new_size);
443}
444
445// TODO: b/239996007 - Implement swap
446
447// Search
448
449// TODO: b/239996007 - Implement std::string search functions:
450//
451// - find
452// - rfind
453// - find_first_of
454// - find_first_not_of
455// - find_last_of
456// - find_last_not_of
457
458PW_MODIFY_DIAGNOSTICS_POP();
459