diff --git a/Libraries/LibJS/Runtime/Intl/DurationFormat.cpp b/Libraries/LibJS/Runtime/Intl/DurationFormat.cpp index cc96d44127f..bd760204426 100644 --- a/Libraries/LibJS/Runtime/Intl/DurationFormat.cpp +++ b/Libraries/LibJS/Runtime/Intl/DurationFormat.cpp @@ -731,13 +731,13 @@ Vector list_format_parts(VM& vm, DurationFormat const& durat auto list_format = construct_list_format(vm, duration_format, list_format_options); // 7. Let strings be a new empty List. - Vector strings; + Vector strings; strings.ensure_capacity(partitioned_parts_list.size()); // 8. For each element parts of partitionedPartsList, do for (auto const& parts : partitioned_parts_list) { // a. Let string be the empty String. - StringBuilder string; + StringBuilder string(StringBuilder::Mode::UTF16); // b. For each Record { [[Type]], [[Value]], [[Unit]] } part in parts, do for (auto const& part : parts) { @@ -746,7 +746,7 @@ Vector list_format_parts(VM& vm, DurationFormat const& durat } // c. Append string to strings. - strings.unchecked_append(MUST(string.to_string())); + strings.unchecked_append(string.to_utf16_string()); } // 9. Let formattedPartsList be CreatePartsFromList(lf, strings). @@ -786,7 +786,7 @@ Vector list_format_parts(VM& vm, DurationFormat const& durat VERIFY(list_part.type == "literal"sv); // ii. Append the Record { [[Type]]: "literal", [[Value]]: listPart.[[Value]], [[Unit]]: empty } to flattenedPartsList. - flattened_parts_list.append({ .type = "literal"sv, .value = move(list_part.value), .unit = {} }); + flattened_parts_list.append({ .type = "literal"sv, .value = list_part.value.to_utf8_but_should_be_ported_to_utf16(), .unit = {} }); } } diff --git a/Libraries/LibJS/Runtime/Intl/ListFormat.cpp b/Libraries/LibJS/Runtime/Intl/ListFormat.cpp index 6dee312a67f..02d8600bf23 100644 --- a/Libraries/LibJS/Runtime/Intl/ListFormat.cpp +++ b/Libraries/LibJS/Runtime/Intl/ListFormat.cpp @@ -35,13 +35,13 @@ ReadonlySpan ListFormat::resolution_option_descripto } // 14.5.2 CreatePartsFromList ( listFormat, list ), https://tc39.es/ecma402/#sec-createpartsfromlist -Vector create_parts_from_list(ListFormat const& list_format, ReadonlySpan list) +Vector create_parts_from_list(ListFormat const& list_format, ReadonlySpan list) { return list_format.formatter().format_to_parts(list); } // 14.5.3 FormatList ( listFormat, list ), https://tc39.es/ecma402/#sec-formatlist -String format_list(ListFormat const& list_format, ReadonlySpan list) +Utf16String format_list(ListFormat const& list_format, ReadonlySpan list) { // 1. Let parts be ! CreatePartsFromList(listFormat, list). // 2. Let result be the empty String. @@ -52,7 +52,7 @@ String format_list(ListFormat const& list_format, ReadonlySpan list) } // 14.5.4 FormatListToParts ( listFormat, list ), https://tc39.es/ecma402/#sec-formatlisttoparts -GC::Ref format_list_to_parts(VM& vm, ListFormat const& list_format, ReadonlySpan list) +GC::Ref format_list_to_parts(VM& vm, ListFormat const& list_format, ReadonlySpan list) { auto& realm = *vm.current_realm(); @@ -88,19 +88,19 @@ GC::Ref format_list_to_parts(VM& vm, ListFormat const& list_format, Reado } // 14.5.5 StringListFromIterable ( iterable ), https://tc39.es/ecma402/#sec-createstringlistfromiterable -ThrowCompletionOr> string_list_from_iterable(VM& vm, Value iterable) +ThrowCompletionOr> string_list_from_iterable(VM& vm, Value iterable) { // 1. If iterable is undefined, then if (iterable.is_undefined()) { // a. Return a new empty List. - return Vector {}; + return Vector {}; } // 2. Let iteratorRecord be ? GetIterator(iterable, sync). auto iterator_record = TRY(get_iterator(vm, iterable, IteratorHint::Sync)); // 3. Let list be a new empty List. - Vector list; + Vector list; // 4. Repeat, while (true) { @@ -123,7 +123,7 @@ ThrowCompletionOr> string_list_from_iterable(VM& vm, Value iterab } // iii. Append next to list. - list.append(next->as_string().utf8_string()); + list.append(next->as_string().utf16_string()); } } diff --git a/Libraries/LibJS/Runtime/Intl/ListFormat.h b/Libraries/LibJS/Runtime/Intl/ListFormat.h index e1a392348b9..8d1c4861416 100644 --- a/Libraries/LibJS/Runtime/Intl/ListFormat.h +++ b/Libraries/LibJS/Runtime/Intl/ListFormat.h @@ -57,9 +57,9 @@ private: OwnPtr m_formatter; }; -Vector create_parts_from_list(ListFormat const&, ReadonlySpan list); -String format_list(ListFormat const&, ReadonlySpan list); -GC::Ref format_list_to_parts(VM&, ListFormat const&, ReadonlySpan list); -ThrowCompletionOr> string_list_from_iterable(VM&, Value iterable); +Vector create_parts_from_list(ListFormat const&, ReadonlySpan list); +Utf16String format_list(ListFormat const&, ReadonlySpan list); +GC::Ref format_list_to_parts(VM&, ListFormat const&, ReadonlySpan list); +ThrowCompletionOr> string_list_from_iterable(VM&, Value iterable); } diff --git a/Libraries/LibUnicode/ICU.cpp b/Libraries/LibUnicode/ICU.cpp index 9a4b9c0f7af..9359673c7b7 100644 --- a/Libraries/LibUnicode/ICU.cpp +++ b/Libraries/LibUnicode/ICU.cpp @@ -138,16 +138,13 @@ TimeZoneData::TimeZoneData(NonnullOwnPtr time_zone) { } -Vector icu_string_list(ReadonlySpan strings) +Vector icu_string_list(ReadonlySpan strings) { Vector result; result.ensure_capacity(strings.size()); - for (auto const& string : strings) { - auto view = string.bytes_as_string_view(); - icu::UnicodeString icu_string(view.characters_without_null_termination(), static_cast(view.length())); - result.unchecked_append(move(icu_string)); - } + for (auto const& string : strings) + result.unchecked_append(icu_string(string)); return result; } diff --git a/Libraries/LibUnicode/ICU.h b/Libraries/LibUnicode/ICU.h index 26bea7d1933..8392e29a616 100644 --- a/Libraries/LibUnicode/ICU.h +++ b/Libraries/LibUnicode/ICU.h @@ -99,7 +99,16 @@ ALWAYS_INLINE icu::UnicodeString icu_string(StringView string) return icu::UnicodeString::fromUTF8(icu_string_piece(string)); } -Vector icu_string_list(ReadonlySpan strings); +// If the Utf16View has ASCII storage, this creates an owned icu::UnicodeString. Otherwise, the icu::UnicodeString is +// unowned (i.e. it is effectively a view). +ALWAYS_INLINE icu::UnicodeString icu_string(Utf16View const& string) +{ + if (string.has_ascii_storage()) + return icu::UnicodeString::fromUTF8(icu_string_piece(string.bytes())); + return { false, string.utf16_span().data(), static_cast(string.length_in_code_units()) }; +} + +Vector icu_string_list(ReadonlySpan strings); String icu_string_to_string(icu::UnicodeString const& string); String icu_string_to_string(UChar const*, i32 length); diff --git a/Libraries/LibUnicode/ListFormat.cpp b/Libraries/LibUnicode/ListFormat.cpp index 6db8045ccbf..28840d1b882 100644 --- a/Libraries/LibUnicode/ListFormat.cpp +++ b/Libraries/LibUnicode/ListFormat.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Tim Flynn + * Copyright (c) 2024-2025, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ @@ -82,7 +82,7 @@ public: virtual ~ListFormatImpl() override = default; - virtual String format(ReadonlySpan list) const override + virtual Utf16String format(ReadonlySpan list) const override { UErrorCode status = U_ZERO_ERROR; @@ -94,10 +94,10 @@ public: if (icu_failure(status)) return {}; - return icu_string_to_string(formatted_string); + return icu_string_to_utf16_string(formatted_string); } - virtual Vector format_to_parts(ReadonlySpan list) const override + virtual Vector format_to_parts(ReadonlySpan list) const override { UErrorCode status = U_ZERO_ERROR; @@ -118,14 +118,14 @@ public: auto type = icu_list_format_field_to_string(position.getField()); auto part = formatted_string.tempSubStringBetween(position.getStart(), position.getLimit()); - result.empend(type, icu_string_to_string(part)); + result.empend(type, icu_string_to_utf16_string(part)); } return result; } private: - Optional format_list_impl(ReadonlySpan list) const + Optional format_list_impl(ReadonlySpan list) const { UErrorCode status = U_ZERO_ERROR; diff --git a/Libraries/LibUnicode/ListFormat.h b/Libraries/LibUnicode/ListFormat.h index 6407e4ffff7..fc522a8b117 100644 --- a/Libraries/LibUnicode/ListFormat.h +++ b/Libraries/LibUnicode/ListFormat.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2024, Tim Flynn + * Copyright (c) 2024-2025, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once -#include +#include #include #include @@ -27,11 +27,11 @@ public: struct Partition { StringView type; - String value; + Utf16String value; }; - virtual String format(ReadonlySpan list) const = 0; - virtual Vector format_to_parts(ReadonlySpan list) const = 0; + virtual Utf16String format(ReadonlySpan list) const = 0; + virtual Vector format_to_parts(ReadonlySpan list) const = 0; protected: ListFormat() = default;