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_type count, T ch) { 39 return static_cast<InlineBasicString&>(Fill(data(), ch, count)); 40} 41 42// Checks capacity rather than current size. 43template <size_type 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_type index, 55 size_type 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_type 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&>( 85 IteratorCopy(start, finish, data(), data() + max_size())); 86} 87 88constexpr InlineBasicString& assign(std::initializer_list<T> list) { 89 return assign(list.begin(), list.size()); 90} 91 92#if PW_CXX_STANDARD_IS_SUPPORTED(17) // std::string_view is a C++17 feature 93 94template <typename StringView, 95 typename = string_impl::EnableIfStringViewLike<T, StringView>> 96constexpr InlineBasicString& assign(const StringView& string) { 97 const std::basic_string_view<T> view = string; 98 PW_ASSERT(view.size() < npos); 99 return assign(view.data(), view.size()); 100} 101 102template <typename StringView, 103 typename = string_impl::EnableIfStringViewLike<T, StringView>> 104constexpr InlineBasicString& assign(const StringView& string, 105 size_type index, 106 size_type count = npos) { 107 const std::basic_string_view<T> view = string; 108 PW_ASSERT(view.size() < npos); 109 return static_cast<InlineBasicString&>(CopySubstr( 110 data(), view.data(), static_cast<size_type>(view.size()), index, count)); 111} 112 113#endif // PW_CXX_STANDARD_IS_SUPPORTED(17) 114 115constexpr InlineBasicString& assign(std::nullptr_t) = delete; 116 117// Element access 118 119constexpr reference at(size_type index) { 120 PW_ASSERT(index < length()); 121 return data()[index]; 122} 123constexpr const_reference at(size_type index) const { 124 PW_ASSERT(index < length()); 125 return data()[index]; 126} 127 128constexpr reference operator[](size_type index) { return data()[index]; } 129constexpr const_reference operator[](size_type index) const { 130 return data()[index]; 131} 132 133constexpr reference front() { return data()[0]; } 134constexpr const_reference front() const { return data()[0]; } 135 136constexpr reference back() { return data()[size() - 1]; } 137constexpr const_reference back() const { return data()[size() - 1]; } 138 139constexpr const_pointer c_str() const noexcept { return data(); } 140 141constexpr operator std::basic_string_view<T>() const noexcept { 142 return std::basic_string_view<T>(data(), size()); 143} 144 145// Iterators 146 147constexpr iterator begin() noexcept { return &data()[0]; } 148constexpr const_iterator begin() const noexcept { return &data()[0]; } 149constexpr const_iterator cbegin() const noexcept { return &data()[0]; } 150 151constexpr iterator end() noexcept { return &data()[size()]; } 152constexpr const_iterator end() const noexcept { return &data()[size()]; } 153constexpr const_iterator cend() const noexcept { return &data()[size()]; } 154 155constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } 156constexpr const_reverse_iterator rbegin() const noexcept { 157 return const_reverse_iterator(end()); 158} 159constexpr const_reverse_iterator crbegin() const noexcept { 160 return const_reverse_iterator(cend()); 161} 162 163constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); } 164constexpr const_reverse_iterator rend() const noexcept { 165 return const_reverse_iterator(begin()); 166} 167constexpr const_reverse_iterator crend() const noexcept { 168 return const_reverse_iterator(cbegin()); 169} 170 171// Capacity 172 173[[nodiscard]] constexpr bool empty() const noexcept { return size() == 0u; } 174 175// The number of characters in the string. 176constexpr size_type length() const noexcept { return size(); } 177 178constexpr size_type capacity() const noexcept { return max_size(); } 179 180// Operations 181 182constexpr void clear() { SetSizeAndTerminate(data(), 0); } 183 184// TODO(b/239996007): Implement insert and erase. 185 186constexpr void push_back(value_type ch) { 187 static_assert(kCapacity != 0, 188 "Cannot add a character to pw::InlineString<0>"); 189 PushBack(data(), ch); 190} 191 192constexpr void pop_back() { 193 static_assert(kCapacity != 0, 194 "Cannot remove a character from pw::InlineString<0>"); 195 PopBack(data()); 196} 197 198constexpr InlineBasicString& append(size_type count, T ch) { 199 return static_cast<InlineBasicString&>(FillExtend(data(), ch, count)); 200} 201 202template <size_type kOtherCapacity> 203constexpr InlineBasicString& append( 204 const InlineBasicString<T, kOtherCapacity>& string) { 205 static_assert( 206 kOtherCapacity == string_impl::kGeneric || kOtherCapacity <= kCapacity, 207 _PW_STRING_CAPACITY_TOO_SMALL_FOR_STRING); 208 return append(string.data(), string.size()); 209} 210 211template <size_type kOtherCapacity> 212constexpr InlineBasicString& append( 213 const InlineBasicString<T, kOtherCapacity>& other, 214 size_type index, 215 size_type count = npos) { 216 return static_cast<InlineBasicString&>( 217 CopyExtendSubstr(data(), other.data(), other.size(), index, count)); 218} 219 220constexpr InlineBasicString& append(const T* string, size_type count) { 221 return static_cast<InlineBasicString&>(CopyExtend(data(), string, count)); 222} 223 224template <size_t kCharArraySize> 225constexpr InlineBasicString& append(const T (&array)[kCharArraySize]) { 226 static_assert( 227 string_impl::NullTerminatedArrayFitsInString(kCharArraySize, kCapacity), 228 _PW_STRING_CAPACITY_TOO_SMALL_FOR_ARRAY); 229 return append(array, string_impl::ArrayStringLength(array, max_size())); 230} 231 232template <typename U, typename = string_impl::EnableIfNonArrayCharPointer<T, U>> 233constexpr InlineBasicString& append(U c_string) { 234 return append(c_string, 235 string_impl::BoundedStringLength(c_string, max_size())); 236} 237 238template <typename InputIterator, 239 typename = string_impl::EnableIfInputIterator<InputIterator>> 240constexpr InlineBasicString& append(InputIterator first, InputIterator last) { 241 return static_cast<InlineBasicString&>( 242 IteratorExtend(first, last, data() + size(), data() + max_size())); 243} 244 245constexpr InlineBasicString& append(std::initializer_list<T> list) { 246 return append(list.begin(), list.size()); 247} 248 249#if PW_CXX_STANDARD_IS_SUPPORTED(17) // std::string_view is a C++17 feature 250 251template <typename StringView, 252 typename = string_impl::EnableIfStringViewLike<T, StringView>> 253constexpr InlineBasicString& append(const StringView& string) { 254 const std::basic_string_view<T> view = string; 255 PW_ASSERT(view.size() < npos); 256 return append(view.data(), view.size()); 257} 258 259template <typename StringView, 260 typename = string_impl::EnableIfStringViewLike<T, StringView>> 261constexpr InlineBasicString& append(const StringView& string, 262 size_type index, 263 size_type count = npos) { 264 const std::basic_string_view<T> view = string; 265 PW_ASSERT(view.size() < npos); 266 return static_cast<InlineBasicString&>(CopyExtendSubstr( 267 data(), view.data(), static_cast<size_type>(view.size()), index, count)); 268} 269 270#endif // PW_CXX_STANDARD_IS_SUPPORTED(17) 271 272template <size_type kOtherCapacity> 273constexpr int compare( 274 const InlineBasicString<T, kOtherCapacity>& other) const noexcept { 275 return string_impl::Compare(data(), size(), other.data(), other.size()); 276} 277 278constexpr int compare(const T* other) const { 279 return string_impl::Compare( 280 data(), 281 size(), 282 other, 283 string_impl::BoundedStringLength(other, max_size())); 284} 285 286// TODO(b/239996007): Implement other compare overloads. 287 288// TODO(b/239996007): Implement other std::string functions: 289// 290// - starts_with 291// - ends_with 292// - replace 293// - substr 294// - copy 295 296constexpr void resize(size_type new_size) { resize(new_size, T()); } 297 298constexpr void resize(size_type new_size, T ch) { 299 return Resize(data(), new_size, ch); 300} 301 302// resize_and_overwrite() only takes the callable object since the underlying 303// buffer has a fixed size. 304template <typename Operation> 305constexpr void resize_and_overwrite(Operation operation) { 306 const auto new_size = std::move(operation)(data(), max_size()); 307 PW_ASSERT(static_cast<size_t>(new_size) <= max_size()); 308 SetSizeAndTerminate(data(), new_size); 309} 310 311// TODO(b/239996007): Implement swap 312 313// Search 314 315// TODO(b/239996007): Implement std::string search functions: 316// 317// - find 318// - rfind 319// - find_first_of 320// - find_first_not_of 321// - find_last_of 322// - find_last_not_of 323 324PW_MODIFY_DIAGNOSTICS_POP(); 325