// Copyright 2022 The Pigweed Authors // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. // This file contains the definitions of most pw::InlineBasicString functions. // The file is included inline in the fixed-capacity pw::InlineBasicString and generic-capacity pw::InlineBasicString specialization // classes. // // These functions cannot simply be defined in the pw::InlineBasicString base // class because: // // 1. Many functions return a *this reference. The functions should to return // a reference to the exact type they are called on rather than the // generic-capacity base class. // 2. Operations on the generic base class cannot be constexpr unless the // class is an InlineBasicString. The functions must be defined in // the fixed-capacity dervied classes to support constexpr operations. // // These functions have no logic and simply defer to shared, length-agnostic // implementations so they do not increase code size. PW_MODIFY_DIAGNOSTICS_PUSH(); PW_MODIFY_DIAGNOSTIC_GCC(ignored, "-Wtype-limits"); // Assignment functions constexpr InlineBasicString& assign(size_t count, T ch) { return static_cast(Fill(data(), ch, count)); } // Checks capacity rather than current size. template constexpr InlineBasicString& assign( const InlineBasicString& other) { static_assert( kOtherCapacity == string_impl::kGeneric || kOtherCapacity <= kCapacity, _PW_STRING_CAPACITY_TOO_SMALL_FOR_STRING); return static_cast( Copy(data(), other.data(), other.size())); } constexpr InlineBasicString& assign(const InlineBasicString& other, size_t index, size_t count = npos) { return static_cast( CopySubstr(data(), other.data(), other.size(), index, count)); } constexpr InlineBasicString& assign(const T* string, size_t count) { return static_cast(Copy(data(), string, count)); } template > constexpr InlineBasicString& assign(U c_string) { return assign(c_string, string_impl::BoundedStringLength(c_string, max_size())); } // Assignment from character array or string literal. For known-size strings, // the capacity is checked against the string/array size at compile time. template constexpr InlineBasicString& assign(const T (&array)[kCharArraySize]) { static_assert( string_impl::NullTerminatedArrayFitsInString(kCharArraySize, kCapacity), _PW_STRING_CAPACITY_TOO_SMALL_FOR_ARRAY); return static_cast( Copy(data(), array, string_impl::ArrayStringLength(array, max_size()))); } template > constexpr InlineBasicString& assign(InputIterator start, InputIterator finish) { return static_cast(CopyIterator(data(), start, finish)); } constexpr InlineBasicString& assign(std::initializer_list list) { return assign(list.begin(), list.size()); } template > constexpr InlineBasicString& assign(const StringView& string) { const string_impl::View view = string; PW_ASSERT(view.size() < npos); return assign(view.data(), view.size()); } template > constexpr InlineBasicString& assign(const StringView& string, size_t index, size_t count = npos) { const string_impl::View view = string; PW_ASSERT(view.size() < npos); return static_cast( CopySubstr(data(), view.data(), view.size(), index, count)); } constexpr InlineBasicString& assign(std::nullptr_t) = delete; // Element access constexpr reference at(size_t index) { PW_ASSERT(index < length()); return data()[index]; } constexpr const_reference at(size_t index) const { PW_ASSERT(index < length()); return data()[index]; } constexpr reference operator[](size_t index) { return data()[index]; } constexpr const_reference operator[](size_t index) const { return data()[index]; } constexpr reference front() { return data()[0]; } constexpr const_reference front() const { return data()[0]; } constexpr reference back() { return data()[size() - 1]; } constexpr const_reference back() const { return data()[size() - 1]; } constexpr const_pointer c_str() const noexcept { return data(); } constexpr operator string_impl::View() const noexcept { return string_impl::View(data(), size()); } // Iterators constexpr iterator begin() noexcept { return &data()[0]; } constexpr const_iterator begin() const noexcept { return &data()[0]; } constexpr const_iterator cbegin() const noexcept { return &data()[0]; } constexpr iterator end() noexcept { return &data()[size()]; } constexpr const_iterator end() const noexcept { return &data()[size()]; } constexpr const_iterator cend() const noexcept { return &data()[size()]; } constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } constexpr const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } constexpr const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(cend()); } constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); } constexpr const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } constexpr const_reverse_iterator crend() const noexcept { return const_reverse_iterator(cbegin()); } // Capacity [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0u; } // The number of characters in the string. constexpr size_t length() const noexcept { return size(); } constexpr size_t capacity() const noexcept { return max_size(); } // Operations constexpr void clear() { SetSizeAndTerminate(data(), 0); } constexpr InlineBasicString& insert(size_t index, size_t count, T ch) { MoveExtend(data(), index, index + count); return static_cast(FillExtend(data(), index, ch, count)); } constexpr InlineBasicString& insert(size_t index, const T* string, size_t count) { MoveExtend(data(), index, index + count); return static_cast( CopyExtend(data(), index, string, count)); } template constexpr InlineBasicString& insert(size_t index, const T (&array)[kCharArraySize]) { return insert( index, array, string_impl::ArrayStringLength(array, max_size())); } template > constexpr InlineBasicString& insert(size_t index, U c_string) { return insert( index, c_string, string_impl::BoundedStringLength(c_string, max_size())); } template constexpr InlineBasicString& insert( size_t index, const InlineBasicString& string) { return insert(index, string.data(), string.size()); } template constexpr InlineBasicString& insert( size_t index, const InlineBasicString& other, size_t other_index, size_t count = npos) { PW_ASSERT(other_index <= other.size()); if (count == npos || count > other.size() - other_index) { count = other.size() - other_index; } PW_ASSERT(index <= index + count); MoveExtend(data(), index, index + count); return static_cast(CopyExtendSubstr( data(), index, other.data(), other.size(), other_index, count)); } // Use a templated type rather than `const_iterator` to convince the compiler // to prefer `0` as an index rather than as a `nullptr`. template constexpr iterator insert(const U* pos, size_t count, T ch) { PW_ASSERT(cbegin() <= pos && pos <= cend()); size_t index = static_cast(pos - cbegin()); PW_ASSERT(index <= index + count); MoveExtend(data(), index, index + count); FillExtend(data(), index, ch, count); return begin() + index; } template constexpr iterator insert(const U* pos, T ch) { return insert(pos, 1, ch); } template constexpr iterator insert(const U* pos, InputIt first, InputIt last) { PW_ASSERT(cbegin() <= pos && pos <= cend()); size_t index = static_cast(pos - cbegin()); size_t count = 0; for (auto tmp = first; tmp != last; ++tmp) { PW_ASSERT(count < max_size()); ++count; } PW_ASSERT(index <= index + count); MoveExtend(data(), index, index + count); CopyIteratorExtend(data(), index, first, last); return begin() + index; } template constexpr iterator insert(const U* pos, std::initializer_list list) { return insert(pos, list.begin(), list.end()); } template > constexpr InlineBasicString& insert(size_t index, const StringView& string, size_t string_index, size_t count = npos) { const string_impl::View view = string; PW_ASSERT(view.size() < npos); PW_ASSERT(string_index <= view.size()); if (count == npos || count > view.size() - string_index) { count = view.size() - string_index; } PW_ASSERT(index <= index + count); MoveExtend(data(), index, index + count); return static_cast(CopyExtendSubstr( data(), index, view.data(), view.size(), string_index, count)); } template > constexpr InlineBasicString& insert(size_t index, const StringView& string) { return insert(index, string, 0); } constexpr InlineBasicString& erase(size_t index = 0, size_t count = npos) { PW_ASSERT(index <= size()); size_t old_index = index + std::min(count == npos ? size() : count, size() - index); return static_cast(MoveExtend(data(), old_index, index)); } // Use a templated type rather than `const_iterator` to convince the compiler // to prefer `0` as an index rather than as a `nullptr`. template constexpr iterator erase(const U* pos) { PW_ASSERT(cbegin() <= pos && pos <= cend()); size_t index = static_cast(pos - cbegin()); size_t old_index = index + 1; if (old_index <= size()) { MoveExtend(data(), old_index, index); } return old_index <= size() ? begin() + index : end(); } template constexpr iterator erase(const U* first, const U* last) { PW_ASSERT(cbegin() <= first && first <= cend()); size_t old_index = first == cend() ? size() : static_cast(first - cbegin()); size_t index = old_index; for (auto tmp = first; tmp != last; ++tmp) { PW_ASSERT(index < size()); ++old_index; } MoveExtend(data(), old_index, index); return old_index <= size() ? begin() + index : end(); } constexpr void push_back(value_type ch) { static_assert(kCapacity != 0, "Cannot add a character to pw::InlineString<0>"); PushBack(data(), ch); } constexpr void pop_back() { static_assert(kCapacity != 0, "Cannot remove a character from pw::InlineString<0>"); PopBack(data()); } constexpr InlineBasicString& append(size_t count, T ch) { return static_cast(FillExtend(data(), size(), ch, count)); } template constexpr InlineBasicString& append( const InlineBasicString& string) { static_assert( kOtherCapacity == string_impl::kGeneric || kOtherCapacity <= kCapacity, _PW_STRING_CAPACITY_TOO_SMALL_FOR_STRING); return append(string.data(), string.size()); } template constexpr InlineBasicString& append( const InlineBasicString& other, size_t index, size_t count = npos) { return static_cast(CopyExtendSubstr( data(), size(), other.data(), other.size(), index, count)); } constexpr InlineBasicString& append(const T* string, size_t count) { return static_cast( CopyExtend(data(), size(), string, count)); } template constexpr InlineBasicString& append(const T (&array)[kCharArraySize]) { static_assert( string_impl::NullTerminatedArrayFitsInString(kCharArraySize, kCapacity), _PW_STRING_CAPACITY_TOO_SMALL_FOR_ARRAY); return append(array, string_impl::ArrayStringLength(array, max_size())); } template > constexpr InlineBasicString& append(U c_string) { return append(c_string, string_impl::BoundedStringLength(c_string, max_size())); } template > constexpr InlineBasicString& append(InputIterator first, InputIterator last) { return static_cast( CopyIteratorExtend(data(), size(), first, last)); } constexpr InlineBasicString& append(std::initializer_list list) { return append(list.begin(), list.size()); } template > constexpr InlineBasicString& append(const StringView& string) { const string_impl::View view = string; PW_ASSERT(view.size() < npos); return append(view.data(), view.size()); } template > constexpr InlineBasicString& append(const StringView& string, size_t index, size_t count = npos) { const string_impl::View view = string; PW_ASSERT(view.size() < npos); return static_cast( CopyExtendSubstr(data(), size(), view.data(), view.size(), index, count)); } template constexpr int compare( const InlineBasicString& other) const noexcept { return string_impl::Compare(data(), size(), other.data(), other.size()); } constexpr int compare(const T* other) const { return string_impl::Compare( data(), size(), other, string_impl::BoundedStringLength(other, max_size())); } // TODO: b/239996007 - Implement other compare overloads. // TODO: b/239996007 - Implement other std::string functions: // // - starts_with // - ends_with // - replace // - substr // - copy constexpr void resize(size_t new_size) { resize(new_size, T()); } constexpr void resize(size_t new_size, T ch) { return Resize(data(), new_size, ch); } // resize_and_overwrite() only takes the callable object since the underlying // buffer has a fixed size. template constexpr void resize_and_overwrite(Operation operation) { const auto new_size = static_cast(std::move(operation)(data(), max_size())); PW_ASSERT(new_size <= max_size()); SetSizeAndTerminate(data(), new_size); } // TODO: b/239996007 - Implement swap // Search // TODO: b/239996007 - Implement std::string search functions: // // - find // - rfind // - find_first_of // - find_first_not_of // - find_last_of // - find_last_not_of PW_MODIFY_DIAGNOSTICS_POP();