AK: Introduce the new String, replacement for DeprecatedString
DeprecatedString (formerly String) has been with us since the start,
and it has served us well. However, it has a number of shortcomings
that I'd like to address.
Some of these issues are hard if not impossible to solve incrementally
inside of DeprecatedString, so instead of doing that, let's build a new
String class and then incrementally move over to it instead.
Problems in DeprecatedString:
- It assumes string allocation never fails. This makes it impossible
to use in allocation-sensitive contexts, and is the reason we had to
ban DeprecatedString from the kernel entirely.
- The awkward null state. DeprecatedString can be null. It's different
from the empty state, although null strings are considered empty.
All code is immediately nicer when using Optional<DeprecatedString>
but DeprecatedString came before Optional, which is how we ended up
like this.
- The encoding of the underlying data is ambiguous. For the most part,
we use it as if it's always UTF-8, but there have been cases where
we pass around strings in other encodings (e.g ISO8859-1)
- operator[] and length() are used to iterate over DeprecatedString one
byte at a time. This is done all over the codebase, and will *not*
give the right results unless the string is all ASCII.
How we solve these issues in the new String:
- Functions that may allocate now return ErrorOr<String> so that ENOMEM
errors can be passed to the caller.
- String has no null state. Use Optional<String> when needed.
- String is always UTF-8. This is validated when constructing a String.
We may need to add a bypass for this in the future, for cases where
you have a known-good string, but for now: validate all the things!
- There is no operator[] or length(). You can get the underlying data
with bytes(), but for iterating over code points, you should be using
an UTF-8 iterator.
Furthermore, it has two nifty new features:
- String implements a small string optimization (SSO) for strings that
can fit entirely within a pointer. This means up to 3 bytes on 32-bit
platforms, and 7 bytes on 64-bit platforms. Such small strings will
not be heap-allocated.
- String can create substrings without making a deep copy of the
substring. Instead, the superstring gets +1 refcount from the
substring, and it acts like a view into the superstring. To make
substrings like this, use the substring_with_shared_superstring() API.
One caveat:
- String does not guarantee that the underlying data is null-terminated
like DeprecatedString does today. While this was nifty in a handful of
places where we were calling C functions, it did stand in the way of
shared-superstring substrings.
2022-12-01 12:27:43 +00:00
|
|
|
/*
|
2024-10-04 11:19:50 +00:00
|
|
|
* Copyright (c) 2018-2022, Andreas Kling <andreas@ladybird.org>
|
AK: Introduce the new String, replacement for DeprecatedString
DeprecatedString (formerly String) has been with us since the start,
and it has served us well. However, it has a number of shortcomings
that I'd like to address.
Some of these issues are hard if not impossible to solve incrementally
inside of DeprecatedString, so instead of doing that, let's build a new
String class and then incrementally move over to it instead.
Problems in DeprecatedString:
- It assumes string allocation never fails. This makes it impossible
to use in allocation-sensitive contexts, and is the reason we had to
ban DeprecatedString from the kernel entirely.
- The awkward null state. DeprecatedString can be null. It's different
from the empty state, although null strings are considered empty.
All code is immediately nicer when using Optional<DeprecatedString>
but DeprecatedString came before Optional, which is how we ended up
like this.
- The encoding of the underlying data is ambiguous. For the most part,
we use it as if it's always UTF-8, but there have been cases where
we pass around strings in other encodings (e.g ISO8859-1)
- operator[] and length() are used to iterate over DeprecatedString one
byte at a time. This is done all over the codebase, and will *not*
give the right results unless the string is all ASCII.
How we solve these issues in the new String:
- Functions that may allocate now return ErrorOr<String> so that ENOMEM
errors can be passed to the caller.
- String has no null state. Use Optional<String> when needed.
- String is always UTF-8. This is validated when constructing a String.
We may need to add a bypass for this in the future, for cases where
you have a known-good string, but for now: validate all the things!
- There is no operator[] or length(). You can get the underlying data
with bytes(), but for iterating over code points, you should be using
an UTF-8 iterator.
Furthermore, it has two nifty new features:
- String implements a small string optimization (SSO) for strings that
can fit entirely within a pointer. This means up to 3 bytes on 32-bit
platforms, and 7 bytes on 64-bit platforms. Such small strings will
not be heap-allocated.
- String can create substrings without making a deep copy of the
substring. Instead, the superstring gets +1 refcount from the
substring, and it acts like a view into the superstring. To make
substrings like this, use the substring_with_shared_superstring() API.
One caveat:
- String does not guarantee that the underlying data is null-terminated
like DeprecatedString does today. While this was nifty in a handful of
places where we were calling C functions, it did stand in the way of
shared-superstring substrings.
2022-12-01 12:27:43 +00:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
*/
|
|
|
|
|
2023-01-22 15:17:48 +00:00
|
|
|
#include <AK/Array.h>
|
AK: Introduce the new String, replacement for DeprecatedString
DeprecatedString (formerly String) has been with us since the start,
and it has served us well. However, it has a number of shortcomings
that I'd like to address.
Some of these issues are hard if not impossible to solve incrementally
inside of DeprecatedString, so instead of doing that, let's build a new
String class and then incrementally move over to it instead.
Problems in DeprecatedString:
- It assumes string allocation never fails. This makes it impossible
to use in allocation-sensitive contexts, and is the reason we had to
ban DeprecatedString from the kernel entirely.
- The awkward null state. DeprecatedString can be null. It's different
from the empty state, although null strings are considered empty.
All code is immediately nicer when using Optional<DeprecatedString>
but DeprecatedString came before Optional, which is how we ended up
like this.
- The encoding of the underlying data is ambiguous. For the most part,
we use it as if it's always UTF-8, but there have been cases where
we pass around strings in other encodings (e.g ISO8859-1)
- operator[] and length() are used to iterate over DeprecatedString one
byte at a time. This is done all over the codebase, and will *not*
give the right results unless the string is all ASCII.
How we solve these issues in the new String:
- Functions that may allocate now return ErrorOr<String> so that ENOMEM
errors can be passed to the caller.
- String has no null state. Use Optional<String> when needed.
- String is always UTF-8. This is validated when constructing a String.
We may need to add a bypass for this in the future, for cases where
you have a known-good string, but for now: validate all the things!
- There is no operator[] or length(). You can get the underlying data
with bytes(), but for iterating over code points, you should be using
an UTF-8 iterator.
Furthermore, it has two nifty new features:
- String implements a small string optimization (SSO) for strings that
can fit entirely within a pointer. This means up to 3 bytes on 32-bit
platforms, and 7 bytes on 64-bit platforms. Such small strings will
not be heap-allocated.
- String can create substrings without making a deep copy of the
substring. Instead, the superstring gets +1 refcount from the
substring, and it acts like a view into the superstring. To make
substrings like this, use the substring_with_shared_superstring() API.
One caveat:
- String does not guarantee that the underlying data is null-terminated
like DeprecatedString does today. While this was nifty in a handful of
places where we were calling C functions, it did stand in the way of
shared-superstring substrings.
2022-12-01 12:27:43 +00:00
|
|
|
#include <AK/Checked.h>
|
2024-07-18 15:57:01 +00:00
|
|
|
#include <AK/Endian.h>
|
2023-01-11 13:26:49 +00:00
|
|
|
#include <AK/FlyString.h>
|
AK: Introduce the new String, replacement for DeprecatedString
DeprecatedString (formerly String) has been with us since the start,
and it has served us well. However, it has a number of shortcomings
that I'd like to address.
Some of these issues are hard if not impossible to solve incrementally
inside of DeprecatedString, so instead of doing that, let's build a new
String class and then incrementally move over to it instead.
Problems in DeprecatedString:
- It assumes string allocation never fails. This makes it impossible
to use in allocation-sensitive contexts, and is the reason we had to
ban DeprecatedString from the kernel entirely.
- The awkward null state. DeprecatedString can be null. It's different
from the empty state, although null strings are considered empty.
All code is immediately nicer when using Optional<DeprecatedString>
but DeprecatedString came before Optional, which is how we ended up
like this.
- The encoding of the underlying data is ambiguous. For the most part,
we use it as if it's always UTF-8, but there have been cases where
we pass around strings in other encodings (e.g ISO8859-1)
- operator[] and length() are used to iterate over DeprecatedString one
byte at a time. This is done all over the codebase, and will *not*
give the right results unless the string is all ASCII.
How we solve these issues in the new String:
- Functions that may allocate now return ErrorOr<String> so that ENOMEM
errors can be passed to the caller.
- String has no null state. Use Optional<String> when needed.
- String is always UTF-8. This is validated when constructing a String.
We may need to add a bypass for this in the future, for cases where
you have a known-good string, but for now: validate all the things!
- There is no operator[] or length(). You can get the underlying data
with bytes(), but for iterating over code points, you should be using
an UTF-8 iterator.
Furthermore, it has two nifty new features:
- String implements a small string optimization (SSO) for strings that
can fit entirely within a pointer. This means up to 3 bytes on 32-bit
platforms, and 7 bytes on 64-bit platforms. Such small strings will
not be heap-allocated.
- String can create substrings without making a deep copy of the
substring. Instead, the superstring gets +1 refcount from the
substring, and it acts like a view into the superstring. To make
substrings like this, use the substring_with_shared_superstring() API.
One caveat:
- String does not guarantee that the underlying data is null-terminated
like DeprecatedString does today. While this was nifty in a handful of
places where we were calling C functions, it did stand in the way of
shared-superstring substrings.
2022-12-01 12:27:43 +00:00
|
|
|
#include <AK/Format.h>
|
2023-01-27 15:17:34 +00:00
|
|
|
#include <AK/MemMem.h>
|
2023-02-20 01:34:29 +00:00
|
|
|
#include <AK/Stream.h>
|
AK: Introduce the new String, replacement for DeprecatedString
DeprecatedString (formerly String) has been with us since the start,
and it has served us well. However, it has a number of shortcomings
that I'd like to address.
Some of these issues are hard if not impossible to solve incrementally
inside of DeprecatedString, so instead of doing that, let's build a new
String class and then incrementally move over to it instead.
Problems in DeprecatedString:
- It assumes string allocation never fails. This makes it impossible
to use in allocation-sensitive contexts, and is the reason we had to
ban DeprecatedString from the kernel entirely.
- The awkward null state. DeprecatedString can be null. It's different
from the empty state, although null strings are considered empty.
All code is immediately nicer when using Optional<DeprecatedString>
but DeprecatedString came before Optional, which is how we ended up
like this.
- The encoding of the underlying data is ambiguous. For the most part,
we use it as if it's always UTF-8, but there have been cases where
we pass around strings in other encodings (e.g ISO8859-1)
- operator[] and length() are used to iterate over DeprecatedString one
byte at a time. This is done all over the codebase, and will *not*
give the right results unless the string is all ASCII.
How we solve these issues in the new String:
- Functions that may allocate now return ErrorOr<String> so that ENOMEM
errors can be passed to the caller.
- String has no null state. Use Optional<String> when needed.
- String is always UTF-8. This is validated when constructing a String.
We may need to add a bypass for this in the future, for cases where
you have a known-good string, but for now: validate all the things!
- There is no operator[] or length(). You can get the underlying data
with bytes(), but for iterating over code points, you should be using
an UTF-8 iterator.
Furthermore, it has two nifty new features:
- String implements a small string optimization (SSO) for strings that
can fit entirely within a pointer. This means up to 3 bytes on 32-bit
platforms, and 7 bytes on 64-bit platforms. Such small strings will
not be heap-allocated.
- String can create substrings without making a deep copy of the
substring. Instead, the superstring gets +1 refcount from the
substring, and it acts like a view into the superstring. To make
substrings like this, use the substring_with_shared_superstring() API.
One caveat:
- String does not guarantee that the underlying data is null-terminated
like DeprecatedString does today. While this was nifty in a handful of
places where we were calling C functions, it did stand in the way of
shared-superstring substrings.
2022-12-01 12:27:43 +00:00
|
|
|
#include <AK/String.h>
|
2024-07-16 20:05:46 +00:00
|
|
|
#include <AK/Utf16View.h>
|
2023-01-13 16:34:00 +00:00
|
|
|
#include <AK/Vector.h>
|
AK: Introduce the new String, replacement for DeprecatedString
DeprecatedString (formerly String) has been with us since the start,
and it has served us well. However, it has a number of shortcomings
that I'd like to address.
Some of these issues are hard if not impossible to solve incrementally
inside of DeprecatedString, so instead of doing that, let's build a new
String class and then incrementally move over to it instead.
Problems in DeprecatedString:
- It assumes string allocation never fails. This makes it impossible
to use in allocation-sensitive contexts, and is the reason we had to
ban DeprecatedString from the kernel entirely.
- The awkward null state. DeprecatedString can be null. It's different
from the empty state, although null strings are considered empty.
All code is immediately nicer when using Optional<DeprecatedString>
but DeprecatedString came before Optional, which is how we ended up
like this.
- The encoding of the underlying data is ambiguous. For the most part,
we use it as if it's always UTF-8, but there have been cases where
we pass around strings in other encodings (e.g ISO8859-1)
- operator[] and length() are used to iterate over DeprecatedString one
byte at a time. This is done all over the codebase, and will *not*
give the right results unless the string is all ASCII.
How we solve these issues in the new String:
- Functions that may allocate now return ErrorOr<String> so that ENOMEM
errors can be passed to the caller.
- String has no null state. Use Optional<String> when needed.
- String is always UTF-8. This is validated when constructing a String.
We may need to add a bypass for this in the future, for cases where
you have a known-good string, but for now: validate all the things!
- There is no operator[] or length(). You can get the underlying data
with bytes(), but for iterating over code points, you should be using
an UTF-8 iterator.
Furthermore, it has two nifty new features:
- String implements a small string optimization (SSO) for strings that
can fit entirely within a pointer. This means up to 3 bytes on 32-bit
platforms, and 7 bytes on 64-bit platforms. Such small strings will
not be heap-allocated.
- String can create substrings without making a deep copy of the
substring. Instead, the superstring gets +1 refcount from the
substring, and it acts like a view into the superstring. To make
substrings like this, use the substring_with_shared_superstring() API.
One caveat:
- String does not guarantee that the underlying data is null-terminated
like DeprecatedString does today. While this was nifty in a handful of
places where we were calling C functions, it did stand in the way of
shared-superstring substrings.
2022-12-01 12:27:43 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
2024-07-16 20:05:46 +00:00
|
|
|
#include <simdutf.h>
|
|
|
|
|
AK: Introduce the new String, replacement for DeprecatedString
DeprecatedString (formerly String) has been with us since the start,
and it has served us well. However, it has a number of shortcomings
that I'd like to address.
Some of these issues are hard if not impossible to solve incrementally
inside of DeprecatedString, so instead of doing that, let's build a new
String class and then incrementally move over to it instead.
Problems in DeprecatedString:
- It assumes string allocation never fails. This makes it impossible
to use in allocation-sensitive contexts, and is the reason we had to
ban DeprecatedString from the kernel entirely.
- The awkward null state. DeprecatedString can be null. It's different
from the empty state, although null strings are considered empty.
All code is immediately nicer when using Optional<DeprecatedString>
but DeprecatedString came before Optional, which is how we ended up
like this.
- The encoding of the underlying data is ambiguous. For the most part,
we use it as if it's always UTF-8, but there have been cases where
we pass around strings in other encodings (e.g ISO8859-1)
- operator[] and length() are used to iterate over DeprecatedString one
byte at a time. This is done all over the codebase, and will *not*
give the right results unless the string is all ASCII.
How we solve these issues in the new String:
- Functions that may allocate now return ErrorOr<String> so that ENOMEM
errors can be passed to the caller.
- String has no null state. Use Optional<String> when needed.
- String is always UTF-8. This is validated when constructing a String.
We may need to add a bypass for this in the future, for cases where
you have a known-good string, but for now: validate all the things!
- There is no operator[] or length(). You can get the underlying data
with bytes(), but for iterating over code points, you should be using
an UTF-8 iterator.
Furthermore, it has two nifty new features:
- String implements a small string optimization (SSO) for strings that
can fit entirely within a pointer. This means up to 3 bytes on 32-bit
platforms, and 7 bytes on 64-bit platforms. Such small strings will
not be heap-allocated.
- String can create substrings without making a deep copy of the
substring. Instead, the superstring gets +1 refcount from the
substring, and it acts like a view into the superstring. To make
substrings like this, use the substring_with_shared_superstring() API.
One caveat:
- String does not guarantee that the underlying data is null-terminated
like DeprecatedString does today. While this was nifty in a handful of
places where we were calling C functions, it did stand in the way of
shared-superstring substrings.
2022-12-01 12:27:43 +00:00
|
|
|
namespace AK {
|
|
|
|
|
2024-08-11 03:19:47 +00:00
|
|
|
String String::from_utf8_with_replacement_character(StringView view, WithBOMHandling with_bom_handling)
|
2024-08-10 05:16:01 +00:00
|
|
|
{
|
2024-08-11 03:19:47 +00:00
|
|
|
if (auto bytes = view.bytes(); with_bom_handling == WithBOMHandling::Yes && bytes.size() >= 3 && bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF)
|
|
|
|
view = view.substring_view(3);
|
|
|
|
|
2024-08-11 02:48:30 +00:00
|
|
|
if (Utf8View(view).validate())
|
|
|
|
return String::from_utf8_without_validation(view.bytes());
|
|
|
|
|
2024-08-10 05:16:01 +00:00
|
|
|
StringBuilder builder;
|
|
|
|
|
|
|
|
for (auto c : Utf8View { view })
|
|
|
|
builder.append_code_point(c);
|
|
|
|
|
|
|
|
return builder.to_string_without_validation();
|
|
|
|
}
|
|
|
|
|
2023-12-29 14:30:15 +00:00
|
|
|
String String::from_utf8_without_validation(ReadonlyBytes bytes)
|
|
|
|
{
|
2023-10-28 20:43:56 +00:00
|
|
|
String result;
|
|
|
|
MUST(result.replace_with_new_string(bytes.size(), [&](Bytes buffer) {
|
|
|
|
bytes.copy_to(buffer);
|
|
|
|
return ErrorOr<void> {};
|
|
|
|
}));
|
|
|
|
return result;
|
2023-12-29 14:30:15 +00:00
|
|
|
}
|
|
|
|
|
AK: Introduce the new String, replacement for DeprecatedString
DeprecatedString (formerly String) has been with us since the start,
and it has served us well. However, it has a number of shortcomings
that I'd like to address.
Some of these issues are hard if not impossible to solve incrementally
inside of DeprecatedString, so instead of doing that, let's build a new
String class and then incrementally move over to it instead.
Problems in DeprecatedString:
- It assumes string allocation never fails. This makes it impossible
to use in allocation-sensitive contexts, and is the reason we had to
ban DeprecatedString from the kernel entirely.
- The awkward null state. DeprecatedString can be null. It's different
from the empty state, although null strings are considered empty.
All code is immediately nicer when using Optional<DeprecatedString>
but DeprecatedString came before Optional, which is how we ended up
like this.
- The encoding of the underlying data is ambiguous. For the most part,
we use it as if it's always UTF-8, but there have been cases where
we pass around strings in other encodings (e.g ISO8859-1)
- operator[] and length() are used to iterate over DeprecatedString one
byte at a time. This is done all over the codebase, and will *not*
give the right results unless the string is all ASCII.
How we solve these issues in the new String:
- Functions that may allocate now return ErrorOr<String> so that ENOMEM
errors can be passed to the caller.
- String has no null state. Use Optional<String> when needed.
- String is always UTF-8. This is validated when constructing a String.
We may need to add a bypass for this in the future, for cases where
you have a known-good string, but for now: validate all the things!
- There is no operator[] or length(). You can get the underlying data
with bytes(), but for iterating over code points, you should be using
an UTF-8 iterator.
Furthermore, it has two nifty new features:
- String implements a small string optimization (SSO) for strings that
can fit entirely within a pointer. This means up to 3 bytes on 32-bit
platforms, and 7 bytes on 64-bit platforms. Such small strings will
not be heap-allocated.
- String can create substrings without making a deep copy of the
substring. Instead, the superstring gets +1 refcount from the
substring, and it acts like a view into the superstring. To make
substrings like this, use the substring_with_shared_superstring() API.
One caveat:
- String does not guarantee that the underlying data is null-terminated
like DeprecatedString does today. While this was nifty in a handful of
places where we were calling C functions, it did stand in the way of
shared-superstring substrings.
2022-12-01 12:27:43 +00:00
|
|
|
ErrorOr<String> String::from_utf8(StringView view)
|
|
|
|
{
|
2023-03-03 14:03:45 +00:00
|
|
|
if (!Utf8View { view }.validate())
|
|
|
|
return Error::from_string_literal("String::from_utf8: Input was not valid UTF-8");
|
|
|
|
|
2023-10-28 20:43:56 +00:00
|
|
|
String result;
|
|
|
|
TRY(result.replace_with_new_string(view.length(), [&](Bytes buffer) {
|
|
|
|
view.bytes().copy_to(buffer);
|
|
|
|
return ErrorOr<void> {};
|
|
|
|
}));
|
|
|
|
return result;
|
AK: Introduce the new String, replacement for DeprecatedString
DeprecatedString (formerly String) has been with us since the start,
and it has served us well. However, it has a number of shortcomings
that I'd like to address.
Some of these issues are hard if not impossible to solve incrementally
inside of DeprecatedString, so instead of doing that, let's build a new
String class and then incrementally move over to it instead.
Problems in DeprecatedString:
- It assumes string allocation never fails. This makes it impossible
to use in allocation-sensitive contexts, and is the reason we had to
ban DeprecatedString from the kernel entirely.
- The awkward null state. DeprecatedString can be null. It's different
from the empty state, although null strings are considered empty.
All code is immediately nicer when using Optional<DeprecatedString>
but DeprecatedString came before Optional, which is how we ended up
like this.
- The encoding of the underlying data is ambiguous. For the most part,
we use it as if it's always UTF-8, but there have been cases where
we pass around strings in other encodings (e.g ISO8859-1)
- operator[] and length() are used to iterate over DeprecatedString one
byte at a time. This is done all over the codebase, and will *not*
give the right results unless the string is all ASCII.
How we solve these issues in the new String:
- Functions that may allocate now return ErrorOr<String> so that ENOMEM
errors can be passed to the caller.
- String has no null state. Use Optional<String> when needed.
- String is always UTF-8. This is validated when constructing a String.
We may need to add a bypass for this in the future, for cases where
you have a known-good string, but for now: validate all the things!
- There is no operator[] or length(). You can get the underlying data
with bytes(), but for iterating over code points, you should be using
an UTF-8 iterator.
Furthermore, it has two nifty new features:
- String implements a small string optimization (SSO) for strings that
can fit entirely within a pointer. This means up to 3 bytes on 32-bit
platforms, and 7 bytes on 64-bit platforms. Such small strings will
not be heap-allocated.
- String can create substrings without making a deep copy of the
substring. Instead, the superstring gets +1 refcount from the
substring, and it acts like a view into the superstring. To make
substrings like this, use the substring_with_shared_superstring() API.
One caveat:
- String does not guarantee that the underlying data is null-terminated
like DeprecatedString does today. While this was nifty in a handful of
places where we were calling C functions, it did stand in the way of
shared-superstring substrings.
2022-12-01 12:27:43 +00:00
|
|
|
}
|
|
|
|
|
2024-07-16 20:05:46 +00:00
|
|
|
ErrorOr<String> String::from_utf16(Utf16View const& utf16)
|
|
|
|
{
|
|
|
|
if (!utf16.validate())
|
|
|
|
return Error::from_string_literal("String::from_utf16: Input was not valid UTF-16");
|
2024-07-20 11:31:19 +00:00
|
|
|
if (utf16.is_empty())
|
|
|
|
return String {};
|
2024-07-16 20:05:46 +00:00
|
|
|
|
|
|
|
String result;
|
|
|
|
|
2024-07-18 15:57:01 +00:00
|
|
|
auto utf8_length = [&]() {
|
|
|
|
switch (utf16.endianness()) {
|
|
|
|
case Endianness::Host:
|
|
|
|
return simdutf::utf8_length_from_utf16(utf16.char_data(), utf16.length_in_code_units());
|
|
|
|
case Endianness::Big:
|
|
|
|
return simdutf::utf8_length_from_utf16be(utf16.char_data(), utf16.length_in_code_units());
|
|
|
|
case Endianness::Little:
|
|
|
|
return simdutf::utf8_length_from_utf16le(utf16.char_data(), utf16.length_in_code_units());
|
|
|
|
}
|
|
|
|
VERIFY_NOT_REACHED();
|
|
|
|
}();
|
2024-07-16 20:05:46 +00:00
|
|
|
|
|
|
|
TRY(result.replace_with_new_string(utf8_length, [&](Bytes buffer) -> ErrorOr<void> {
|
2024-07-18 15:57:01 +00:00
|
|
|
[[maybe_unused]] auto result = [&]() {
|
|
|
|
switch (utf16.endianness()) {
|
|
|
|
case Endianness::Host:
|
|
|
|
return simdutf::convert_utf16_to_utf8(utf16.char_data(), utf16.length_in_code_units(), reinterpret_cast<char*>(buffer.data()));
|
|
|
|
case Endianness::Big:
|
|
|
|
return simdutf::convert_utf16be_to_utf8(utf16.char_data(), utf16.length_in_code_units(), reinterpret_cast<char*>(buffer.data()));
|
|
|
|
case Endianness::Little:
|
|
|
|
return simdutf::convert_utf16le_to_utf8(utf16.char_data(), utf16.length_in_code_units(), reinterpret_cast<char*>(buffer.data()));
|
|
|
|
}
|
|
|
|
VERIFY_NOT_REACHED();
|
|
|
|
}();
|
2024-07-16 20:05:46 +00:00
|
|
|
ASSERT(result == buffer.size());
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}));
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-02-20 01:34:29 +00:00
|
|
|
ErrorOr<String> String::from_stream(Stream& stream, size_t byte_count)
|
|
|
|
{
|
2023-10-28 21:11:55 +00:00
|
|
|
String result;
|
|
|
|
TRY(result.replace_with_new_string(byte_count, [&](Bytes buffer) -> ErrorOr<void> {
|
|
|
|
TRY(stream.read_until_filled(buffer));
|
|
|
|
if (!Utf8View { StringView { buffer } }.validate())
|
|
|
|
return Error::from_string_literal("String::from_stream: Input was not valid UTF-8");
|
|
|
|
return {};
|
|
|
|
}));
|
|
|
|
return result;
|
2023-02-20 01:34:29 +00:00
|
|
|
}
|
|
|
|
|
2024-07-19 19:38:41 +00:00
|
|
|
ErrorOr<String> String::from_string_builder(Badge<StringBuilder>, StringBuilder& builder)
|
|
|
|
{
|
|
|
|
if (!Utf8View { builder.string_view() }.validate())
|
|
|
|
return Error::from_string_literal("String::from_string_builder: Input was not valid UTF-8");
|
|
|
|
|
|
|
|
String result;
|
|
|
|
result.replace_with_string_builder(builder);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
String String::from_string_builder_without_validation(Badge<StringBuilder>, StringBuilder& builder)
|
|
|
|
{
|
|
|
|
String result;
|
|
|
|
result.replace_with_string_builder(builder);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-01-22 15:17:48 +00:00
|
|
|
ErrorOr<String> String::repeated(u32 code_point, size_t count)
|
|
|
|
{
|
|
|
|
VERIFY(is_unicode(code_point));
|
|
|
|
|
|
|
|
Array<u8, 4> code_point_as_utf8;
|
|
|
|
size_t i = 0;
|
|
|
|
|
|
|
|
size_t code_point_byte_length = UnicodeUtils::code_point_to_utf8(code_point, [&](auto byte) {
|
|
|
|
code_point_as_utf8[i++] = static_cast<u8>(byte);
|
|
|
|
});
|
|
|
|
|
|
|
|
auto total_byte_count = code_point_byte_length * count;
|
|
|
|
|
2023-10-28 21:15:40 +00:00
|
|
|
String result;
|
|
|
|
TRY(result.replace_with_new_string(total_byte_count, [&](Bytes buffer) {
|
|
|
|
if (code_point_byte_length == 1) {
|
|
|
|
buffer.fill(code_point_as_utf8[0]);
|
|
|
|
} else {
|
|
|
|
for (i = 0; i < count; ++i)
|
|
|
|
memcpy(buffer.data() + (i * code_point_byte_length), code_point_as_utf8.data(), code_point_byte_length);
|
|
|
|
}
|
|
|
|
return ErrorOr<void> {};
|
|
|
|
}));
|
|
|
|
return result;
|
2023-01-22 15:17:48 +00:00
|
|
|
}
|
|
|
|
|
2024-04-04 02:00:23 +00:00
|
|
|
StringView String::bytes_as_string_view() const&
|
AK: Introduce the new String, replacement for DeprecatedString
DeprecatedString (formerly String) has been with us since the start,
and it has served us well. However, it has a number of shortcomings
that I'd like to address.
Some of these issues are hard if not impossible to solve incrementally
inside of DeprecatedString, so instead of doing that, let's build a new
String class and then incrementally move over to it instead.
Problems in DeprecatedString:
- It assumes string allocation never fails. This makes it impossible
to use in allocation-sensitive contexts, and is the reason we had to
ban DeprecatedString from the kernel entirely.
- The awkward null state. DeprecatedString can be null. It's different
from the empty state, although null strings are considered empty.
All code is immediately nicer when using Optional<DeprecatedString>
but DeprecatedString came before Optional, which is how we ended up
like this.
- The encoding of the underlying data is ambiguous. For the most part,
we use it as if it's always UTF-8, but there have been cases where
we pass around strings in other encodings (e.g ISO8859-1)
- operator[] and length() are used to iterate over DeprecatedString one
byte at a time. This is done all over the codebase, and will *not*
give the right results unless the string is all ASCII.
How we solve these issues in the new String:
- Functions that may allocate now return ErrorOr<String> so that ENOMEM
errors can be passed to the caller.
- String has no null state. Use Optional<String> when needed.
- String is always UTF-8. This is validated when constructing a String.
We may need to add a bypass for this in the future, for cases where
you have a known-good string, but for now: validate all the things!
- There is no operator[] or length(). You can get the underlying data
with bytes(), but for iterating over code points, you should be using
an UTF-8 iterator.
Furthermore, it has two nifty new features:
- String implements a small string optimization (SSO) for strings that
can fit entirely within a pointer. This means up to 3 bytes on 32-bit
platforms, and 7 bytes on 64-bit platforms. Such small strings will
not be heap-allocated.
- String can create substrings without making a deep copy of the
substring. Instead, the superstring gets +1 refcount from the
substring, and it acts like a view into the superstring. To make
substrings like this, use the substring_with_shared_superstring() API.
One caveat:
- String does not guarantee that the underlying data is null-terminated
like DeprecatedString does today. While this was nifty in a handful of
places where we were calling C functions, it did stand in the way of
shared-superstring substrings.
2022-12-01 12:27:43 +00:00
|
|
|
{
|
|
|
|
return StringView(bytes());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool String::is_empty() const
|
|
|
|
{
|
|
|
|
return bytes().size() == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ErrorOr<String> String::vformatted(StringView fmtstr, TypeErasedFormatParams& params)
|
|
|
|
{
|
|
|
|
StringBuilder builder;
|
|
|
|
TRY(vformat(builder, fmtstr, params));
|
|
|
|
return builder.to_string();
|
|
|
|
}
|
|
|
|
|
2023-01-16 16:12:53 +00:00
|
|
|
ErrorOr<Vector<String>> String::split(u32 separator, SplitBehavior split_behavior) const
|
|
|
|
{
|
|
|
|
return split_limit(separator, 0, split_behavior);
|
|
|
|
}
|
|
|
|
|
|
|
|
ErrorOr<Vector<String>> String::split_limit(u32 separator, size_t limit, SplitBehavior split_behavior) const
|
|
|
|
{
|
|
|
|
Vector<String> result;
|
|
|
|
|
|
|
|
if (is_empty())
|
|
|
|
return result;
|
|
|
|
|
|
|
|
bool keep_empty = has_flag(split_behavior, SplitBehavior::KeepEmpty);
|
|
|
|
|
|
|
|
size_t substring_start = 0;
|
|
|
|
for (auto it = code_points().begin(); it != code_points().end() && (result.size() + 1) != limit; ++it) {
|
|
|
|
u32 code_point = *it;
|
|
|
|
if (code_point == separator) {
|
|
|
|
size_t substring_length = code_points().iterator_offset(it) - substring_start;
|
|
|
|
if (substring_length != 0 || keep_empty)
|
|
|
|
TRY(result.try_append(TRY(substring_from_byte_offset_with_shared_superstring(substring_start, substring_length))));
|
|
|
|
substring_start = code_points().iterator_offset(it) + it.underlying_code_point_length_in_bytes();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
size_t tail_length = code_points().byte_length() - substring_start;
|
|
|
|
if (tail_length != 0 || keep_empty)
|
|
|
|
TRY(result.try_append(TRY(substring_from_byte_offset_with_shared_superstring(substring_start, tail_length))));
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-01-22 14:24:12 +00:00
|
|
|
Optional<size_t> String::find_byte_offset(u32 code_point, size_t from_byte_offset) const
|
|
|
|
{
|
|
|
|
auto code_points = this->code_points();
|
|
|
|
if (from_byte_offset >= code_points.byte_length())
|
|
|
|
return {};
|
|
|
|
|
|
|
|
for (auto it = code_points.iterator_at_byte_offset(from_byte_offset); it != code_points.end(); ++it) {
|
|
|
|
if (*it == code_point)
|
|
|
|
return code_points.byte_offset_of(it);
|
|
|
|
}
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2023-01-27 15:17:34 +00:00
|
|
|
Optional<size_t> String::find_byte_offset(StringView substring, size_t from_byte_offset) const
|
|
|
|
{
|
|
|
|
auto view = bytes_as_string_view();
|
|
|
|
if (from_byte_offset >= view.length())
|
|
|
|
return {};
|
|
|
|
|
|
|
|
auto index = memmem_optional(
|
|
|
|
view.characters_without_null_termination() + from_byte_offset, view.length() - from_byte_offset,
|
|
|
|
substring.characters_without_null_termination(), substring.length());
|
|
|
|
|
|
|
|
if (index.has_value())
|
|
|
|
return *index + from_byte_offset;
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2023-01-11 13:26:49 +00:00
|
|
|
bool String::operator==(FlyString const& other) const
|
|
|
|
{
|
2023-10-28 22:58:29 +00:00
|
|
|
return static_cast<StringBase const&>(*this) == other.data({});
|
2023-01-11 13:26:49 +00:00
|
|
|
}
|
|
|
|
|
AK: Introduce the new String, replacement for DeprecatedString
DeprecatedString (formerly String) has been with us since the start,
and it has served us well. However, it has a number of shortcomings
that I'd like to address.
Some of these issues are hard if not impossible to solve incrementally
inside of DeprecatedString, so instead of doing that, let's build a new
String class and then incrementally move over to it instead.
Problems in DeprecatedString:
- It assumes string allocation never fails. This makes it impossible
to use in allocation-sensitive contexts, and is the reason we had to
ban DeprecatedString from the kernel entirely.
- The awkward null state. DeprecatedString can be null. It's different
from the empty state, although null strings are considered empty.
All code is immediately nicer when using Optional<DeprecatedString>
but DeprecatedString came before Optional, which is how we ended up
like this.
- The encoding of the underlying data is ambiguous. For the most part,
we use it as if it's always UTF-8, but there have been cases where
we pass around strings in other encodings (e.g ISO8859-1)
- operator[] and length() are used to iterate over DeprecatedString one
byte at a time. This is done all over the codebase, and will *not*
give the right results unless the string is all ASCII.
How we solve these issues in the new String:
- Functions that may allocate now return ErrorOr<String> so that ENOMEM
errors can be passed to the caller.
- String has no null state. Use Optional<String> when needed.
- String is always UTF-8. This is validated when constructing a String.
We may need to add a bypass for this in the future, for cases where
you have a known-good string, but for now: validate all the things!
- There is no operator[] or length(). You can get the underlying data
with bytes(), but for iterating over code points, you should be using
an UTF-8 iterator.
Furthermore, it has two nifty new features:
- String implements a small string optimization (SSO) for strings that
can fit entirely within a pointer. This means up to 3 bytes on 32-bit
platforms, and 7 bytes on 64-bit platforms. Such small strings will
not be heap-allocated.
- String can create substrings without making a deep copy of the
substring. Instead, the superstring gets +1 refcount from the
substring, and it acts like a view into the superstring. To make
substrings like this, use the substring_with_shared_superstring() API.
One caveat:
- String does not guarantee that the underlying data is null-terminated
like DeprecatedString does today. While this was nifty in a handful of
places where we were calling C functions, it did stand in the way of
shared-superstring substrings.
2022-12-01 12:27:43 +00:00
|
|
|
bool String::operator==(StringView other) const
|
|
|
|
{
|
|
|
|
return bytes_as_string_view() == other;
|
|
|
|
}
|
|
|
|
|
|
|
|
ErrorOr<String> String::substring_from_byte_offset(size_t start, size_t byte_count) const
|
|
|
|
{
|
|
|
|
if (!byte_count)
|
|
|
|
return String {};
|
|
|
|
return String::from_utf8(bytes_as_string_view().substring_view(start, byte_count));
|
|
|
|
}
|
|
|
|
|
2023-01-22 16:40:57 +00:00
|
|
|
ErrorOr<String> String::substring_from_byte_offset(size_t start) const
|
|
|
|
{
|
|
|
|
VERIFY(start <= bytes_as_string_view().length());
|
|
|
|
return substring_from_byte_offset(start, bytes_as_string_view().length() - start);
|
|
|
|
}
|
|
|
|
|
AK: Introduce the new String, replacement for DeprecatedString
DeprecatedString (formerly String) has been with us since the start,
and it has served us well. However, it has a number of shortcomings
that I'd like to address.
Some of these issues are hard if not impossible to solve incrementally
inside of DeprecatedString, so instead of doing that, let's build a new
String class and then incrementally move over to it instead.
Problems in DeprecatedString:
- It assumes string allocation never fails. This makes it impossible
to use in allocation-sensitive contexts, and is the reason we had to
ban DeprecatedString from the kernel entirely.
- The awkward null state. DeprecatedString can be null. It's different
from the empty state, although null strings are considered empty.
All code is immediately nicer when using Optional<DeprecatedString>
but DeprecatedString came before Optional, which is how we ended up
like this.
- The encoding of the underlying data is ambiguous. For the most part,
we use it as if it's always UTF-8, but there have been cases where
we pass around strings in other encodings (e.g ISO8859-1)
- operator[] and length() are used to iterate over DeprecatedString one
byte at a time. This is done all over the codebase, and will *not*
give the right results unless the string is all ASCII.
How we solve these issues in the new String:
- Functions that may allocate now return ErrorOr<String> so that ENOMEM
errors can be passed to the caller.
- String has no null state. Use Optional<String> when needed.
- String is always UTF-8. This is validated when constructing a String.
We may need to add a bypass for this in the future, for cases where
you have a known-good string, but for now: validate all the things!
- There is no operator[] or length(). You can get the underlying data
with bytes(), but for iterating over code points, you should be using
an UTF-8 iterator.
Furthermore, it has two nifty new features:
- String implements a small string optimization (SSO) for strings that
can fit entirely within a pointer. This means up to 3 bytes on 32-bit
platforms, and 7 bytes on 64-bit platforms. Such small strings will
not be heap-allocated.
- String can create substrings without making a deep copy of the
substring. Instead, the superstring gets +1 refcount from the
substring, and it acts like a view into the superstring. To make
substrings like this, use the substring_with_shared_superstring() API.
One caveat:
- String does not guarantee that the underlying data is null-terminated
like DeprecatedString does today. While this was nifty in a handful of
places where we were calling C functions, it did stand in the way of
shared-superstring substrings.
2022-12-01 12:27:43 +00:00
|
|
|
ErrorOr<String> String::substring_from_byte_offset_with_shared_superstring(size_t start, size_t byte_count) const
|
|
|
|
{
|
2023-10-28 21:50:24 +00:00
|
|
|
return String { TRY(StringBase::substring_from_byte_offset_with_shared_superstring(start, byte_count)) };
|
AK: Introduce the new String, replacement for DeprecatedString
DeprecatedString (formerly String) has been with us since the start,
and it has served us well. However, it has a number of shortcomings
that I'd like to address.
Some of these issues are hard if not impossible to solve incrementally
inside of DeprecatedString, so instead of doing that, let's build a new
String class and then incrementally move over to it instead.
Problems in DeprecatedString:
- It assumes string allocation never fails. This makes it impossible
to use in allocation-sensitive contexts, and is the reason we had to
ban DeprecatedString from the kernel entirely.
- The awkward null state. DeprecatedString can be null. It's different
from the empty state, although null strings are considered empty.
All code is immediately nicer when using Optional<DeprecatedString>
but DeprecatedString came before Optional, which is how we ended up
like this.
- The encoding of the underlying data is ambiguous. For the most part,
we use it as if it's always UTF-8, but there have been cases where
we pass around strings in other encodings (e.g ISO8859-1)
- operator[] and length() are used to iterate over DeprecatedString one
byte at a time. This is done all over the codebase, and will *not*
give the right results unless the string is all ASCII.
How we solve these issues in the new String:
- Functions that may allocate now return ErrorOr<String> so that ENOMEM
errors can be passed to the caller.
- String has no null state. Use Optional<String> when needed.
- String is always UTF-8. This is validated when constructing a String.
We may need to add a bypass for this in the future, for cases where
you have a known-good string, but for now: validate all the things!
- There is no operator[] or length(). You can get the underlying data
with bytes(), but for iterating over code points, you should be using
an UTF-8 iterator.
Furthermore, it has two nifty new features:
- String implements a small string optimization (SSO) for strings that
can fit entirely within a pointer. This means up to 3 bytes on 32-bit
platforms, and 7 bytes on 64-bit platforms. Such small strings will
not be heap-allocated.
- String can create substrings without making a deep copy of the
substring. Instead, the superstring gets +1 refcount from the
substring, and it acts like a view into the superstring. To make
substrings like this, use the substring_with_shared_superstring() API.
One caveat:
- String does not guarantee that the underlying data is null-terminated
like DeprecatedString does today. While this was nifty in a handful of
places where we were calling C functions, it did stand in the way of
shared-superstring substrings.
2022-12-01 12:27:43 +00:00
|
|
|
}
|
|
|
|
|
2023-01-22 16:40:57 +00:00
|
|
|
ErrorOr<String> String::substring_from_byte_offset_with_shared_superstring(size_t start) const
|
|
|
|
{
|
|
|
|
VERIFY(start <= bytes_as_string_view().length());
|
|
|
|
return substring_from_byte_offset_with_shared_superstring(start, bytes_as_string_view().length() - start);
|
|
|
|
}
|
|
|
|
|
AK: Introduce the new String, replacement for DeprecatedString
DeprecatedString (formerly String) has been with us since the start,
and it has served us well. However, it has a number of shortcomings
that I'd like to address.
Some of these issues are hard if not impossible to solve incrementally
inside of DeprecatedString, so instead of doing that, let's build a new
String class and then incrementally move over to it instead.
Problems in DeprecatedString:
- It assumes string allocation never fails. This makes it impossible
to use in allocation-sensitive contexts, and is the reason we had to
ban DeprecatedString from the kernel entirely.
- The awkward null state. DeprecatedString can be null. It's different
from the empty state, although null strings are considered empty.
All code is immediately nicer when using Optional<DeprecatedString>
but DeprecatedString came before Optional, which is how we ended up
like this.
- The encoding of the underlying data is ambiguous. For the most part,
we use it as if it's always UTF-8, but there have been cases where
we pass around strings in other encodings (e.g ISO8859-1)
- operator[] and length() are used to iterate over DeprecatedString one
byte at a time. This is done all over the codebase, and will *not*
give the right results unless the string is all ASCII.
How we solve these issues in the new String:
- Functions that may allocate now return ErrorOr<String> so that ENOMEM
errors can be passed to the caller.
- String has no null state. Use Optional<String> when needed.
- String is always UTF-8. This is validated when constructing a String.
We may need to add a bypass for this in the future, for cases where
you have a known-good string, but for now: validate all the things!
- There is no operator[] or length(). You can get the underlying data
with bytes(), but for iterating over code points, you should be using
an UTF-8 iterator.
Furthermore, it has two nifty new features:
- String implements a small string optimization (SSO) for strings that
can fit entirely within a pointer. This means up to 3 bytes on 32-bit
platforms, and 7 bytes on 64-bit platforms. Such small strings will
not be heap-allocated.
- String can create substrings without making a deep copy of the
substring. Instead, the superstring gets +1 refcount from the
substring, and it acts like a view into the superstring. To make
substrings like this, use the substring_with_shared_superstring() API.
One caveat:
- String does not guarantee that the underlying data is null-terminated
like DeprecatedString does today. While this was nifty in a handful of
places where we were calling C functions, it did stand in the way of
shared-superstring substrings.
2022-12-01 12:27:43 +00:00
|
|
|
bool String::operator==(char const* c_string) const
|
|
|
|
{
|
|
|
|
return bytes_as_string_view() == c_string;
|
|
|
|
}
|
|
|
|
|
2023-09-05 17:55:21 +00:00
|
|
|
u32 String::ascii_case_insensitive_hash() const
|
|
|
|
{
|
|
|
|
return case_insensitive_string_hash(reinterpret_cast<char const*>(bytes().data()), bytes().size());
|
|
|
|
}
|
|
|
|
|
2024-04-04 02:00:23 +00:00
|
|
|
Utf8View String::code_points() const&
|
AK: Introduce the new String, replacement for DeprecatedString
DeprecatedString (formerly String) has been with us since the start,
and it has served us well. However, it has a number of shortcomings
that I'd like to address.
Some of these issues are hard if not impossible to solve incrementally
inside of DeprecatedString, so instead of doing that, let's build a new
String class and then incrementally move over to it instead.
Problems in DeprecatedString:
- It assumes string allocation never fails. This makes it impossible
to use in allocation-sensitive contexts, and is the reason we had to
ban DeprecatedString from the kernel entirely.
- The awkward null state. DeprecatedString can be null. It's different
from the empty state, although null strings are considered empty.
All code is immediately nicer when using Optional<DeprecatedString>
but DeprecatedString came before Optional, which is how we ended up
like this.
- The encoding of the underlying data is ambiguous. For the most part,
we use it as if it's always UTF-8, but there have been cases where
we pass around strings in other encodings (e.g ISO8859-1)
- operator[] and length() are used to iterate over DeprecatedString one
byte at a time. This is done all over the codebase, and will *not*
give the right results unless the string is all ASCII.
How we solve these issues in the new String:
- Functions that may allocate now return ErrorOr<String> so that ENOMEM
errors can be passed to the caller.
- String has no null state. Use Optional<String> when needed.
- String is always UTF-8. This is validated when constructing a String.
We may need to add a bypass for this in the future, for cases where
you have a known-good string, but for now: validate all the things!
- There is no operator[] or length(). You can get the underlying data
with bytes(), but for iterating over code points, you should be using
an UTF-8 iterator.
Furthermore, it has two nifty new features:
- String implements a small string optimization (SSO) for strings that
can fit entirely within a pointer. This means up to 3 bytes on 32-bit
platforms, and 7 bytes on 64-bit platforms. Such small strings will
not be heap-allocated.
- String can create substrings without making a deep copy of the
substring. Instead, the superstring gets +1 refcount from the
substring, and it acts like a view into the superstring. To make
substrings like this, use the substring_with_shared_superstring() API.
One caveat:
- String does not guarantee that the underlying data is null-terminated
like DeprecatedString does today. While this was nifty in a handful of
places where we were calling C functions, it did stand in the way of
shared-superstring substrings.
2022-12-01 12:27:43 +00:00
|
|
|
{
|
|
|
|
return Utf8View(bytes_as_string_view());
|
|
|
|
}
|
|
|
|
|
|
|
|
ErrorOr<void> Formatter<String>::format(FormatBuilder& builder, String const& utf8_string)
|
|
|
|
{
|
|
|
|
return Formatter<StringView>::format(builder, utf8_string.bytes_as_string_view());
|
|
|
|
}
|
|
|
|
|
|
|
|
ErrorOr<String> String::replace(StringView needle, StringView replacement, ReplaceMode replace_mode) const
|
|
|
|
{
|
|
|
|
return StringUtils::replace(*this, needle, replacement, replace_mode);
|
|
|
|
}
|
|
|
|
|
2023-01-13 16:34:00 +00:00
|
|
|
ErrorOr<String> String::reverse() const
|
|
|
|
{
|
|
|
|
// FIXME: This handles multi-byte code points, but not e.g. grapheme clusters.
|
|
|
|
// FIXME: We could avoid allocating a temporary vector if Utf8View supports reverse iteration.
|
|
|
|
auto code_point_length = code_points().length();
|
|
|
|
|
|
|
|
Vector<u32> code_points;
|
|
|
|
TRY(code_points.try_ensure_capacity(code_point_length));
|
|
|
|
|
|
|
|
for (auto code_point : this->code_points())
|
|
|
|
code_points.unchecked_append(code_point);
|
|
|
|
|
|
|
|
auto builder = TRY(StringBuilder::create(code_point_length * sizeof(u32)));
|
|
|
|
while (!code_points.is_empty())
|
|
|
|
TRY(builder.try_append_code_point(code_points.take_last()));
|
|
|
|
|
|
|
|
return builder.to_string();
|
|
|
|
}
|
|
|
|
|
2023-01-27 19:37:40 +00:00
|
|
|
ErrorOr<String> String::trim(Utf8View const& code_points_to_trim, TrimMode mode) const
|
|
|
|
{
|
|
|
|
auto trimmed = code_points().trim(code_points_to_trim, mode);
|
|
|
|
return String::from_utf8(trimmed.as_string());
|
|
|
|
}
|
|
|
|
|
|
|
|
ErrorOr<String> String::trim(StringView code_points_to_trim, TrimMode mode) const
|
|
|
|
{
|
|
|
|
return trim(Utf8View { code_points_to_trim }, mode);
|
|
|
|
}
|
|
|
|
|
2023-07-07 07:52:36 +00:00
|
|
|
ErrorOr<String> String::trim_ascii_whitespace(TrimMode mode) const
|
|
|
|
{
|
|
|
|
return trim(" \n\t\v\f\r"sv, mode);
|
|
|
|
}
|
|
|
|
|
2023-01-14 15:17:32 +00:00
|
|
|
bool String::contains(StringView needle, CaseSensitivity case_sensitivity) const
|
|
|
|
{
|
|
|
|
return StringUtils::contains(bytes_as_string_view(), needle, case_sensitivity);
|
|
|
|
}
|
|
|
|
|
2023-03-08 14:06:59 +00:00
|
|
|
bool String::contains(u32 needle, CaseSensitivity case_sensitivity) const
|
2023-01-14 15:17:32 +00:00
|
|
|
{
|
2023-03-08 14:06:59 +00:00
|
|
|
auto needle_as_string = String::from_code_point(needle);
|
|
|
|
return contains(needle_as_string.bytes_as_string_view(), case_sensitivity);
|
2023-01-14 15:17:32 +00:00
|
|
|
}
|
|
|
|
|
2023-03-03 09:27:50 +00:00
|
|
|
bool String::starts_with(u32 code_point) const
|
|
|
|
{
|
2023-03-08 13:56:02 +00:00
|
|
|
if (is_empty())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return *code_points().begin() == code_point;
|
2023-03-03 09:27:50 +00:00
|
|
|
}
|
|
|
|
|
2023-11-04 09:07:01 +00:00
|
|
|
bool String::starts_with_bytes(StringView bytes, CaseSensitivity case_sensitivity) const
|
2023-02-18 06:34:37 +00:00
|
|
|
{
|
2023-11-04 09:07:01 +00:00
|
|
|
return bytes_as_string_view().starts_with(bytes, case_sensitivity);
|
2023-02-18 06:34:37 +00:00
|
|
|
}
|
|
|
|
|
2023-03-03 09:27:50 +00:00
|
|
|
bool String::ends_with(u32 code_point) const
|
2023-02-18 06:34:37 +00:00
|
|
|
{
|
2023-03-08 13:56:02 +00:00
|
|
|
if (is_empty())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
u32 last_code_point = 0;
|
|
|
|
for (auto it = code_points().begin(); it != code_points().end(); ++it)
|
|
|
|
last_code_point = *it;
|
|
|
|
|
|
|
|
return last_code_point == code_point;
|
2023-03-03 09:27:50 +00:00
|
|
|
}
|
|
|
|
|
2023-11-04 09:07:01 +00:00
|
|
|
bool String::ends_with_bytes(StringView bytes, CaseSensitivity case_sensitivity) const
|
2023-03-03 09:27:50 +00:00
|
|
|
{
|
2023-11-04 09:07:01 +00:00
|
|
|
return bytes_as_string_view().ends_with(bytes, case_sensitivity);
|
2023-02-18 06:34:37 +00:00
|
|
|
}
|
|
|
|
|
AK: Introduce the new String, replacement for DeprecatedString
DeprecatedString (formerly String) has been with us since the start,
and it has served us well. However, it has a number of shortcomings
that I'd like to address.
Some of these issues are hard if not impossible to solve incrementally
inside of DeprecatedString, so instead of doing that, let's build a new
String class and then incrementally move over to it instead.
Problems in DeprecatedString:
- It assumes string allocation never fails. This makes it impossible
to use in allocation-sensitive contexts, and is the reason we had to
ban DeprecatedString from the kernel entirely.
- The awkward null state. DeprecatedString can be null. It's different
from the empty state, although null strings are considered empty.
All code is immediately nicer when using Optional<DeprecatedString>
but DeprecatedString came before Optional, which is how we ended up
like this.
- The encoding of the underlying data is ambiguous. For the most part,
we use it as if it's always UTF-8, but there have been cases where
we pass around strings in other encodings (e.g ISO8859-1)
- operator[] and length() are used to iterate over DeprecatedString one
byte at a time. This is done all over the codebase, and will *not*
give the right results unless the string is all ASCII.
How we solve these issues in the new String:
- Functions that may allocate now return ErrorOr<String> so that ENOMEM
errors can be passed to the caller.
- String has no null state. Use Optional<String> when needed.
- String is always UTF-8. This is validated when constructing a String.
We may need to add a bypass for this in the future, for cases where
you have a known-good string, but for now: validate all the things!
- There is no operator[] or length(). You can get the underlying data
with bytes(), but for iterating over code points, you should be using
an UTF-8 iterator.
Furthermore, it has two nifty new features:
- String implements a small string optimization (SSO) for strings that
can fit entirely within a pointer. This means up to 3 bytes on 32-bit
platforms, and 7 bytes on 64-bit platforms. Such small strings will
not be heap-allocated.
- String can create substrings without making a deep copy of the
substring. Instead, the superstring gets +1 refcount from the
substring, and it acts like a view into the superstring. To make
substrings like this, use the substring_with_shared_superstring() API.
One caveat:
- String does not guarantee that the underlying data is null-terminated
like DeprecatedString does today. While this was nifty in a handful of
places where we were calling C functions, it did stand in the way of
shared-superstring substrings.
2022-12-01 12:27:43 +00:00
|
|
|
unsigned Traits<String>::hash(String const& string)
|
|
|
|
{
|
|
|
|
return string.hash();
|
|
|
|
}
|
|
|
|
|
2023-12-16 14:19:34 +00:00
|
|
|
ByteString String::to_byte_string() const
|
AK: Introduce the new String, replacement for DeprecatedString
DeprecatedString (formerly String) has been with us since the start,
and it has served us well. However, it has a number of shortcomings
that I'd like to address.
Some of these issues are hard if not impossible to solve incrementally
inside of DeprecatedString, so instead of doing that, let's build a new
String class and then incrementally move over to it instead.
Problems in DeprecatedString:
- It assumes string allocation never fails. This makes it impossible
to use in allocation-sensitive contexts, and is the reason we had to
ban DeprecatedString from the kernel entirely.
- The awkward null state. DeprecatedString can be null. It's different
from the empty state, although null strings are considered empty.
All code is immediately nicer when using Optional<DeprecatedString>
but DeprecatedString came before Optional, which is how we ended up
like this.
- The encoding of the underlying data is ambiguous. For the most part,
we use it as if it's always UTF-8, but there have been cases where
we pass around strings in other encodings (e.g ISO8859-1)
- operator[] and length() are used to iterate over DeprecatedString one
byte at a time. This is done all over the codebase, and will *not*
give the right results unless the string is all ASCII.
How we solve these issues in the new String:
- Functions that may allocate now return ErrorOr<String> so that ENOMEM
errors can be passed to the caller.
- String has no null state. Use Optional<String> when needed.
- String is always UTF-8. This is validated when constructing a String.
We may need to add a bypass for this in the future, for cases where
you have a known-good string, but for now: validate all the things!
- There is no operator[] or length(). You can get the underlying data
with bytes(), but for iterating over code points, you should be using
an UTF-8 iterator.
Furthermore, it has two nifty new features:
- String implements a small string optimization (SSO) for strings that
can fit entirely within a pointer. This means up to 3 bytes on 32-bit
platforms, and 7 bytes on 64-bit platforms. Such small strings will
not be heap-allocated.
- String can create substrings without making a deep copy of the
substring. Instead, the superstring gets +1 refcount from the
substring, and it acts like a view into the superstring. To make
substrings like this, use the substring_with_shared_superstring() API.
One caveat:
- String does not guarantee that the underlying data is null-terminated
like DeprecatedString does today. While this was nifty in a handful of
places where we were calling C functions, it did stand in the way of
shared-superstring substrings.
2022-12-01 12:27:43 +00:00
|
|
|
{
|
2023-12-16 14:19:34 +00:00
|
|
|
return ByteString(bytes_as_string_view());
|
AK: Introduce the new String, replacement for DeprecatedString
DeprecatedString (formerly String) has been with us since the start,
and it has served us well. However, it has a number of shortcomings
that I'd like to address.
Some of these issues are hard if not impossible to solve incrementally
inside of DeprecatedString, so instead of doing that, let's build a new
String class and then incrementally move over to it instead.
Problems in DeprecatedString:
- It assumes string allocation never fails. This makes it impossible
to use in allocation-sensitive contexts, and is the reason we had to
ban DeprecatedString from the kernel entirely.
- The awkward null state. DeprecatedString can be null. It's different
from the empty state, although null strings are considered empty.
All code is immediately nicer when using Optional<DeprecatedString>
but DeprecatedString came before Optional, which is how we ended up
like this.
- The encoding of the underlying data is ambiguous. For the most part,
we use it as if it's always UTF-8, but there have been cases where
we pass around strings in other encodings (e.g ISO8859-1)
- operator[] and length() are used to iterate over DeprecatedString one
byte at a time. This is done all over the codebase, and will *not*
give the right results unless the string is all ASCII.
How we solve these issues in the new String:
- Functions that may allocate now return ErrorOr<String> so that ENOMEM
errors can be passed to the caller.
- String has no null state. Use Optional<String> when needed.
- String is always UTF-8. This is validated when constructing a String.
We may need to add a bypass for this in the future, for cases where
you have a known-good string, but for now: validate all the things!
- There is no operator[] or length(). You can get the underlying data
with bytes(), but for iterating over code points, you should be using
an UTF-8 iterator.
Furthermore, it has two nifty new features:
- String implements a small string optimization (SSO) for strings that
can fit entirely within a pointer. This means up to 3 bytes on 32-bit
platforms, and 7 bytes on 64-bit platforms. Such small strings will
not be heap-allocated.
- String can create substrings without making a deep copy of the
substring. Instead, the superstring gets +1 refcount from the
substring, and it acts like a view into the superstring. To make
substrings like this, use the substring_with_shared_superstring() API.
One caveat:
- String does not guarantee that the underlying data is null-terminated
like DeprecatedString does today. While this was nifty in a handful of
places where we were calling C functions, it did stand in the way of
shared-superstring substrings.
2022-12-01 12:27:43 +00:00
|
|
|
}
|
|
|
|
|
2023-12-16 14:19:34 +00:00
|
|
|
ErrorOr<String> String::from_byte_string(ByteString const& byte_string)
|
AK: Introduce the new String, replacement for DeprecatedString
DeprecatedString (formerly String) has been with us since the start,
and it has served us well. However, it has a number of shortcomings
that I'd like to address.
Some of these issues are hard if not impossible to solve incrementally
inside of DeprecatedString, so instead of doing that, let's build a new
String class and then incrementally move over to it instead.
Problems in DeprecatedString:
- It assumes string allocation never fails. This makes it impossible
to use in allocation-sensitive contexts, and is the reason we had to
ban DeprecatedString from the kernel entirely.
- The awkward null state. DeprecatedString can be null. It's different
from the empty state, although null strings are considered empty.
All code is immediately nicer when using Optional<DeprecatedString>
but DeprecatedString came before Optional, which is how we ended up
like this.
- The encoding of the underlying data is ambiguous. For the most part,
we use it as if it's always UTF-8, but there have been cases where
we pass around strings in other encodings (e.g ISO8859-1)
- operator[] and length() are used to iterate over DeprecatedString one
byte at a time. This is done all over the codebase, and will *not*
give the right results unless the string is all ASCII.
How we solve these issues in the new String:
- Functions that may allocate now return ErrorOr<String> so that ENOMEM
errors can be passed to the caller.
- String has no null state. Use Optional<String> when needed.
- String is always UTF-8. This is validated when constructing a String.
We may need to add a bypass for this in the future, for cases where
you have a known-good string, but for now: validate all the things!
- There is no operator[] or length(). You can get the underlying data
with bytes(), but for iterating over code points, you should be using
an UTF-8 iterator.
Furthermore, it has two nifty new features:
- String implements a small string optimization (SSO) for strings that
can fit entirely within a pointer. This means up to 3 bytes on 32-bit
platforms, and 7 bytes on 64-bit platforms. Such small strings will
not be heap-allocated.
- String can create substrings without making a deep copy of the
substring. Instead, the superstring gets +1 refcount from the
substring, and it acts like a view into the superstring. To make
substrings like this, use the substring_with_shared_superstring() API.
One caveat:
- String does not guarantee that the underlying data is null-terminated
like DeprecatedString does today. While this was nifty in a handful of
places where we were calling C functions, it did stand in the way of
shared-superstring substrings.
2022-12-01 12:27:43 +00:00
|
|
|
{
|
2023-12-16 14:19:34 +00:00
|
|
|
return String::from_utf8(byte_string.view());
|
AK: Introduce the new String, replacement for DeprecatedString
DeprecatedString (formerly String) has been with us since the start,
and it has served us well. However, it has a number of shortcomings
that I'd like to address.
Some of these issues are hard if not impossible to solve incrementally
inside of DeprecatedString, so instead of doing that, let's build a new
String class and then incrementally move over to it instead.
Problems in DeprecatedString:
- It assumes string allocation never fails. This makes it impossible
to use in allocation-sensitive contexts, and is the reason we had to
ban DeprecatedString from the kernel entirely.
- The awkward null state. DeprecatedString can be null. It's different
from the empty state, although null strings are considered empty.
All code is immediately nicer when using Optional<DeprecatedString>
but DeprecatedString came before Optional, which is how we ended up
like this.
- The encoding of the underlying data is ambiguous. For the most part,
we use it as if it's always UTF-8, but there have been cases where
we pass around strings in other encodings (e.g ISO8859-1)
- operator[] and length() are used to iterate over DeprecatedString one
byte at a time. This is done all over the codebase, and will *not*
give the right results unless the string is all ASCII.
How we solve these issues in the new String:
- Functions that may allocate now return ErrorOr<String> so that ENOMEM
errors can be passed to the caller.
- String has no null state. Use Optional<String> when needed.
- String is always UTF-8. This is validated when constructing a String.
We may need to add a bypass for this in the future, for cases where
you have a known-good string, but for now: validate all the things!
- There is no operator[] or length(). You can get the underlying data
with bytes(), but for iterating over code points, you should be using
an UTF-8 iterator.
Furthermore, it has two nifty new features:
- String implements a small string optimization (SSO) for strings that
can fit entirely within a pointer. This means up to 3 bytes on 32-bit
platforms, and 7 bytes on 64-bit platforms. Such small strings will
not be heap-allocated.
- String can create substrings without making a deep copy of the
substring. Instead, the superstring gets +1 refcount from the
substring, and it acts like a view into the superstring. To make
substrings like this, use the substring_with_shared_superstring() API.
One caveat:
- String does not guarantee that the underlying data is null-terminated
like DeprecatedString does today. While this was nifty in a handful of
places where we were calling C functions, it did stand in the way of
shared-superstring substrings.
2022-12-01 12:27:43 +00:00
|
|
|
}
|
|
|
|
|
2024-10-14 08:51:15 +00:00
|
|
|
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)
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
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)
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
return String::from_utf8_without_validation(uppercase_bytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool String::equals_ignoring_ascii_case(String const& other) const
|
|
|
|
{
|
|
|
|
return StringUtils::equals_ignoring_ascii_case(bytes_as_string_view(), other.bytes_as_string_view());
|
|
|
|
}
|
|
|
|
|
2023-11-04 09:07:01 +00:00
|
|
|
bool String::equals_ignoring_ascii_case(StringView other) const
|
|
|
|
{
|
|
|
|
return StringUtils::equals_ignoring_ascii_case(bytes_as_string_view(), other);
|
|
|
|
}
|
|
|
|
|
2024-04-18 09:35:35 +00:00
|
|
|
ErrorOr<String> String::repeated(String const& input, size_t count)
|
2023-12-29 12:20:11 +00:00
|
|
|
{
|
2024-05-06 19:52:11 +00:00
|
|
|
if (Checked<u32>::multiplication_would_overflow(count, input.bytes().size()))
|
2024-04-18 09:35:35 +00:00
|
|
|
return Error::from_errno(EOVERFLOW);
|
2023-12-29 12:20:11 +00:00
|
|
|
|
2023-10-28 21:15:40 +00:00
|
|
|
String result;
|
|
|
|
size_t input_size = input.bytes().size();
|
2024-04-18 09:35:35 +00:00
|
|
|
TRY(result.replace_with_new_string(count * input_size, [&](Bytes buffer) {
|
2023-10-28 21:15:40 +00:00
|
|
|
if (input_size == 1) {
|
|
|
|
buffer.fill(input.bytes().first());
|
|
|
|
} else {
|
|
|
|
for (size_t i = 0; i < count; ++i)
|
|
|
|
input.bytes().copy_to(buffer.slice(i * input_size, input_size));
|
|
|
|
}
|
|
|
|
return ErrorOr<void> {};
|
|
|
|
}));
|
2024-04-18 09:35:35 +00:00
|
|
|
|
2023-10-28 21:15:40 +00:00
|
|
|
return result;
|
2023-12-29 12:20:11 +00:00
|
|
|
}
|
|
|
|
|
AK: Introduce the new String, replacement for DeprecatedString
DeprecatedString (formerly String) has been with us since the start,
and it has served us well. However, it has a number of shortcomings
that I'd like to address.
Some of these issues are hard if not impossible to solve incrementally
inside of DeprecatedString, so instead of doing that, let's build a new
String class and then incrementally move over to it instead.
Problems in DeprecatedString:
- It assumes string allocation never fails. This makes it impossible
to use in allocation-sensitive contexts, and is the reason we had to
ban DeprecatedString from the kernel entirely.
- The awkward null state. DeprecatedString can be null. It's different
from the empty state, although null strings are considered empty.
All code is immediately nicer when using Optional<DeprecatedString>
but DeprecatedString came before Optional, which is how we ended up
like this.
- The encoding of the underlying data is ambiguous. For the most part,
we use it as if it's always UTF-8, but there have been cases where
we pass around strings in other encodings (e.g ISO8859-1)
- operator[] and length() are used to iterate over DeprecatedString one
byte at a time. This is done all over the codebase, and will *not*
give the right results unless the string is all ASCII.
How we solve these issues in the new String:
- Functions that may allocate now return ErrorOr<String> so that ENOMEM
errors can be passed to the caller.
- String has no null state. Use Optional<String> when needed.
- String is always UTF-8. This is validated when constructing a String.
We may need to add a bypass for this in the future, for cases where
you have a known-good string, but for now: validate all the things!
- There is no operator[] or length(). You can get the underlying data
with bytes(), but for iterating over code points, you should be using
an UTF-8 iterator.
Furthermore, it has two nifty new features:
- String implements a small string optimization (SSO) for strings that
can fit entirely within a pointer. This means up to 3 bytes on 32-bit
platforms, and 7 bytes on 64-bit platforms. Such small strings will
not be heap-allocated.
- String can create substrings without making a deep copy of the
substring. Instead, the superstring gets +1 refcount from the
substring, and it acts like a view into the superstring. To make
substrings like this, use the substring_with_shared_superstring() API.
One caveat:
- String does not guarantee that the underlying data is null-terminated
like DeprecatedString does today. While this was nifty in a handful of
places where we were calling C functions, it did stand in the way of
shared-superstring substrings.
2022-12-01 12:27:43 +00:00
|
|
|
}
|