mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-19 15:32:31 +00:00
LibJS+LibWeb: Replace JS::Utf16String with AK::Utf16String
This commit is contained in:
parent
d40e3af697
commit
a43cb15e81
Notes:
github-actions[bot]
2025-07-18 16:46:59 +00:00
Author: https://github.com/trflynn89
Commit: a43cb15e81
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5388
Reviewed-by: https://github.com/shannonbooth ✅
24 changed files with 172 additions and 526 deletions
|
@ -245,7 +245,6 @@ set(SOURCES
|
||||||
Runtime/TypedArrayConstructor.cpp
|
Runtime/TypedArrayConstructor.cpp
|
||||||
Runtime/TypedArrayPrototype.cpp
|
Runtime/TypedArrayPrototype.cpp
|
||||||
Runtime/Uint8Array.cpp
|
Runtime/Uint8Array.cpp
|
||||||
Runtime/Utf16String.cpp
|
|
||||||
Runtime/Value.cpp
|
Runtime/Value.cpp
|
||||||
Runtime/VM.cpp
|
Runtime/VM.cpp
|
||||||
Runtime/WeakMap.cpp
|
Runtime/WeakMap.cpp
|
||||||
|
|
|
@ -219,7 +219,6 @@ struct SourceRange;
|
||||||
class SourceTextModule;
|
class SourceTextModule;
|
||||||
class Symbol;
|
class Symbol;
|
||||||
class Token;
|
class Token;
|
||||||
class Utf16String;
|
|
||||||
class VM;
|
class VM;
|
||||||
class PrototypeChainValidity;
|
class PrototypeChainValidity;
|
||||||
class Value;
|
class Value;
|
||||||
|
|
|
@ -774,11 +774,9 @@ ErrorOr<void> print_intl_segmenter(JS::PrintContext& print_context, JS::Intl::Se
|
||||||
|
|
||||||
ErrorOr<void> print_intl_segments(JS::PrintContext& print_context, JS::Intl::Segments const& segments, HashTable<JS::Object*>& seen_objects)
|
ErrorOr<void> print_intl_segments(JS::PrintContext& print_context, JS::Intl::Segments const& segments, HashTable<JS::Object*>& seen_objects)
|
||||||
{
|
{
|
||||||
auto segments_string = JS::Utf16String::create(segments.segments_string());
|
|
||||||
|
|
||||||
TRY(print_type(print_context, "Segments"sv));
|
TRY(print_type(print_context, "Segments"sv));
|
||||||
TRY(js_out(print_context, "\n string: "));
|
TRY(js_out(print_context, "\n string: "));
|
||||||
TRY(print_value(print_context, JS::PrimitiveString::create(segments.vm(), move(segments_string)), seen_objects));
|
TRY(print_value(print_context, JS::PrimitiveString::create(segments.vm(), segments.segments_string()), seen_objects));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1284,7 +1284,7 @@ ThrowCompletionOr<String> get_substitution(VM& vm, Utf16View const& matched, Utf
|
||||||
|
|
||||||
// 4. Let templateRemainder be replacementTemplate.
|
// 4. Let templateRemainder be replacementTemplate.
|
||||||
auto replace_template_string = TRY(replacement_template.to_utf16_string(vm));
|
auto replace_template_string = TRY(replacement_template.to_utf16_string(vm));
|
||||||
auto template_remainder = replace_template_string.view();
|
Utf16View template_remainder { replace_template_string };
|
||||||
|
|
||||||
// 5. Repeat, while templateRemainder is not the empty String,
|
// 5. Repeat, while templateRemainder is not the empty String,
|
||||||
while (!template_remainder.is_empty()) {
|
while (!template_remainder.is_empty()) {
|
||||||
|
@ -1387,7 +1387,7 @@ ThrowCompletionOr<String> get_substitution(VM& vm, Utf16View const& matched, Utf
|
||||||
else {
|
else {
|
||||||
// a. Let refReplacement be capture.
|
// a. Let refReplacement be capture.
|
||||||
capture_string = TRY(capture.to_utf16_string(vm));
|
capture_string = TRY(capture.to_utf16_string(vm));
|
||||||
ref_replacement = capture_string->view();
|
ref_replacement = *capture_string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ix. Else,
|
// ix. Else,
|
||||||
|
@ -1434,7 +1434,7 @@ ThrowCompletionOr<String> get_substitution(VM& vm, Utf16View const& matched, Utf
|
||||||
else {
|
else {
|
||||||
// a. Let refReplacement be ? ToString(capture).
|
// a. Let refReplacement be ? ToString(capture).
|
||||||
capture_string = TRY(capture.to_utf16_string(vm));
|
capture_string = TRY(capture.to_utf16_string(vm));
|
||||||
ref_replacement = capture_string->view();
|
ref_replacement = *capture_string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -387,7 +387,7 @@ JS_DEFINE_NATIVE_FUNCTION(GlobalObject::parse_int)
|
||||||
// 19.2.6.5 Encode ( string, extraUnescaped ), https://tc39.es/ecma262/#sec-encode
|
// 19.2.6.5 Encode ( string, extraUnescaped ), https://tc39.es/ecma262/#sec-encode
|
||||||
static ThrowCompletionOr<ByteString> encode(VM& vm, ByteString const& string, StringView unescaped_set)
|
static ThrowCompletionOr<ByteString> encode(VM& vm, ByteString const& string, StringView unescaped_set)
|
||||||
{
|
{
|
||||||
auto utf16_string = Utf16String::create(string);
|
auto utf16_string = Utf16String::from_utf8(string);
|
||||||
|
|
||||||
// 1. Let strLen be the length of string.
|
// 1. Let strLen be the length of string.
|
||||||
auto string_length = utf16_string.length_in_code_units();
|
auto string_length = utf16_string.length_in_code_units();
|
||||||
|
@ -421,7 +421,7 @@ static ThrowCompletionOr<ByteString> encode(VM& vm, ByteString const& string, St
|
||||||
// d. Else,
|
// d. Else,
|
||||||
else {
|
else {
|
||||||
// i. Let cp be CodePointAt(string, k).
|
// i. Let cp be CodePointAt(string, k).
|
||||||
auto code_point = code_point_at(utf16_string.view(), k);
|
auto code_point = code_point_at(utf16_string, k);
|
||||||
// ii. If cp.[[IsUnpairedSurrogate]] is true, throw a URIError exception.
|
// ii. If cp.[[IsUnpairedSurrogate]] is true, throw a URIError exception.
|
||||||
if (code_point.is_unpaired_surrogate)
|
if (code_point.is_unpaired_surrogate)
|
||||||
return vm.throw_completion<URIError>(ErrorType::URIMalformed);
|
return vm.throw_completion<URIError>(ErrorType::URIMalformed);
|
||||||
|
|
|
@ -57,13 +57,13 @@ ThrowCompletionOr<GC::Ref<Object>> create_segment_data_object(VM& vm, Unicode::S
|
||||||
auto segment = string.substring_view(start_index, end_index - start_index);
|
auto segment = string.substring_view(start_index, end_index - start_index);
|
||||||
|
|
||||||
// 7. Perform ! CreateDataPropertyOrThrow(result, "segment", segment).
|
// 7. Perform ! CreateDataPropertyOrThrow(result, "segment", segment).
|
||||||
MUST(result->create_data_property_or_throw(vm.names.segment, PrimitiveString::create(vm, Utf16String::create(segment))));
|
MUST(result->create_data_property_or_throw(vm.names.segment, PrimitiveString::create(vm, segment)));
|
||||||
|
|
||||||
// 8. Perform ! CreateDataPropertyOrThrow(result, "index", 𝔽(startIndex)).
|
// 8. Perform ! CreateDataPropertyOrThrow(result, "index", 𝔽(startIndex)).
|
||||||
MUST(result->create_data_property_or_throw(vm.names.index, Value(start_index)));
|
MUST(result->create_data_property_or_throw(vm.names.index, Value(start_index)));
|
||||||
|
|
||||||
// 9. Perform ! CreateDataPropertyOrThrow(result, "input", string).
|
// 9. Perform ! CreateDataPropertyOrThrow(result, "input", string).
|
||||||
MUST(result->create_data_property_or_throw(vm.names.input, PrimitiveString::create(vm, Utf16String::create(string))));
|
MUST(result->create_data_property_or_throw(vm.names.input, PrimitiveString::create(vm, string)));
|
||||||
|
|
||||||
// 10. Let granularity be segmenter.[[SegmenterGranularity]].
|
// 10. Let granularity be segmenter.[[SegmenterGranularity]].
|
||||||
auto granularity = segmenter.segmenter_granularity();
|
auto granularity = segmenter.segmenter_granularity();
|
||||||
|
|
|
@ -29,7 +29,7 @@ Segments::Segments(Realm& realm, Unicode::Segmenter const& segmenter, Utf16Strin
|
||||||
, m_segments_segmenter(segmenter.clone())
|
, m_segments_segmenter(segmenter.clone())
|
||||||
, m_segments_string(move(string))
|
, m_segments_string(move(string))
|
||||||
{
|
{
|
||||||
m_segments_segmenter->set_segmented_text(m_segments_string.view());
|
m_segments_segmenter->set_segmented_text(m_segments_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ public:
|
||||||
|
|
||||||
Unicode::Segmenter& segments_segmenter() const { return *m_segments_segmenter; }
|
Unicode::Segmenter& segments_segmenter() const { return *m_segments_segmenter; }
|
||||||
|
|
||||||
Utf16View segments_string() const { return m_segments_string.view(); }
|
Utf16String const& segments_string() const { return m_segments_string; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Segments(Realm&, Unicode::Segmenter const&, Utf16String);
|
Segments(Realm&, Unicode::Segmenter const&, Utf16String);
|
||||||
|
|
|
@ -76,7 +76,7 @@ JS_DEFINE_NATIVE_FUNCTION(SegmentsPrototype::symbol_iterator)
|
||||||
auto& segmenter = segments->segments_segmenter();
|
auto& segmenter = segments->segments_segmenter();
|
||||||
|
|
||||||
// 4. Let string be segments.[[SegmentsString]].
|
// 4. Let string be segments.[[SegmentsString]].
|
||||||
auto string = segments->segments_string();
|
auto const& string = segments->segments_string();
|
||||||
|
|
||||||
// 5. Return ! CreateSegmentIterator(segmenter, string).
|
// 5. Return ! CreateSegmentIterator(segmenter, string).
|
||||||
return SegmentIterator::create(realm, segmenter, string, segments);
|
return SegmentIterator::create(realm, segmenter, string, segments);
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <AK/FlyString.h>
|
#include <AK/FlyString.h>
|
||||||
#include <AK/StringBuilder.h>
|
#include <AK/StringBuilder.h>
|
||||||
#include <AK/UnicodeUtils.h>
|
#include <AK/UnicodeUtils.h>
|
||||||
|
#include <AK/Utf16FlyString.h>
|
||||||
#include <AK/Utf16View.h>
|
#include <AK/Utf16View.h>
|
||||||
#include <AK/Utf8View.h>
|
#include <AK/Utf8View.h>
|
||||||
#include <LibJS/Runtime/AbstractOperations.h>
|
#include <LibJS/Runtime/AbstractOperations.h>
|
||||||
|
@ -23,18 +24,80 @@ namespace JS {
|
||||||
GC_DEFINE_ALLOCATOR(PrimitiveString);
|
GC_DEFINE_ALLOCATOR(PrimitiveString);
|
||||||
GC_DEFINE_ALLOCATOR(RopeString);
|
GC_DEFINE_ALLOCATOR(RopeString);
|
||||||
|
|
||||||
RopeString::RopeString(GC::Ref<PrimitiveString> lhs, GC::Ref<PrimitiveString> rhs)
|
GC::Ref<PrimitiveString> PrimitiveString::create(VM& vm, Utf16String string)
|
||||||
: PrimitiveString(RopeTag::Rope)
|
|
||||||
, m_lhs(lhs)
|
|
||||||
, m_rhs(rhs)
|
|
||||||
{
|
{
|
||||||
|
if (string.is_empty())
|
||||||
|
return vm.empty_string();
|
||||||
|
|
||||||
|
if (string.length_in_code_units() == 1) {
|
||||||
|
if (auto code_unit = string.code_unit_at(0); is_ascii(code_unit))
|
||||||
|
return vm.single_ascii_character_string(static_cast<u8>(code_unit));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& string_cache = vm.utf16_string_cache();
|
||||||
|
if (auto it = string_cache.find(string); it != string_cache.end())
|
||||||
|
return *it->value;
|
||||||
|
|
||||||
|
auto new_string = vm.heap().allocate<PrimitiveString>(string);
|
||||||
|
string_cache.set(move(string), new_string);
|
||||||
|
return *new_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
RopeString::~RopeString() = default;
|
GC::Ref<PrimitiveString> PrimitiveString::create(VM& vm, Utf16View const& string)
|
||||||
|
|
||||||
PrimitiveString::PrimitiveString(String string)
|
|
||||||
: m_utf8_string(move(string))
|
|
||||||
{
|
{
|
||||||
|
return create(vm, Utf16String::from_utf16(string));
|
||||||
|
}
|
||||||
|
|
||||||
|
GC::Ref<PrimitiveString> PrimitiveString::create(VM& vm, Utf16FlyString const& string)
|
||||||
|
{
|
||||||
|
return create(vm, string.to_utf16_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
GC::Ref<PrimitiveString> PrimitiveString::create(VM& vm, String string)
|
||||||
|
{
|
||||||
|
if (string.is_empty())
|
||||||
|
return vm.empty_string();
|
||||||
|
|
||||||
|
if (auto bytes = string.bytes_as_string_view(); bytes.length() == 1) {
|
||||||
|
if (auto ch = static_cast<u8>(bytes[0]); is_ascii(ch))
|
||||||
|
return vm.single_ascii_character_string(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& string_cache = vm.string_cache();
|
||||||
|
if (auto it = string_cache.find(string); it != string_cache.end())
|
||||||
|
return *it->value;
|
||||||
|
|
||||||
|
auto new_string = vm.heap().allocate<PrimitiveString>(string);
|
||||||
|
string_cache.set(move(string), new_string);
|
||||||
|
return *new_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
GC::Ref<PrimitiveString> PrimitiveString::create(VM& vm, StringView string)
|
||||||
|
{
|
||||||
|
return create(vm, String::from_utf8(string).release_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
GC::Ref<PrimitiveString> PrimitiveString::create(VM& vm, FlyString const& string)
|
||||||
|
{
|
||||||
|
return create(vm, string.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
GC::Ref<PrimitiveString> PrimitiveString::create(VM& vm, PrimitiveString& lhs, PrimitiveString& rhs)
|
||||||
|
{
|
||||||
|
// We're here to concatenate two strings into a new rope string. However, if any of them are empty, no rope is required.
|
||||||
|
bool lhs_empty = lhs.is_empty();
|
||||||
|
bool rhs_empty = rhs.is_empty();
|
||||||
|
|
||||||
|
if (lhs_empty && rhs_empty)
|
||||||
|
return vm.empty_string();
|
||||||
|
|
||||||
|
if (lhs_empty)
|
||||||
|
return rhs;
|
||||||
|
|
||||||
|
if (rhs_empty)
|
||||||
|
return lhs;
|
||||||
|
|
||||||
|
return vm.heap().allocate<RopeString>(lhs, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
PrimitiveString::PrimitiveString(Utf16String string)
|
PrimitiveString::PrimitiveString(Utf16String string)
|
||||||
|
@ -42,19 +105,17 @@ PrimitiveString::PrimitiveString(Utf16String string)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
PrimitiveString::~PrimitiveString()
|
PrimitiveString::PrimitiveString(String string)
|
||||||
|
: m_utf8_string(move(string))
|
||||||
{
|
{
|
||||||
if (has_utf8_string())
|
|
||||||
vm().string_cache().remove(*m_utf8_string);
|
|
||||||
if (has_utf16_string())
|
|
||||||
vm().utf16_string_cache().remove(*m_utf16_string);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RopeString::visit_edges(Cell::Visitor& visitor)
|
PrimitiveString::~PrimitiveString()
|
||||||
{
|
{
|
||||||
Base::visit_edges(visitor);
|
if (has_utf16_string())
|
||||||
visitor.visit(m_lhs);
|
vm().utf16_string_cache().remove(*m_utf16_string);
|
||||||
visitor.visit(m_rhs);
|
if (has_utf8_string())
|
||||||
|
vm().string_cache().remove(*m_utf8_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PrimitiveString::is_empty() const
|
bool PrimitiveString::is_empty() const
|
||||||
|
@ -95,7 +156,7 @@ Utf16String PrimitiveString::utf16_string() const
|
||||||
|
|
||||||
if (!has_utf16_string()) {
|
if (!has_utf16_string()) {
|
||||||
VERIFY(has_utf8_string());
|
VERIFY(has_utf8_string());
|
||||||
m_utf16_string = Utf16String::create(m_utf8_string->bytes_as_string_view());
|
m_utf16_string = Utf16String::from_utf8(*m_utf8_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
return *m_utf16_string;
|
return *m_utf16_string;
|
||||||
|
@ -104,7 +165,7 @@ Utf16String PrimitiveString::utf16_string() const
|
||||||
Utf16View PrimitiveString::utf16_string_view() const
|
Utf16View PrimitiveString::utf16_string_view() const
|
||||||
{
|
{
|
||||||
(void)utf16_string();
|
(void)utf16_string();
|
||||||
return m_utf16_string->view();
|
return *m_utf16_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t PrimitiveString::length_in_utf16_code_units() const
|
size_t PrimitiveString::length_in_utf16_code_units() const
|
||||||
|
@ -119,7 +180,7 @@ bool PrimitiveString::operator==(PrimitiveString const& other) const
|
||||||
if (m_utf8_string.has_value() && other.m_utf8_string.has_value())
|
if (m_utf8_string.has_value() && other.m_utf8_string.has_value())
|
||||||
return m_utf8_string->bytes_as_string_view() == other.m_utf8_string->bytes_as_string_view();
|
return m_utf8_string->bytes_as_string_view() == other.m_utf8_string->bytes_as_string_view();
|
||||||
if (m_utf16_string.has_value() && other.m_utf16_string.has_value())
|
if (m_utf16_string.has_value() && other.m_utf16_string.has_value())
|
||||||
return m_utf16_string->string() == other.m_utf16_string->string();
|
return *m_utf16_string == *other.m_utf16_string;
|
||||||
return utf8_string_view() == other.utf8_string_view();
|
return utf8_string_view() == other.utf8_string_view();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,89 +188,22 @@ ThrowCompletionOr<Optional<Value>> PrimitiveString::get(VM& vm, PropertyKey cons
|
||||||
{
|
{
|
||||||
if (property_key.is_symbol())
|
if (property_key.is_symbol())
|
||||||
return Optional<Value> {};
|
return Optional<Value> {};
|
||||||
|
|
||||||
if (property_key.is_string()) {
|
if (property_key.is_string()) {
|
||||||
if (property_key.as_string() == vm.names.length.as_string()) {
|
if (property_key.as_string() == vm.names.length.as_string()) {
|
||||||
return Value(static_cast<double>(length_in_utf16_code_units()));
|
return Value(static_cast<double>(length_in_utf16_code_units()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto index = canonical_numeric_index_string(property_key, CanonicalIndexMode::IgnoreNumericRoundtrip);
|
auto index = canonical_numeric_index_string(property_key, CanonicalIndexMode::IgnoreNumericRoundtrip);
|
||||||
if (!index.is_index())
|
if (!index.is_index())
|
||||||
return Optional<Value> {};
|
return Optional<Value> {};
|
||||||
auto str = utf16_string_view();
|
|
||||||
auto length = str.length_in_code_units();
|
auto string = utf16_string_view();
|
||||||
if (length <= index.as_index())
|
if (string.length_in_code_units() <= index.as_index())
|
||||||
return Optional<Value> {};
|
return Optional<Value> {};
|
||||||
return create(vm, Utf16String::create(str.substring_view(index.as_index(), 1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
GC::Ref<PrimitiveString> PrimitiveString::create(VM& vm, Utf16String string)
|
return create(vm, string.substring_view(index.as_index(), 1));
|
||||||
{
|
|
||||||
if (string.is_empty())
|
|
||||||
return vm.empty_string();
|
|
||||||
|
|
||||||
if (string.length_in_code_units() == 1) {
|
|
||||||
u16 code_unit = string.code_unit_at(0);
|
|
||||||
if (is_ascii(code_unit))
|
|
||||||
return vm.single_ascii_character_string(static_cast<u8>(code_unit));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& string_cache = vm.utf16_string_cache();
|
|
||||||
if (auto it = string_cache.find(string); it != string_cache.end())
|
|
||||||
return *it->value;
|
|
||||||
|
|
||||||
auto new_string = vm.heap().allocate<PrimitiveString>(string);
|
|
||||||
string_cache.set(move(string), new_string);
|
|
||||||
return *new_string;
|
|
||||||
}
|
|
||||||
|
|
||||||
GC::Ref<PrimitiveString> PrimitiveString::create(VM& vm, String string)
|
|
||||||
{
|
|
||||||
if (string.is_empty())
|
|
||||||
return vm.empty_string();
|
|
||||||
|
|
||||||
if (auto bytes = string.bytes_as_string_view(); bytes.length() == 1) {
|
|
||||||
auto ch = static_cast<u8>(bytes[0]);
|
|
||||||
if (is_ascii(ch))
|
|
||||||
return vm.single_ascii_character_string(ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& string_cache = vm.string_cache();
|
|
||||||
if (auto it = string_cache.find(string); it != string_cache.end())
|
|
||||||
return *it->value;
|
|
||||||
|
|
||||||
auto new_string = vm.heap().allocate<PrimitiveString>(string);
|
|
||||||
string_cache.set(move(string), new_string);
|
|
||||||
return *new_string;
|
|
||||||
}
|
|
||||||
|
|
||||||
GC::Ref<PrimitiveString> PrimitiveString::create(VM& vm, FlyString const& string)
|
|
||||||
{
|
|
||||||
return create(vm, string.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
GC::Ref<PrimitiveString> PrimitiveString::create(VM& vm, StringView string)
|
|
||||||
{
|
|
||||||
return create(vm, String::from_utf8(string).release_value());
|
|
||||||
}
|
|
||||||
|
|
||||||
GC::Ref<PrimitiveString> PrimitiveString::create(VM& vm, PrimitiveString& lhs, PrimitiveString& rhs)
|
|
||||||
{
|
|
||||||
// We're here to concatenate two strings into a new rope string.
|
|
||||||
// However, if any of them are empty, no rope is required.
|
|
||||||
|
|
||||||
bool lhs_empty = lhs.is_empty();
|
|
||||||
bool rhs_empty = rhs.is_empty();
|
|
||||||
|
|
||||||
if (lhs_empty && rhs_empty)
|
|
||||||
return vm.empty_string();
|
|
||||||
|
|
||||||
if (lhs_empty)
|
|
||||||
return rhs;
|
|
||||||
|
|
||||||
if (rhs_empty)
|
|
||||||
return lhs;
|
|
||||||
|
|
||||||
return vm.heap().allocate<RopeString>(lhs, rhs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrimitiveString::resolve_rope_if_needed(EncodingPreference preference) const
|
void PrimitiveString::resolve_rope_if_needed(EncodingPreference preference) const
|
||||||
|
@ -218,7 +212,7 @@ void PrimitiveString::resolve_rope_if_needed(EncodingPreference preference) cons
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto const& rope_string = static_cast<RopeString const&>(*this);
|
auto const& rope_string = static_cast<RopeString const&>(*this);
|
||||||
return rope_string.resolve(preference);
|
rope_string.resolve(preference);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RopeString::resolve(EncodingPreference preference) const
|
void RopeString::resolve(EncodingPreference preference) const
|
||||||
|
@ -251,12 +245,16 @@ void RopeString::resolve(EncodingPreference preference) const
|
||||||
if (preference == EncodingPreference::UTF16) {
|
if (preference == EncodingPreference::UTF16) {
|
||||||
// The caller wants a UTF-16 string, so we can simply concatenate all the pieces
|
// The caller wants a UTF-16 string, so we can simply concatenate all the pieces
|
||||||
// into a UTF-16 code unit buffer and create a Utf16String from it.
|
// into a UTF-16 code unit buffer and create a Utf16String from it.
|
||||||
|
StringBuilder builder(StringBuilder::Mode::UTF16);
|
||||||
|
|
||||||
Utf16Data code_units;
|
for (auto const* current : pieces) {
|
||||||
for (auto const* current : pieces)
|
if (current->has_utf8_string())
|
||||||
code_units.extend(current->utf16_string().string());
|
builder.append(current->utf8_string_view());
|
||||||
|
else
|
||||||
|
builder.append(current->utf16_string_view());
|
||||||
|
}
|
||||||
|
|
||||||
m_utf16_string = Utf16String::create(move(code_units));
|
m_utf16_string = builder.to_utf16_string_without_validation();
|
||||||
m_is_rope = false;
|
m_is_rope = false;
|
||||||
m_lhs = nullptr;
|
m_lhs = nullptr;
|
||||||
m_rhs = nullptr;
|
m_rhs = nullptr;
|
||||||
|
@ -331,4 +329,20 @@ void RopeString::resolve(EncodingPreference preference) const
|
||||||
m_rhs = nullptr;
|
m_rhs = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RopeString::RopeString(GC::Ref<PrimitiveString> lhs, GC::Ref<PrimitiveString> rhs)
|
||||||
|
: PrimitiveString(RopeTag::Rope)
|
||||||
|
, m_lhs(lhs)
|
||||||
|
, m_rhs(rhs)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RopeString::~RopeString() = default;
|
||||||
|
|
||||||
|
void RopeString::visit_edges(Cell::Visitor& visitor)
|
||||||
|
{
|
||||||
|
Base::visit_edges(visitor);
|
||||||
|
visitor.visit(m_lhs);
|
||||||
|
visitor.visit(m_rhs);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,11 @@
|
||||||
#include <AK/Optional.h>
|
#include <AK/Optional.h>
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
#include <AK/StringView.h>
|
#include <AK/StringView.h>
|
||||||
|
#include <AK/Utf16String.h>
|
||||||
#include <LibGC/CellAllocator.h>
|
#include <LibGC/CellAllocator.h>
|
||||||
#include <LibJS/Forward.h>
|
#include <LibJS/Forward.h>
|
||||||
#include <LibJS/Heap/Cell.h>
|
#include <LibJS/Heap/Cell.h>
|
||||||
#include <LibJS/Runtime/Completion.h>
|
#include <LibJS/Runtime/Completion.h>
|
||||||
#include <LibJS/Runtime/Utf16String.h>
|
|
||||||
#include <LibJS/Runtime/Value.h>
|
#include <LibJS/Runtime/Value.h>
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
@ -25,10 +25,14 @@ class JS_API PrimitiveString : public Cell {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] static GC::Ref<PrimitiveString> create(VM&, Utf16String);
|
[[nodiscard]] static GC::Ref<PrimitiveString> create(VM&, Utf16String);
|
||||||
|
[[nodiscard]] static GC::Ref<PrimitiveString> create(VM&, Utf16View const&);
|
||||||
|
[[nodiscard]] static GC::Ref<PrimitiveString> create(VM&, Utf16FlyString const&);
|
||||||
|
|
||||||
[[nodiscard]] static GC::Ref<PrimitiveString> create(VM&, String);
|
[[nodiscard]] static GC::Ref<PrimitiveString> create(VM&, String);
|
||||||
[[nodiscard]] static GC::Ref<PrimitiveString> create(VM&, FlyString const&);
|
|
||||||
[[nodiscard]] static GC::Ref<PrimitiveString> create(VM&, PrimitiveString&, PrimitiveString&);
|
|
||||||
[[nodiscard]] static GC::Ref<PrimitiveString> create(VM&, StringView);
|
[[nodiscard]] static GC::Ref<PrimitiveString> create(VM&, StringView);
|
||||||
|
[[nodiscard]] static GC::Ref<PrimitiveString> create(VM&, FlyString const&);
|
||||||
|
|
||||||
|
[[nodiscard]] static GC::Ref<PrimitiveString> create(VM&, PrimitiveString&, PrimitiveString&);
|
||||||
|
|
||||||
virtual ~PrimitiveString();
|
virtual ~PrimitiveString();
|
||||||
|
|
||||||
|
@ -71,8 +75,8 @@ protected:
|
||||||
private:
|
private:
|
||||||
friend class RopeString;
|
friend class RopeString;
|
||||||
|
|
||||||
explicit PrimitiveString(String);
|
|
||||||
explicit PrimitiveString(Utf16String);
|
explicit PrimitiveString(Utf16String);
|
||||||
|
explicit PrimitiveString(String);
|
||||||
|
|
||||||
void resolve_rope_if_needed(EncodingPreference) const;
|
void resolve_rope_if_needed(EncodingPreference) const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -94,7 +94,7 @@ void update_legacy_regexp_static_properties(RegExpConstructor& constructor, Utf1
|
||||||
legacy_static_properties.set_input(string);
|
legacy_static_properties.set_input(string);
|
||||||
|
|
||||||
// 8. Set the value of C’s [[RegExpLastMatch]] internal slot to a String whose length is endIndex - startIndex and containing the code units from S with indices startIndex through endIndex - 1, in ascending order.
|
// 8. Set the value of C’s [[RegExpLastMatch]] internal slot to a String whose length is endIndex - startIndex and containing the code units from S with indices startIndex through endIndex - 1, in ascending order.
|
||||||
auto last_match = string.view().substring_view(start_index, end_index - start_index);
|
auto last_match = string.substring_view(start_index, end_index - start_index);
|
||||||
legacy_static_properties.set_last_match(last_match);
|
legacy_static_properties.set_last_match(last_match);
|
||||||
|
|
||||||
// 9. If n > 0, set the value of C’s [[RegExpLastParen]] internal slot to the last element of capturedValues.
|
// 9. If n > 0, set the value of C’s [[RegExpLastParen]] internal slot to the last element of capturedValues.
|
||||||
|
@ -104,22 +104,22 @@ void update_legacy_regexp_static_properties(RegExpConstructor& constructor, Utf1
|
||||||
}
|
}
|
||||||
// 10. Else, set the value of C’s [[RegExpLastParen]] internal slot to the empty String.
|
// 10. Else, set the value of C’s [[RegExpLastParen]] internal slot to the empty String.
|
||||||
else {
|
else {
|
||||||
legacy_static_properties.set_last_paren(Utf16String::create());
|
legacy_static_properties.set_last_paren({});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 11. Set the value of C’s [[RegExpLeftContext]] internal slot to a String whose length is startIndex and containing the code units from S with indices 0 through startIndex - 1, in ascending order.
|
// 11. Set the value of C’s [[RegExpLeftContext]] internal slot to a String whose length is startIndex and containing the code units from S with indices 0 through startIndex - 1, in ascending order.
|
||||||
auto left_context = string.view().substring_view(0, start_index);
|
auto left_context = string.substring_view(0, start_index);
|
||||||
legacy_static_properties.set_left_context(left_context);
|
legacy_static_properties.set_left_context(left_context);
|
||||||
|
|
||||||
// 12. Set the value of C’s [[RegExpRightContext]] internal slot to a String whose length is len - endIndex and containing the code units from S with indices endIndex through len - 1, in ascending order.
|
// 12. Set the value of C’s [[RegExpRightContext]] internal slot to a String whose length is len - endIndex and containing the code units from S with indices endIndex through len - 1, in ascending order.
|
||||||
auto right_context = string.view().substring_view(end_index, len - end_index);
|
auto right_context = string.substring_view(end_index, len - end_index);
|
||||||
legacy_static_properties.set_right_context(right_context);
|
legacy_static_properties.set_right_context(right_context);
|
||||||
|
|
||||||
// 13. For each integer i such that 1 ≤ i ≤ 9
|
// 13. For each integer i such that 1 ≤ i ≤ 9
|
||||||
for (size_t i = 1; i <= 9; i++) {
|
for (size_t i = 1; i <= 9; i++) {
|
||||||
// i. If i ≤ n, set the value of C’s [[RegExpPareni]] internal slot to the ith element of capturedValues.
|
// i. If i ≤ n, set the value of C’s [[RegExpPareni]] internal slot to the ith element of capturedValues.
|
||||||
// ii. Else, set the value of C’s [[RegExpPareni]] internal slot to the empty String.
|
// ii. Else, set the value of C’s [[RegExpPareni]] internal slot to the empty String.
|
||||||
auto value = (i <= group_count) ? captured_values[i - 1] : Utf16String::create();
|
auto value = (i <= group_count) ? captured_values[i - 1] : Utf16String {};
|
||||||
|
|
||||||
if (i == 1) {
|
if (i == 1) {
|
||||||
legacy_static_properties.set_$1(move(value));
|
legacy_static_properties.set_$1(move(value));
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/Optional.h>
|
#include <AK/Optional.h>
|
||||||
|
#include <AK/Utf16String.h>
|
||||||
#include <LibJS/Forward.h>
|
#include <LibJS/Forward.h>
|
||||||
#include <LibJS/Runtime/Utf16String.h>
|
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
|
@ -26,20 +26,20 @@ public:
|
||||||
Optional<Utf16String> const& last_match() const
|
Optional<Utf16String> const& last_match() const
|
||||||
{
|
{
|
||||||
if (!m_last_match_string.has_value())
|
if (!m_last_match_string.has_value())
|
||||||
m_last_match_string = Utf16String::create(m_last_match);
|
m_last_match_string = Utf16String::from_utf16_without_validation(m_last_match);
|
||||||
return m_last_match_string;
|
return m_last_match_string;
|
||||||
}
|
}
|
||||||
Optional<Utf16String> const& last_paren() const { return m_last_paren; }
|
Optional<Utf16String> const& last_paren() const { return m_last_paren; }
|
||||||
Optional<Utf16String> const& left_context() const
|
Optional<Utf16String> const& left_context() const
|
||||||
{
|
{
|
||||||
if (!m_left_context_string.has_value())
|
if (!m_left_context_string.has_value())
|
||||||
m_left_context_string = Utf16String::create(m_left_context);
|
m_left_context_string = Utf16String::from_utf16_without_validation(m_left_context);
|
||||||
return m_left_context_string;
|
return m_left_context_string;
|
||||||
}
|
}
|
||||||
Optional<Utf16String> const& right_context() const
|
Optional<Utf16String> const& right_context() const
|
||||||
{
|
{
|
||||||
if (!m_right_context_string.has_value())
|
if (!m_right_context_string.has_value())
|
||||||
m_right_context_string = Utf16String::create(m_right_context);
|
m_right_context_string = Utf16String::from_utf16_without_validation(m_right_context);
|
||||||
return m_right_context_string;
|
return m_right_context_string;
|
||||||
}
|
}
|
||||||
Optional<Utf16String> const& $1() const { return m_$1; }
|
Optional<Utf16String> const& $1() const { return m_$1; }
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include <AK/CharacterTypes.h>
|
#include <AK/CharacterTypes.h>
|
||||||
#include <AK/Function.h>
|
#include <AK/Function.h>
|
||||||
|
#include <AK/Utf16String.h>
|
||||||
#include <AK/Utf16View.h>
|
#include <AK/Utf16View.h>
|
||||||
#include <LibJS/Runtime/AbstractOperations.h>
|
#include <LibJS/Runtime/AbstractOperations.h>
|
||||||
#include <LibJS/Runtime/Array.h>
|
#include <LibJS/Runtime/Array.h>
|
||||||
|
@ -280,7 +281,7 @@ static ThrowCompletionOr<Value> regexp_builtin_exec(VM& vm, RegExpObject& regexp
|
||||||
|
|
||||||
// 28. Let matchedValue be ! GetMatchString(S, match).
|
// 28. Let matchedValue be ! GetMatchString(S, match).
|
||||||
// 29. Perform ! CreateDataPropertyOrThrow(A, "0", matchedValue).
|
// 29. Perform ! CreateDataPropertyOrThrow(A, "0", matchedValue).
|
||||||
MUST(array->create_data_property_or_throw(0, PrimitiveString::create(vm, Utf16String::create(match.view.u16_view()))));
|
MUST(array->create_data_property_or_throw(0, PrimitiveString::create(vm, match.view.u16_view())));
|
||||||
|
|
||||||
// 30. If R contains any GroupName, then
|
// 30. If R contains any GroupName, then
|
||||||
// a. Let groups be OrdinaryObjectCreate(null).
|
// a. Let groups be OrdinaryObjectCreate(null).
|
||||||
|
@ -305,7 +306,7 @@ static ThrowCompletionOr<Value> regexp_builtin_exec(VM& vm, RegExpObject& regexp
|
||||||
// ii. Append undefined to indices.
|
// ii. Append undefined to indices.
|
||||||
indices.append({});
|
indices.append({});
|
||||||
// iii. Append capture to indices.
|
// iii. Append capture to indices.
|
||||||
captured_values.append(Utf16String::create());
|
captured_values.append({});
|
||||||
}
|
}
|
||||||
// c. Else,
|
// c. Else,
|
||||||
else {
|
else {
|
||||||
|
@ -316,7 +317,7 @@ static ThrowCompletionOr<Value> regexp_builtin_exec(VM& vm, RegExpObject& regexp
|
||||||
// 2. Set captureEnd to ! GetStringIndex(S, Input, captureEnd).
|
// 2. Set captureEnd to ! GetStringIndex(S, Input, captureEnd).
|
||||||
// iv. Let capture be the Match { [[StartIndex]]: captureStart, [[EndIndex]: captureEnd }.
|
// iv. Let capture be the Match { [[StartIndex]]: captureStart, [[EndIndex]: captureEnd }.
|
||||||
// v. Let capturedValue be ! GetMatchString(S, capture).
|
// v. Let capturedValue be ! GetMatchString(S, capture).
|
||||||
auto capture_as_utf16_string = Utf16String::create(capture.view.u16_view());
|
auto capture_as_utf16_string = Utf16String::from_utf16_without_validation(capture.view.u16_view());
|
||||||
captured_value = PrimitiveString::create(vm, capture_as_utf16_string);
|
captured_value = PrimitiveString::create(vm, capture_as_utf16_string);
|
||||||
// vi. Append capture to indices.
|
// vi. Append capture to indices.
|
||||||
indices.append(Match::create(capture));
|
indices.append(Match::create(capture));
|
||||||
|
@ -987,7 +988,7 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_split)
|
||||||
auto substring = string->utf16_string_view().substring_view(last_match_end, next_search_from - last_match_end);
|
auto substring = string->utf16_string_view().substring_view(last_match_end, next_search_from - last_match_end);
|
||||||
|
|
||||||
// 2. Perform ! CreateDataPropertyOrThrow(A, ! ToString(𝔽(lengthA)), T).
|
// 2. Perform ! CreateDataPropertyOrThrow(A, ! ToString(𝔽(lengthA)), T).
|
||||||
MUST(array->create_data_property_or_throw(array_length, PrimitiveString::create(vm, Utf16String::create(substring))));
|
MUST(array->create_data_property_or_throw(array_length, PrimitiveString::create(vm, substring)));
|
||||||
|
|
||||||
// 3. Set lengthA to lengthA + 1.
|
// 3. Set lengthA to lengthA + 1.
|
||||||
++array_length;
|
++array_length;
|
||||||
|
@ -1033,7 +1034,7 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_split)
|
||||||
auto substring = string->utf16_string_view().substring_view(last_match_end);
|
auto substring = string->utf16_string_view().substring_view(last_match_end);
|
||||||
|
|
||||||
// 21. Perform ! CreateDataPropertyOrThrow(A, ! ToString(𝔽(lengthA)), T).
|
// 21. Perform ! CreateDataPropertyOrThrow(A, ! ToString(𝔽(lengthA)), T).
|
||||||
MUST(array->create_data_property_or_throw(array_length, PrimitiveString::create(vm, Utf16String::create(substring))));
|
MUST(array->create_data_property_or_throw(array_length, PrimitiveString::create(vm, substring)));
|
||||||
|
|
||||||
// 22. Return A.
|
// 22. Return A.
|
||||||
return array;
|
return array;
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
#include <LibJS/Runtime/PrototypeObject.h>
|
#include <LibJS/Runtime/PrototypeObject.h>
|
||||||
#include <LibJS/Runtime/RegExpObject.h>
|
#include <LibJS/Runtime/RegExpObject.h>
|
||||||
#include <LibJS/Runtime/Utf16String.h>
|
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,11 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <AK/Utf16View.h>
|
||||||
#include <LibJS/Runtime/GlobalObject.h>
|
#include <LibJS/Runtime/GlobalObject.h>
|
||||||
#include <LibJS/Runtime/Iterator.h>
|
#include <LibJS/Runtime/Iterator.h>
|
||||||
#include <LibJS/Runtime/RegExpPrototype.h>
|
#include <LibJS/Runtime/RegExpPrototype.h>
|
||||||
#include <LibJS/Runtime/RegExpStringIteratorPrototype.h>
|
#include <LibJS/Runtime/RegExpStringIteratorPrototype.h>
|
||||||
#include <LibJS/Runtime/Utf16String.h>
|
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <AK/StringBuilder.h>
|
#include <AK/StringBuilder.h>
|
||||||
#include <AK/UnicodeUtils.h>
|
#include <AK/UnicodeUtils.h>
|
||||||
|
#include <AK/Utf16String.h>
|
||||||
#include <AK/Utf16View.h>
|
#include <AK/Utf16View.h>
|
||||||
#include <LibJS/Runtime/AbstractOperations.h>
|
#include <LibJS/Runtime/AbstractOperations.h>
|
||||||
#include <LibJS/Runtime/Array.h>
|
#include <LibJS/Runtime/Array.h>
|
||||||
|
@ -13,7 +14,6 @@
|
||||||
#include <LibJS/Runtime/GlobalObject.h>
|
#include <LibJS/Runtime/GlobalObject.h>
|
||||||
#include <LibJS/Runtime/StringConstructor.h>
|
#include <LibJS/Runtime/StringConstructor.h>
|
||||||
#include <LibJS/Runtime/StringObject.h>
|
#include <LibJS/Runtime/StringObject.h>
|
||||||
#include <LibJS/Runtime/Utf16String.h>
|
|
||||||
#include <LibJS/Runtime/ValueInlines.h>
|
#include <LibJS/Runtime/ValueInlines.h>
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
@ -89,8 +89,7 @@ ThrowCompletionOr<GC::Ref<Object>> StringConstructor::construct(FunctionObject&
|
||||||
JS_DEFINE_NATIVE_FUNCTION(StringConstructor::from_char_code)
|
JS_DEFINE_NATIVE_FUNCTION(StringConstructor::from_char_code)
|
||||||
{
|
{
|
||||||
// 1. Let result be the empty String.
|
// 1. Let result be the empty String.
|
||||||
Utf16Data string;
|
StringBuilder builder(StringBuilder::Mode::UTF16, vm.argument_count());
|
||||||
string.ensure_capacity(vm.argument_count());
|
|
||||||
|
|
||||||
// 2. For each element next of codeUnits, do
|
// 2. For each element next of codeUnits, do
|
||||||
for (size_t i = 0; i < vm.argument_count(); ++i) {
|
for (size_t i = 0; i < vm.argument_count(); ++i) {
|
||||||
|
@ -98,20 +97,19 @@ JS_DEFINE_NATIVE_FUNCTION(StringConstructor::from_char_code)
|
||||||
auto next_code_unit = TRY(vm.argument(i).to_u16(vm));
|
auto next_code_unit = TRY(vm.argument(i).to_u16(vm));
|
||||||
|
|
||||||
// b. Set result to the string-concatenation of result and nextCU.
|
// b. Set result to the string-concatenation of result and nextCU.
|
||||||
string.append(next_code_unit);
|
builder.append_code_unit(next_code_unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Return result.
|
// 3. Return result.
|
||||||
return PrimitiveString::create(vm, Utf16String::create(move(string)));
|
return PrimitiveString::create(vm, builder.to_utf16_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 22.1.2.2 String.fromCodePoint ( ...codePoints ), https://tc39.es/ecma262/#sec-string.fromcodepoint
|
// 22.1.2.2 String.fromCodePoint ( ...codePoints ), https://tc39.es/ecma262/#sec-string.fromcodepoint
|
||||||
JS_DEFINE_NATIVE_FUNCTION(StringConstructor::from_code_point)
|
JS_DEFINE_NATIVE_FUNCTION(StringConstructor::from_code_point)
|
||||||
{
|
{
|
||||||
// 1. Let result be the empty String.
|
// 1. Let result be the empty String.
|
||||||
Utf16Data string;
|
// NOTE: This will be an under-estimate if any code point is > 0xffff.
|
||||||
// This will be an under-estimate if any code point is > 0xffff.
|
StringBuilder builder(StringBuilder::Mode::UTF16, vm.argument_count());
|
||||||
string.ensure_capacity(vm.argument_count());
|
|
||||||
|
|
||||||
// 2. For each element next of codePoints, do
|
// 2. For each element next of codePoints, do
|
||||||
for (size_t i = 0; i < vm.argument_count(); ++i) {
|
for (size_t i = 0; i < vm.argument_count(); ++i) {
|
||||||
|
@ -130,16 +128,16 @@ JS_DEFINE_NATIVE_FUNCTION(StringConstructor::from_code_point)
|
||||||
|
|
||||||
// d. Set result to the string-concatenation of result and UTF16EncodeCodePoint(ℝ(nextCP)).
|
// d. Set result to the string-concatenation of result and UTF16EncodeCodePoint(ℝ(nextCP)).
|
||||||
(void)AK::UnicodeUtils::code_point_to_utf16(static_cast<u32>(code_point), [&](auto code_unit) {
|
(void)AK::UnicodeUtils::code_point_to_utf16(static_cast<u32>(code_point), [&](auto code_unit) {
|
||||||
string.append(code_unit);
|
builder.append_code_unit(code_unit);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Assert: If codePoints is empty, then result is the empty String.
|
// 3. Assert: If codePoints is empty, then result is the empty String.
|
||||||
if (!vm.argument_count())
|
if (!vm.argument_count())
|
||||||
VERIFY(string.is_empty());
|
VERIFY(builder.is_empty());
|
||||||
|
|
||||||
// 4. Return result.
|
// 4. Return result.
|
||||||
return PrimitiveString::create(vm, Utf16String::create(move(string)));
|
return PrimitiveString::create(vm, builder.to_utf16_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 22.1.2.4 String.raw ( template, ...substitutions ), https://tc39.es/ecma262/#sec-string.raw
|
// 22.1.2.4 String.raw ( template, ...substitutions ), https://tc39.es/ecma262/#sec-string.raw
|
||||||
|
|
|
@ -83,7 +83,7 @@ static ThrowCompletionOr<Optional<PropertyDescriptor>> string_get_own_property(S
|
||||||
return Optional<PropertyDescriptor> {};
|
return Optional<PropertyDescriptor> {};
|
||||||
|
|
||||||
// 10. Let resultStr be the substring of str from ℝ(index) to ℝ(index) + 1.
|
// 10. Let resultStr be the substring of str from ℝ(index) to ℝ(index) + 1.
|
||||||
auto result_str = PrimitiveString::create(vm, Utf16String::create(str.substring_view(index.as_index(), 1)));
|
auto result_str = PrimitiveString::create(vm, str.substring_view(index.as_index(), 1));
|
||||||
|
|
||||||
// 11. Return the PropertyDescriptor { [[Value]]: resultStr, [[Writable]]: false, [[Enumerable]]: true, [[Configurable]]: false }.
|
// 11. Return the PropertyDescriptor { [[Value]]: resultStr, [[Writable]]: false, [[Enumerable]]: true, [[Configurable]]: false }.
|
||||||
return PropertyDescriptor {
|
return PropertyDescriptor {
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
#include <LibJS/Runtime/StringIterator.h>
|
#include <LibJS/Runtime/StringIterator.h>
|
||||||
#include <LibJS/Runtime/StringObject.h>
|
#include <LibJS/Runtime/StringObject.h>
|
||||||
#include <LibJS/Runtime/StringPrototype.h>
|
#include <LibJS/Runtime/StringPrototype.h>
|
||||||
#include <LibJS/Runtime/Utf16String.h>
|
|
||||||
#include <LibJS/Runtime/Value.h>
|
#include <LibJS/Runtime/Value.h>
|
||||||
#include <LibJS/Runtime/ValueInlines.h>
|
#include <LibJS/Runtime/ValueInlines.h>
|
||||||
#include <LibUnicode/CharacterTypes.h>
|
#include <LibUnicode/CharacterTypes.h>
|
||||||
|
@ -259,7 +258,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::at)
|
||||||
return js_undefined();
|
return js_undefined();
|
||||||
|
|
||||||
// 7. Return ? Get(O, ! ToString(𝔽(k))).
|
// 7. Return ? Get(O, ! ToString(𝔽(k))).
|
||||||
return PrimitiveString::create(vm, Utf16String::create(string->utf16_string_view().substring_view(index.value(), 1)));
|
return PrimitiveString::create(vm, string->utf16_string_view().substring_view(index.value(), 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 22.1.3.2 String.prototype.charAt ( pos ), https://tc39.es/ecma262/#sec-string.prototype.charat
|
// 22.1.3.2 String.prototype.charAt ( pos ), https://tc39.es/ecma262/#sec-string.prototype.charat
|
||||||
|
@ -278,7 +277,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::char_at)
|
||||||
return PrimitiveString::create(vm, String {});
|
return PrimitiveString::create(vm, String {});
|
||||||
|
|
||||||
// 6. Return the substring of S from position to position + 1.
|
// 6. Return the substring of S from position to position + 1.
|
||||||
return PrimitiveString::create(vm, Utf16String::create(string->utf16_string_view().substring_view(position, 1)));
|
return PrimitiveString::create(vm, string->utf16_string_view().substring_view(position, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 22.1.3.3 String.prototype.charCodeAt ( pos ), https://tc39.es/ecma262/#sec-string.prototype.charcodeat
|
// 22.1.3.3 String.prototype.charCodeAt ( pos ), https://tc39.es/ecma262/#sec-string.prototype.charcodeat
|
||||||
|
@ -686,7 +685,7 @@ static ThrowCompletionOr<Value> pad_string(VM& vm, GC::Ref<PrimitiveString> stri
|
||||||
return string;
|
return string;
|
||||||
|
|
||||||
// 5. If fillString is undefined, let filler be the String value consisting solely of the code unit 0x0020 (SPACE).
|
// 5. If fillString is undefined, let filler be the String value consisting solely of the code unit 0x0020 (SPACE).
|
||||||
auto filler = Utf16String::create(Utf16Data { 0x20 });
|
auto filler = " "_utf16;
|
||||||
if (!fill_string.is_undefined()) {
|
if (!fill_string.is_undefined()) {
|
||||||
// 6. Else, let filler be ? ToString(fillString).
|
// 6. Else, let filler be ? ToString(fillString).
|
||||||
filler = TRY(fill_string.to_utf16_string(vm));
|
filler = TRY(fill_string.to_utf16_string(vm));
|
||||||
|
@ -702,7 +701,7 @@ static ThrowCompletionOr<Value> pad_string(VM& vm, GC::Ref<PrimitiveString> stri
|
||||||
StringBuilder truncated_string_filler_builder;
|
StringBuilder truncated_string_filler_builder;
|
||||||
auto fill_code_units = filler.length_in_code_units();
|
auto fill_code_units = filler.length_in_code_units();
|
||||||
for (size_t i = 0; i < fill_length / fill_code_units; ++i)
|
for (size_t i = 0; i < fill_length / fill_code_units; ++i)
|
||||||
truncated_string_filler_builder.append(filler.view());
|
truncated_string_filler_builder.append(filler);
|
||||||
|
|
||||||
// 9. Let truncatedStringFiller be the String value consisting of repeated concatenations of filler truncated to length fillLen.
|
// 9. Let truncatedStringFiller be the String value consisting of repeated concatenations of filler truncated to length fillLen.
|
||||||
truncated_string_filler_builder.append(filler.substring_view(0, fill_length % fill_code_units));
|
truncated_string_filler_builder.append(filler.substring_view(0, fill_length % fill_code_units));
|
||||||
|
@ -1046,7 +1045,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::slice)
|
||||||
return PrimitiveString::create(vm, String {});
|
return PrimitiveString::create(vm, String {});
|
||||||
|
|
||||||
// 13. Return the substring of S from from to to.
|
// 13. Return the substring of S from from to to.
|
||||||
return PrimitiveString::create(vm, Utf16String::create(string->utf16_string_view().substring_view(int_start, int_end - int_start)));
|
return PrimitiveString::create(vm, string->utf16_string_view().substring_view(int_start, int_end - int_start));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 22.1.3.23 String.prototype.split ( separator, limit ), https://tc39.es/ecma262/#sec-string.prototype.split
|
// 22.1.3.23 String.prototype.split ( separator, limit ), https://tc39.es/ecma262/#sec-string.prototype.split
|
||||||
|
@ -1127,7 +1126,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::split)
|
||||||
auto segment = string->utf16_string_view().substring_view(start, position - start);
|
auto segment = string->utf16_string_view().substring_view(start, position - start);
|
||||||
|
|
||||||
// b. Append T to substrings.
|
// b. Append T to substrings.
|
||||||
MUST(array->create_data_property_or_throw(array_length, PrimitiveString::create(vm, Utf16String::create(segment))));
|
MUST(array->create_data_property_or_throw(array_length, PrimitiveString::create(vm, segment)));
|
||||||
++array_length;
|
++array_length;
|
||||||
|
|
||||||
// c. If the number of elements in substrings is lim, return CreateArrayFromList(substrings).
|
// c. If the number of elements in substrings is lim, return CreateArrayFromList(substrings).
|
||||||
|
@ -1145,7 +1144,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::split)
|
||||||
auto rest = string->utf16_string_view().substring_view(start);
|
auto rest = string->utf16_string_view().substring_view(start);
|
||||||
|
|
||||||
// 16. Append T to substrings.
|
// 16. Append T to substrings.
|
||||||
MUST(array->create_data_property_or_throw(array_length, PrimitiveString::create(vm, Utf16String::create(rest))));
|
MUST(array->create_data_property_or_throw(array_length, PrimitiveString::create(vm, rest)));
|
||||||
|
|
||||||
// 17. Return CreateArrayFromList(substrings).
|
// 17. Return CreateArrayFromList(substrings).
|
||||||
return array;
|
return array;
|
||||||
|
@ -1237,7 +1236,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::substring)
|
||||||
size_t to = max(final_start, final_end);
|
size_t to = max(final_start, final_end);
|
||||||
|
|
||||||
// 10. Return the substring of S from from to to.
|
// 10. Return the substring of S from from to to.
|
||||||
return PrimitiveString::create(vm, Utf16String::create(string->utf16_string_view().substring_view(from, to - from)));
|
return PrimitiveString::create(vm, string->utf16_string_view().substring_view(from, to - from));
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class TargetCase {
|
enum class TargetCase {
|
||||||
|
@ -1382,7 +1381,7 @@ String to_well_formed_string(Utf16String const& string)
|
||||||
// 6. Repeat, while k < strLen,
|
// 6. Repeat, while k < strLen,
|
||||||
while (k < length) {
|
while (k < length) {
|
||||||
// a. Let cp be CodePointAt(S, k).
|
// a. Let cp be CodePointAt(S, k).
|
||||||
auto code_point = JS::code_point_at(string.view(), k);
|
auto code_point = JS::code_point_at(string, k);
|
||||||
|
|
||||||
// b. If cp.[[IsUnpairedSurrogate]] is true, then
|
// b. If cp.[[IsUnpairedSurrogate]] is true, then
|
||||||
if (code_point.is_unpaired_surrogate) {
|
if (code_point.is_unpaired_surrogate) {
|
||||||
|
@ -1507,7 +1506,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::substr)
|
||||||
return PrimitiveString::create(vm, String {});
|
return PrimitiveString::create(vm, String {});
|
||||||
|
|
||||||
// 11. Return the substring of S from intStart to intEnd.
|
// 11. Return the substring of S from intStart to intEnd.
|
||||||
return PrimitiveString::create(vm, Utf16String::create(string->utf16_string_view().substring_view(int_start, int_end - int_start)));
|
return PrimitiveString::create(vm, string->utf16_string_view().substring_view(int_start, int_end - int_start));
|
||||||
}
|
}
|
||||||
|
|
||||||
// B.2.2.2.1 CreateHTML ( string, tag, attribute, value ), https://tc39.es/ecma262/#sec-createhtml
|
// B.2.2.2.1 CreateHTML ( string, tag, attribute, value ), https://tc39.es/ecma262/#sec-createhtml
|
||||||
|
|
|
@ -1,157 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2021-2023, Tim Flynn <trflynn89@serenityos.org>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <AK/StringView.h>
|
|
||||||
#include <LibJS/Runtime/Utf16String.h>
|
|
||||||
#include <LibJS/Runtime/VM.h>
|
|
||||||
|
|
||||||
namespace JS {
|
|
||||||
namespace Detail {
|
|
||||||
|
|
||||||
static NonnullRefPtr<Utf16StringImpl> the_empty_utf16_string()
|
|
||||||
{
|
|
||||||
static NonnullRefPtr<Utf16StringImpl> empty_string = Utf16StringImpl::create();
|
|
||||||
return empty_string;
|
|
||||||
}
|
|
||||||
|
|
||||||
Utf16StringImpl::Utf16StringImpl(Utf16Data string)
|
|
||||||
: m_string(move(string))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
NonnullRefPtr<Utf16StringImpl> Utf16StringImpl::create()
|
|
||||||
{
|
|
||||||
return adopt_ref(*new Utf16StringImpl);
|
|
||||||
}
|
|
||||||
|
|
||||||
NonnullRefPtr<Utf16StringImpl> Utf16StringImpl::create(Utf16Data string)
|
|
||||||
{
|
|
||||||
return adopt_ref(*new Utf16StringImpl(move(string)));
|
|
||||||
}
|
|
||||||
|
|
||||||
NonnullRefPtr<Utf16StringImpl> Utf16StringImpl::create(StringView string)
|
|
||||||
{
|
|
||||||
auto result = MUST(utf8_to_utf16(string));
|
|
||||||
auto impl = create(move(result.data));
|
|
||||||
impl->m_cached_view.unsafe_set_code_point_length(result.code_point_count);
|
|
||||||
return impl;
|
|
||||||
}
|
|
||||||
|
|
||||||
NonnullRefPtr<Utf16StringImpl> Utf16StringImpl::create(Utf16View const& view)
|
|
||||||
{
|
|
||||||
Utf16Data string;
|
|
||||||
string.ensure_capacity(view.length_in_code_units());
|
|
||||||
|
|
||||||
if (view.has_ascii_storage()) {
|
|
||||||
for (size_t i = 0; i < view.length_in_code_units(); ++i)
|
|
||||||
string.unchecked_append(static_cast<char16_t>(view.code_unit_at(i)));
|
|
||||||
} else {
|
|
||||||
string.unchecked_append(view.utf16_span().data(), view.length_in_code_units());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto impl = create(move(string));
|
|
||||||
if (auto length_in_code_points = view.length_in_code_points_if_known(); length_in_code_points.has_value())
|
|
||||||
impl->m_cached_view.unsafe_set_code_point_length(*length_in_code_points);
|
|
||||||
|
|
||||||
return impl;
|
|
||||||
}
|
|
||||||
|
|
||||||
Utf16Data const& Utf16StringImpl::string() const
|
|
||||||
{
|
|
||||||
return m_string;
|
|
||||||
}
|
|
||||||
|
|
||||||
Utf16View Utf16StringImpl::view() const
|
|
||||||
{
|
|
||||||
return m_cached_view;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 Utf16StringImpl::compute_hash() const
|
|
||||||
{
|
|
||||||
if (m_string.is_empty())
|
|
||||||
return 0;
|
|
||||||
return string_hash((char const*)m_string.data(), m_string.size() * sizeof(u16));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Utf16String Utf16String::create()
|
|
||||||
{
|
|
||||||
return Utf16String { Detail::the_empty_utf16_string() };
|
|
||||||
}
|
|
||||||
|
|
||||||
Utf16String Utf16String::create(Utf16Data string)
|
|
||||||
{
|
|
||||||
return Utf16String { Detail::Utf16StringImpl::create(move(string)) };
|
|
||||||
}
|
|
||||||
|
|
||||||
Utf16String Utf16String::create(StringView string)
|
|
||||||
{
|
|
||||||
return Utf16String { Detail::Utf16StringImpl::create(string) };
|
|
||||||
}
|
|
||||||
|
|
||||||
Utf16String Utf16String::create(Utf16View const& string)
|
|
||||||
{
|
|
||||||
return Utf16String { Detail::Utf16StringImpl::create(string) };
|
|
||||||
}
|
|
||||||
|
|
||||||
Utf16String Utf16String::invalid()
|
|
||||||
{
|
|
||||||
static auto invalid = Utf16String {};
|
|
||||||
return invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
Utf16String::Utf16String(NonnullRefPtr<Detail::Utf16StringImpl> string)
|
|
||||||
: m_string(move(string))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Utf16Data const& Utf16String::string() const
|
|
||||||
{
|
|
||||||
return m_string->string();
|
|
||||||
}
|
|
||||||
|
|
||||||
Utf16View Utf16String::view() const
|
|
||||||
{
|
|
||||||
return m_string->view();
|
|
||||||
}
|
|
||||||
|
|
||||||
Utf16View Utf16String::substring_view(size_t code_unit_offset, size_t code_unit_length) const
|
|
||||||
{
|
|
||||||
return view().substring_view(code_unit_offset, code_unit_length);
|
|
||||||
}
|
|
||||||
|
|
||||||
Utf16View Utf16String::substring_view(size_t code_unit_offset) const
|
|
||||||
{
|
|
||||||
return view().substring_view(code_unit_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
String Utf16String::to_utf8() const
|
|
||||||
{
|
|
||||||
return MUST(view().to_utf8());
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteString Utf16String::to_byte_string() const
|
|
||||||
{
|
|
||||||
return MUST(view().to_byte_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
u16 Utf16String::code_unit_at(size_t index) const
|
|
||||||
{
|
|
||||||
return view().code_unit_at(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t Utf16String::length_in_code_units() const
|
|
||||||
{
|
|
||||||
return view().length_in_code_units();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Utf16String::is_empty() const
|
|
||||||
{
|
|
||||||
return view().is_empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,197 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2021-2023, Tim Flynn <trflynn89@serenityos.org>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <AK/ByteString.h>
|
|
||||||
#include <AK/NonnullRefPtr.h>
|
|
||||||
#include <AK/RefCounted.h>
|
|
||||||
#include <AK/Types.h>
|
|
||||||
#include <AK/Utf16View.h>
|
|
||||||
#include <AK/Vector.h>
|
|
||||||
#include <LibJS/Runtime/Completion.h>
|
|
||||||
|
|
||||||
namespace JS {
|
|
||||||
namespace Detail {
|
|
||||||
|
|
||||||
class JS_API Utf16StringImpl : public RefCounted<Utf16StringImpl> {
|
|
||||||
public:
|
|
||||||
~Utf16StringImpl() = default;
|
|
||||||
|
|
||||||
[[nodiscard]] static NonnullRefPtr<Utf16StringImpl> create();
|
|
||||||
[[nodiscard]] static NonnullRefPtr<Utf16StringImpl> create(Utf16Data);
|
|
||||||
[[nodiscard]] static NonnullRefPtr<Utf16StringImpl> create(StringView);
|
|
||||||
[[nodiscard]] static NonnullRefPtr<Utf16StringImpl> create(Utf16View const&);
|
|
||||||
|
|
||||||
Utf16Data const& string() const;
|
|
||||||
Utf16View view() const;
|
|
||||||
|
|
||||||
[[nodiscard]] u32 hash() const
|
|
||||||
{
|
|
||||||
if (!m_has_hash) {
|
|
||||||
m_hash = compute_hash();
|
|
||||||
m_has_hash = true;
|
|
||||||
}
|
|
||||||
return m_hash;
|
|
||||||
}
|
|
||||||
[[nodiscard]] bool operator==(Utf16StringImpl const& other) const { return string() == other.string(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Utf16StringImpl() = default;
|
|
||||||
explicit Utf16StringImpl(Utf16Data string);
|
|
||||||
|
|
||||||
[[nodiscard]] u32 compute_hash() const;
|
|
||||||
|
|
||||||
mutable bool m_has_hash { false };
|
|
||||||
mutable u32 m_hash { 0 };
|
|
||||||
Utf16Data m_string;
|
|
||||||
Utf16View m_cached_view { m_string };
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class JS_API Utf16String {
|
|
||||||
public:
|
|
||||||
[[nodiscard]] static Utf16String create();
|
|
||||||
[[nodiscard]] static Utf16String create(Utf16Data);
|
|
||||||
[[nodiscard]] static Utf16String create(StringView);
|
|
||||||
[[nodiscard]] static Utf16String create(Utf16View const&);
|
|
||||||
[[nodiscard]] static Utf16String invalid();
|
|
||||||
|
|
||||||
Utf16Data const& string() const;
|
|
||||||
Utf16View view() const;
|
|
||||||
Utf16View substring_view(size_t code_unit_offset, size_t code_unit_length) const;
|
|
||||||
Utf16View substring_view(size_t code_unit_offset) const;
|
|
||||||
|
|
||||||
[[nodiscard]] String to_utf8() const;
|
|
||||||
[[nodiscard]] ByteString to_byte_string() const;
|
|
||||||
u16 code_unit_at(size_t index) const;
|
|
||||||
|
|
||||||
size_t length_in_code_units() const;
|
|
||||||
bool is_empty() const;
|
|
||||||
bool is_valid() const { return m_string; }
|
|
||||||
|
|
||||||
[[nodiscard]] u32 hash() const { return m_string->hash(); }
|
|
||||||
[[nodiscard]] bool operator==(Utf16String const& other) const
|
|
||||||
{
|
|
||||||
if (m_string == other.m_string)
|
|
||||||
return true;
|
|
||||||
return *m_string == *other.m_string;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Utf16String() = default;
|
|
||||||
explicit Utf16String(NonnullRefPtr<Detail::Utf16StringImpl>);
|
|
||||||
|
|
||||||
RefPtr<Detail::Utf16StringImpl> m_string;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace AK {
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct Traits<JS::Utf16String> : public DefaultTraits<JS::Utf16String> {
|
|
||||||
static unsigned hash(JS::Utf16String const& s) { return s.hash(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
|
||||||
class Optional<JS::Utf16String> : public OptionalBase<JS::Utf16String> {
|
|
||||||
template<typename U>
|
|
||||||
friend class Optional;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using ValueType = JS::Utf16String;
|
|
||||||
|
|
||||||
Optional() = default;
|
|
||||||
|
|
||||||
template<SameAs<OptionalNone> V>
|
|
||||||
Optional(V) { }
|
|
||||||
|
|
||||||
Optional(Optional<JS::Utf16String> const& other)
|
|
||||||
{
|
|
||||||
if (other.has_value())
|
|
||||||
m_value = other.m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
Optional(Optional&& other)
|
|
||||||
: m_value(other.m_value)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U = JS::Utf16String>
|
|
||||||
requires(!IsSame<OptionalNone, RemoveCVReference<U>>)
|
|
||||||
explicit(!IsConvertible<U&&, JS::Utf16String>) Optional(U&& value)
|
|
||||||
requires(!IsSame<RemoveCVReference<U>, Optional<JS::Utf16String>> && IsConstructible<JS::Utf16String, U &&>)
|
|
||||||
: m_value(forward<U>(value))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<SameAs<OptionalNone> V>
|
|
||||||
Optional& operator=(V)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Optional& operator=(Optional const& other)
|
|
||||||
{
|
|
||||||
if (this != &other) {
|
|
||||||
clear();
|
|
||||||
m_value = other.m_value;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Optional& operator=(Optional&& other)
|
|
||||||
{
|
|
||||||
if (this != &other) {
|
|
||||||
clear();
|
|
||||||
m_value = other.m_value;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
m_value = JS::Utf16String::invalid();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] bool has_value() const
|
|
||||||
{
|
|
||||||
return m_value.is_valid();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] JS::Utf16String& value() &
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] JS::Utf16String const& value() const&
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] JS::Utf16String value() &&
|
|
||||||
{
|
|
||||||
return release_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] JS::Utf16String release_value()
|
|
||||||
{
|
|
||||||
VERIFY(has_value());
|
|
||||||
JS::Utf16String released_value = m_value;
|
|
||||||
clear();
|
|
||||||
return released_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
JS::Utf16String m_value { JS::Utf16String::invalid() };
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <AK/CharacterTypes.h>
|
#include <AK/CharacterTypes.h>
|
||||||
#include <AK/StringBuilder.h>
|
#include <AK/StringBuilder.h>
|
||||||
#include <AK/StringFloatingPointConversions.h>
|
#include <AK/StringFloatingPointConversions.h>
|
||||||
|
#include <AK/Utf16String.h>
|
||||||
#include <AK/Utf8View.h>
|
#include <AK/Utf8View.h>
|
||||||
#include <LibCrypto/BigInt/SignedBigInteger.h>
|
#include <LibCrypto/BigInt/SignedBigInteger.h>
|
||||||
#include <LibJS/Runtime/AbstractOperations.h>
|
#include <LibJS/Runtime/AbstractOperations.h>
|
||||||
|
@ -34,7 +35,6 @@
|
||||||
#include <LibJS/Runtime/StringObject.h>
|
#include <LibJS/Runtime/StringObject.h>
|
||||||
#include <LibJS/Runtime/StringPrototype.h>
|
#include <LibJS/Runtime/StringPrototype.h>
|
||||||
#include <LibJS/Runtime/SymbolObject.h>
|
#include <LibJS/Runtime/SymbolObject.h>
|
||||||
#include <LibJS/Runtime/Utf16String.h>
|
|
||||||
#include <LibJS/Runtime/VM.h>
|
#include <LibJS/Runtime/VM.h>
|
||||||
#include <LibJS/Runtime/Value.h>
|
#include <LibJS/Runtime/Value.h>
|
||||||
#include <LibJS/Runtime/ValueInlines.h>
|
#include <LibJS/Runtime/ValueInlines.h>
|
||||||
|
@ -59,12 +59,12 @@ static inline bool same_type_for_equality(Value const& lhs, Value const& rhs)
|
||||||
|
|
||||||
static Crypto::SignedBigInteger const BIGINT_ZERO { 0 };
|
static Crypto::SignedBigInteger const BIGINT_ZERO { 0 };
|
||||||
|
|
||||||
ALWAYS_INLINE bool both_number(Value const& lhs, Value const& rhs)
|
static ALWAYS_INLINE bool both_number(Value const& lhs, Value const& rhs)
|
||||||
{
|
{
|
||||||
return lhs.is_number() && rhs.is_number();
|
return lhs.is_number() && rhs.is_number();
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE bool both_bigint(Value const& lhs, Value const& rhs)
|
static ALWAYS_INLINE bool both_bigint(Value const& lhs, Value const& rhs)
|
||||||
{
|
{
|
||||||
return lhs.is_bigint() && rhs.is_bigint();
|
return lhs.is_bigint() && rhs.is_bigint();
|
||||||
}
|
}
|
||||||
|
@ -455,7 +455,7 @@ ThrowCompletionOr<Utf16String> Value::to_utf16_string(VM& vm) const
|
||||||
return as_string().utf16_string();
|
return as_string().utf16_string();
|
||||||
|
|
||||||
auto utf8_string = TRY(to_string(vm));
|
auto utf8_string = TRY(to_string(vm));
|
||||||
return Utf16String::create(utf8_string.bytes_as_string_view());
|
return Utf16String::from_utf8(utf8_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
ThrowCompletionOr<String> Value::to_well_formed_string(VM& vm) const
|
ThrowCompletionOr<String> Value::to_well_formed_string(VM& vm) const
|
||||||
|
|
|
@ -5,16 +5,10 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AK/Utf16View.h>
|
|
||||||
#include <LibJS/Runtime/Completion.h>
|
|
||||||
#include <LibJS/Runtime/Utf16String.h>
|
|
||||||
#include <LibWeb/Bindings/SVGTextContentElementPrototype.h>
|
#include <LibWeb/Bindings/SVGTextContentElementPrototype.h>
|
||||||
#include <LibWeb/CSS/Parser/Parser.h>
|
|
||||||
#include <LibWeb/DOM/Document.h>
|
#include <LibWeb/DOM/Document.h>
|
||||||
#include <LibWeb/Layout/SVGTextBox.h>
|
#include <LibWeb/Layout/Node.h>
|
||||||
#include <LibWeb/SVG/AttributeNames.h>
|
|
||||||
#include <LibWeb/SVG/AttributeParser.h>
|
#include <LibWeb/SVG/AttributeParser.h>
|
||||||
#include <LibWeb/SVG/SVGGeometryElement.h>
|
|
||||||
#include <LibWeb/SVG/SVGTextContentElement.h>
|
#include <LibWeb/SVG/SVGTextContentElement.h>
|
||||||
|
|
||||||
namespace Web::SVG {
|
namespace Web::SVG {
|
||||||
|
|
|
@ -5,15 +5,10 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AK/Utf16View.h>
|
|
||||||
#include <LibJS/Runtime/Completion.h>
|
|
||||||
#include <LibJS/Runtime/Utf16String.h>
|
|
||||||
#include <LibWeb/Bindings/SVGTextPositioningElementPrototype.h>
|
#include <LibWeb/Bindings/SVGTextPositioningElementPrototype.h>
|
||||||
#include <LibWeb/CSS/Parser/Parser.h>
|
|
||||||
#include <LibWeb/DOM/Document.h>
|
#include <LibWeb/DOM/Document.h>
|
||||||
#include <LibWeb/SVG/AttributeNames.h>
|
#include <LibWeb/SVG/AttributeNames.h>
|
||||||
#include <LibWeb/SVG/AttributeParser.h>
|
#include <LibWeb/SVG/AttributeParser.h>
|
||||||
#include <LibWeb/SVG/SVGGeometryElement.h>
|
|
||||||
#include <LibWeb/SVG/SVGTextPositioningElement.h>
|
#include <LibWeb/SVG/SVGTextPositioningElement.h>
|
||||||
|
|
||||||
namespace Web::SVG {
|
namespace Web::SVG {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue