AK: Simplify ASCII case conversion implementations a bit

* Use `any_of` instead of manual loops

* Don't check if a code point is upper/lowercase twice. The check we
  are using is already present inside the case converter.

* Move StringImpl's implementation into ByteString. ByteString is its
  only user, so let's avoid some jumping around. The other ASCII case
  methods on StringImpl will soon also be removed.
This commit is contained in:
Timothy Flynn 2025-04-06 09:45:05 -04:00
parent 25e343464d
commit a434d4b6c4
4 changed files with 31 additions and 53 deletions

View file

@ -6,6 +6,7 @@
#include <AK/ByteBuffer.h>
#include <AK/ByteString.h>
#include <AK/Enumerate.h>
#include <AK/FlyString.h>
#include <AK/Format.h>
#include <AK/Function.h>
@ -339,12 +340,30 @@ ByteString::ByteString(FlyString const& string)
ByteString ByteString::to_lowercase() const
{
return m_impl->to_lowercase();
if (!any_of(bytes(), is_ascii_upper_alpha))
return *this;
char* buffer = nullptr;
auto impl = StringImpl::create_uninitialized(length(), buffer);
for (auto [i, character] : enumerate(view()))
buffer[i] = static_cast<char>(to_ascii_lowercase(character));
return *impl;
}
ByteString ByteString::to_uppercase() const
{
return m_impl->to_uppercase();
if (!any_of(bytes(), is_ascii_lower_alpha))
return *this;
char* buffer = nullptr;
auto impl = StringImpl::create_uninitialized(length(), buffer);
for (auto [i, character] : enumerate(view()))
buffer[i] = static_cast<char>(to_ascii_uppercase(character));
return *impl;
}
ByteString ByteString::to_snakecase() const

View file

@ -374,49 +374,29 @@ ErrorOr<String> String::from_byte_string(ByteString const& byte_string)
String String::to_ascii_lowercase() const
{
bool const has_ascii_uppercase = [&] {
for (u8 const byte : bytes()) {
if (AK::is_ascii_upper_alpha(byte))
return true;
}
return false;
}();
if (!has_ascii_uppercase)
if (!any_of(bytes(), is_ascii_upper_alpha))
return *this;
Vector<u8> lowercase_bytes;
lowercase_bytes.ensure_capacity(bytes().size());
for (u8 const byte : bytes()) {
if (AK::is_ascii_upper_alpha(byte))
lowercase_bytes.unchecked_append(AK::to_ascii_lowercase(byte));
else
lowercase_bytes.unchecked_append(byte);
}
for (auto character : bytes_as_string_view())
lowercase_bytes.unchecked_append(AK::to_ascii_lowercase(character));
return String::from_utf8_without_validation(lowercase_bytes);
}
String String::to_ascii_uppercase() const
{
bool const has_ascii_lowercase = [&] {
for (u8 const byte : bytes()) {
if (AK::is_ascii_lower_alpha(byte))
return true;
}
return false;
}();
if (!has_ascii_lowercase)
if (!any_of(bytes(), is_ascii_lower_alpha))
return *this;
Vector<u8> uppercase_bytes;
uppercase_bytes.ensure_capacity(bytes().size());
for (u8 const byte : bytes()) {
if (AK::is_ascii_lower_alpha(byte))
uppercase_bytes.unchecked_append(AK::to_ascii_uppercase(byte));
else
uppercase_bytes.unchecked_append(byte);
}
for (auto character : bytes_as_string_view())
uppercase_bytes.unchecked_append(AK::to_ascii_uppercase(character));
return String::from_utf8_without_validation(uppercase_bytes);
}

View file

@ -97,24 +97,6 @@ RefPtr<StringImpl const> StringImpl::create_uppercased(char const* cstring, size
return impl;
}
NonnullRefPtr<StringImpl const> StringImpl::to_lowercase() const
{
for (size_t i = 0; i < m_length; ++i) {
if (is_ascii_upper_alpha(characters()[i]))
return create_lowercased(characters(), m_length).release_nonnull();
}
return const_cast<StringImpl&>(*this);
}
NonnullRefPtr<StringImpl const> StringImpl::to_uppercase() const
{
for (size_t i = 0; i < m_length; ++i) {
if (is_ascii_lower_alpha(characters()[i]))
return create_uppercased(characters(), m_length).release_nonnull();
}
return const_cast<StringImpl&>(*this);
}
unsigned StringImpl::case_insensitive_hash() const
{
return case_insensitive_string_hash(characters(), length());

View file

@ -31,9 +31,6 @@ public:
static RefPtr<StringImpl const> create_lowercased(char const* cstring, size_t length);
static RefPtr<StringImpl const> create_uppercased(char const* cstring, size_t length);
NonnullRefPtr<StringImpl const> to_lowercase() const;
NonnullRefPtr<StringImpl const> to_uppercase() const;
void operator delete(void* ptr)
{
kfree_sized(ptr, allocation_size_for_stringimpl(static_cast<StringImpl*>(ptr)->m_length));