From 3ea65200d82a59530ed94136c8fb8baa9461d69c Mon Sep 17 00:00:00 2001 From: Max Wipfli Date: Thu, 1 Jul 2021 13:45:59 +0200 Subject: [PATCH] AK: Implement StringView::to_{lower,upper}case_string This patch refactors StringImpl::to_{lower,upper}case to use the new static methods StringImpl::create_{lower,upper}cased if they have to use to create a new StringImpl. This allows implementing StringView's to_{lower,upper}case_string using the same methods. It also replaces the usage of hand-written to_ascii_lowercase() and similar methods with those from CharacterTypes.h. --- AK/StringImpl.cpp | 61 +++++++++++++++++++---------------------------- AK/StringImpl.h | 3 +++ AK/StringView.cpp | 10 ++++++++ AK/StringView.h | 3 +++ 4 files changed, 41 insertions(+), 36 deletions(-) diff --git a/AK/StringImpl.cpp b/AK/StringImpl.cpp index b7639b11eee..3af1ce1eaca 100644 --- a/AK/StringImpl.cpp +++ b/AK/StringImpl.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include @@ -90,60 +91,48 @@ RefPtr StringImpl::create(ReadonlyBytes bytes, ShouldChomp shouldCho return StringImpl::create(reinterpret_cast(bytes.data()), bytes.size(), shouldChomp); } -static inline bool is_ascii_lowercase(char c) +RefPtr StringImpl::create_lowercased(char const* cstring, size_t length) { - return c >= 'a' && c <= 'z'; + if (!cstring) + return nullptr; + if (!length) + return the_empty_stringimpl(); + char* buffer; + auto impl = create_uninitialized(length, buffer); + for (size_t i = 0; i < length; ++i) + buffer[i] = (char)to_ascii_lowercase(cstring[i]); + return impl; } -static inline bool is_ascii_uppercase(char c) +RefPtr StringImpl::create_uppercased(char const* cstring, size_t length) { - return c >= 'A' && c <= 'Z'; -} - -static inline char to_ascii_lowercase(char c) -{ - if (is_ascii_uppercase(c)) - return c | 0x20; - return c; -} - -static inline char to_ascii_uppercase(char c) -{ - if (is_ascii_lowercase(c)) - return c & ~0x20; - return c; + if (!cstring) + return nullptr; + if (!length) + return the_empty_stringimpl(); + char* buffer; + auto impl = create_uninitialized(length, buffer); + for (size_t i = 0; i < length; ++i) + buffer[i] = (char)to_ascii_uppercase(cstring[i]); + return impl; } NonnullRefPtr StringImpl::to_lowercase() const { for (size_t i = 0; i < m_length; ++i) { - if (!is_ascii_lowercase(characters()[i])) - goto slow_path; + if (is_ascii_upper_alpha(characters()[i])) + return create_lowercased(characters(), m_length).release_nonnull(); } return const_cast(*this); - -slow_path: - char* buffer; - auto lowercased = create_uninitialized(m_length, buffer); - for (size_t i = 0; i < m_length; ++i) - buffer[i] = to_ascii_lowercase(characters()[i]); - return lowercased; } NonnullRefPtr StringImpl::to_uppercase() const { for (size_t i = 0; i < m_length; ++i) { - if (!is_ascii_uppercase(characters()[i])) - goto slow_path; + if (is_ascii_lower_alpha(characters()[i])) + return create_uppercased(characters(), m_length).release_nonnull(); } return const_cast(*this); - -slow_path: - char* buffer; - auto uppercased = create_uninitialized(m_length, buffer); - for (size_t i = 0; i < m_length; ++i) - buffer[i] = to_ascii_uppercase(characters()[i]); - return uppercased; } void StringImpl::compute_hash() const diff --git a/AK/StringImpl.h b/AK/StringImpl.h index e84fa014329..219abdd5390 100644 --- a/AK/StringImpl.h +++ b/AK/StringImpl.h @@ -26,6 +26,9 @@ public: static RefPtr create(const char* cstring, ShouldChomp = NoChomp); static RefPtr create(const char* cstring, size_t length, ShouldChomp = NoChomp); static RefPtr create(ReadonlyBytes, ShouldChomp = NoChomp); + static RefPtr create_lowercased(char const* cstring, size_t length); + static RefPtr create_uppercased(char const* cstring, size_t length); + NonnullRefPtr to_lowercase() const; NonnullRefPtr to_uppercase() const; diff --git a/AK/StringView.cpp b/AK/StringView.cpp index fe74bc9fd24..9053a6d1312 100644 --- a/AK/StringView.cpp +++ b/AK/StringView.cpp @@ -173,6 +173,16 @@ bool StringView::equals_ignoring_case(const StringView& other) const return StringUtils::equals_ignoring_case(*this, other); } +String StringView::to_lowercase_string() const +{ + return StringImpl::create_lowercased(characters_without_null_termination(), length()); +} + +String StringView::to_uppercase_string() const +{ + return StringImpl::create_uppercased(characters_without_null_termination(), length()); +} + StringView StringView::substring_view_starting_from_substring(const StringView& substring) const { const char* remaining_characters = substring.characters_without_null_termination(); diff --git a/AK/StringView.h b/AK/StringView.h index 6cf0092ad45..356f65f8f20 100644 --- a/AK/StringView.h +++ b/AK/StringView.h @@ -83,6 +83,9 @@ public: [[nodiscard]] StringView trim(const StringView& characters, TrimMode mode = TrimMode::Both) const { return StringUtils::trim(*this, characters, mode); } [[nodiscard]] StringView trim_whitespace(TrimMode mode = TrimMode::Both) const { return StringUtils::trim_whitespace(*this, mode); } + [[nodiscard]] String to_lowercase_string() const; + [[nodiscard]] String to_uppercase_string() const; + Optional find_first_of(char) const; Optional find_first_of(const StringView&) const;