// 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_type 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_type index, size_type count = npos) { return static_cast( CopySubstr(data(), other.data(), other.size(), index, count)); } constexpr InlineBasicString& assign(const T* string, size_type 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( IteratorCopy(start, finish, data(), data() + max_size())); } constexpr InlineBasicString& assign(std::initializer_list list) { return assign(list.begin(), list.size()); } #if PW_CXX_STANDARD_IS_SUPPORTED(17) // std::string_view is a C++17 feature template > constexpr InlineBasicString& assign(const StringView& string) { const std::basic_string_view view = string; PW_ASSERT(view.size() < npos); return assign(view.data(), view.size()); } template > constexpr InlineBasicString& assign(const StringView& string, size_type index, size_type count = npos) { const std::basic_string_view view = string; PW_ASSERT(view.size() < npos); return static_cast(CopySubstr( data(), view.data(), static_cast(view.size()), index, count)); } #endif // PW_CXX_STANDARD_IS_SUPPORTED(17) constexpr InlineBasicString& assign(std::nullptr_t) = delete; // Element access constexpr reference at(size_type index) { PW_ASSERT(index < length()); return data()[index]; } constexpr const_reference at(size_type index) const { PW_ASSERT(index < length()); return data()[index]; } constexpr reference operator[](size_type index) { return data()[index]; } constexpr const_reference operator[](size_type 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 std::basic_string_view() const noexcept { return std::basic_string_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_type length() const noexcept { return size(); } constexpr size_type capacity() const noexcept { return max_size(); } // Operations constexpr void clear() { SetSizeAndTerminate(data(), 0); } // TODO(b/239996007): Implement insert and erase. 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_type count, T ch) { return static_cast(FillExtend(data(), 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_type index, size_type count = npos) { return static_cast( CopyExtendSubstr(data(), other.data(), other.size(), index, count)); } constexpr InlineBasicString& append(const T* string, size_type count) { return static_cast(CopyExtend(data(), 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( IteratorExtend(first, last, data() + size(), data() + max_size())); } constexpr InlineBasicString& append(std::initializer_list list) { return append(list.begin(), list.size()); } #if PW_CXX_STANDARD_IS_SUPPORTED(17) // std::string_view is a C++17 feature template > constexpr InlineBasicString& append(const StringView& string) { const std::basic_string_view view = string; PW_ASSERT(view.size() < npos); return append(view.data(), view.size()); } template > constexpr InlineBasicString& append(const StringView& string, size_type index, size_type count = npos) { const std::basic_string_view view = string; PW_ASSERT(view.size() < npos); return static_cast(CopyExtendSubstr( data(), view.data(), static_cast(view.size()), index, count)); } #endif // PW_CXX_STANDARD_IS_SUPPORTED(17) 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_type new_size) { resize(new_size, T()); } constexpr void resize(size_type 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 = std::move(operation)(data(), max_size()); PW_ASSERT(static_cast(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();