diff options
5 files changed, 78 insertions, 65 deletions
diff --git a/Meta/Lagom/Tools/CodeGenerators/LibUnicode/GenerateUnicodeNumberFormat.cpp b/Meta/Lagom/Tools/CodeGenerators/LibUnicode/GenerateUnicodeNumberFormat.cpp index b5af991636..9b40a82bd4 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibUnicode/GenerateUnicodeNumberFormat.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibUnicode/GenerateUnicodeNumberFormat.cpp @@ -38,6 +38,9 @@ constexpr auto s_number_format_index_type = "u16"sv; using NumberFormatListIndexType = u16; constexpr auto s_number_format_list_index_type = "u16"sv; +using NumericSymbolListIndexType = u8; +constexpr auto s_numeric_symbol_list_index_type = "u8"sv; + enum class NumberFormatType { Standard, Compact, @@ -135,9 +138,11 @@ struct AK::Traits<NumberFormatList> : public GenericTraits<NumberFormatList> { } }; +using NumericSymbolList = Vector<StringIndexType>; + struct NumberSystem { StringIndexType system { 0 }; - HashMap<String, StringIndexType> symbols {}; + NumericSymbolListIndexType symbols { 0 }; u8 primary_grouping_size { 0 }; u8 secondary_grouping_size { 0 }; @@ -171,9 +176,9 @@ struct UnicodeLocaleData { UniqueStringStorage<StringIndexType> unique_strings; UniqueStorage<NumberFormat, NumberFormatIndexType> unique_formats; UniqueStorage<NumberFormatList, NumberFormatListIndexType> unique_format_lists; + UniqueStorage<NumericSymbolList, NumericSymbolListIndexType> unique_symbols; HashMap<String, Locale> locales; - Vector<String> numeric_symbols; size_t max_identifier_count { 0 }; }; @@ -370,6 +375,26 @@ static ErrorOr<void> parse_number_systems(String locale_numbers_path, UnicodeLoc return locale_data.unique_format_lists.ensure(move(result)); }; + auto numeric_symbol_from_string = [&](StringView numeric_symbol) -> Optional<Unicode::NumericSymbol> { + if (numeric_symbol == "decimal"sv) + return Unicode::NumericSymbol::Decimal; + if (numeric_symbol == "exponential"sv) + return Unicode::NumericSymbol::Exponential; + if (numeric_symbol == "group"sv) + return Unicode::NumericSymbol::Group; + if (numeric_symbol == "infinity"sv) + return Unicode::NumericSymbol::Infinity; + if (numeric_symbol == "minusSign"sv) + return Unicode::NumericSymbol::MinusSign; + if (numeric_symbol == "nan"sv) + return Unicode::NumericSymbol::NaN; + if (numeric_symbol == "percentSign"sv) + return Unicode::NumericSymbol::PercentSign; + if (numeric_symbol == "plusSign"sv) + return Unicode::NumericSymbol::PlusSign; + return {}; + }; + locale_numbers_object.as_object().for_each_member([&](auto const& key, JsonValue const& value) { constexpr auto symbols_prefix = "symbols-numberSystem-"sv; constexpr auto decimal_formats_prefix = "decimalFormats-numberSystem-"sv; @@ -381,13 +406,21 @@ static ErrorOr<void> parse_number_systems(String locale_numbers_path, UnicodeLoc auto system = key.substring(symbols_prefix.length()); auto& number_system = ensure_number_system(system); + NumericSymbolList symbols; + value.as_object().for_each_member([&](auto const& symbol, JsonValue const& localization) { - auto symbol_index = locale_data.unique_strings.ensure(localization.as_string()); - number_system.symbols.set(symbol, symbol_index); + auto numeric_symbol = numeric_symbol_from_string(symbol); + if (!numeric_symbol.has_value()) + return; + + if (to_underlying(*numeric_symbol) >= symbols.size()) + symbols.resize(to_underlying(*numeric_symbol) + 1); - if (!locale_data.numeric_symbols.contains_slow(symbol)) - locale_data.numeric_symbols.append(symbol); + auto symbol_index = locale_data.unique_strings.ensure(localization.as_string()); + symbols[to_underlying(*numeric_symbol)] = symbol_index; }); + + number_system.symbols = locale_data.unique_symbols.ensure(move(symbols)); } else if (key.starts_with(decimal_formats_prefix)) { auto system = key.substring(decimal_formats_prefix.length()); auto& number_system = ensure_number_system(system); @@ -571,18 +604,7 @@ static ErrorOr<void> parse_all_locales(String numbers_path, String units_path, U return {}; } -static String format_identifier(StringView owner, String identifier) -{ - identifier = identifier.replace("-"sv, "_"sv, true); - - if (all_of(identifier, is_ascii_digit)) - return String::formatted("{}_{}", owner[0], identifier); - if (is_ascii_lower_alpha(identifier[0])) - return String::formatted("{:c}{}", to_ascii_uppercase(identifier[0]), identifier.substring_view(1)); - return identifier; -} - -static void generate_unicode_locale_header(Core::File& file, UnicodeLocaleData& locale_data) +static void generate_unicode_locale_header(Core::File& file, UnicodeLocaleData&) { StringBuilder builder; SourceGenerator generator { builder }; @@ -592,19 +614,16 @@ static void generate_unicode_locale_header(Core::File& file, UnicodeLocaleData& #include <AK/Optional.h> #include <AK/StringView.h> -#include <AK/Types.h> #include <AK/Vector.h> #include <LibUnicode/Forward.h> namespace Unicode { )~~~"); - generate_enum(generator, format_identifier, "NumericSymbol"sv, {}, locale_data.numeric_symbols); - generator.append(R"~~~( namespace Detail { -Optional<StringView> get_number_system_symbol(StringView locale, StringView system, StringView numeric_symbol); +Optional<StringView> get_number_system_symbol(StringView locale, StringView system, Unicode::NumericSymbol symbol); Optional<NumberGroupings> get_number_system_groupings(StringView locale, StringView system); Optional<NumberFormat> get_standard_number_system_format(StringView locale, StringView system, StandardNumberFormatType type); Vector<NumberFormat> get_compact_number_system_formats(StringView locale, StringView system, CompactNumberFormatType type); @@ -626,7 +645,7 @@ static void generate_unicode_locale_implementation(Core::File& file, UnicodeLoca generator.set("string_index_type"sv, s_string_index_type); generator.set("number_format_index_type"sv, s_number_format_index_type); generator.set("number_format_list_index_type"sv, s_number_format_list_index_type); - generator.set("numeric_symbols_size", String::number(locale_data.numeric_symbols.size())); + generator.set("numeric_symbol_list_index_type"sv, s_numeric_symbol_list_index_type); generator.set("identifier_count", String::number(locale_data.max_identifier_count)); generator.append(R"~~~( @@ -672,7 +691,7 @@ struct NumberFormat { struct NumberSystem { @string_index_type@ system { 0 }; - Array<@string_index_type@, @numeric_symbols_size@> symbols {}; + @numeric_symbol_list_index_type@ symbols { 0 }; u8 primary_grouping_size { 0 }; u8 secondary_grouping_size { 0 }; @@ -700,6 +719,7 @@ struct Unit { locale_data.unique_formats.generate(generator, "NumberFormat"sv, "s_number_formats"sv, 10); locale_data.unique_format_lists.generate(generator, s_number_format_index_type, "s_number_format_lists"sv); + locale_data.unique_symbols.generate(generator, s_string_index_type, "s_numeric_symbol_lists"sv); auto append_number_systems = [&](String name, auto const& number_systems) { generator.set("name", name); @@ -710,6 +730,7 @@ static constexpr Array<NumberSystem, @size@> @name@ { {)~~~"); for (auto const& number_system : number_systems) { generator.set("system"sv, String::number(number_system.value.system)); + generator.set("symbols"sv, String::number(number_system.value.symbols)); generator.set("primary_grouping_size"sv, String::number(number_system.value.primary_grouping_size)); generator.set("secondary_grouping_size"sv, String::number(number_system.value.secondary_grouping_size)); generator.set("decimal_format", String::number(number_system.value.decimal_format)); @@ -722,16 +743,8 @@ static constexpr Array<NumberSystem, @size@> @name@ { {)~~~"); generator.set("percent_format", String::number(number_system.value.percent_format)); generator.set("scientific_format", String::number(number_system.value.scientific_format)); - generator.append(R"~~~( - { @system@, {)~~~"); - - for (auto const& symbol : locale_data.numeric_symbols) { - auto index = number_system.value.symbols.get(symbol).value_or(0); - generator.set("index", String::number(index)); - generator.append(" @index@,"); - } - - generator.append(" }, @primary_grouping_size@, @secondary_grouping_size@, "); + generator.append("\n { "); + generator.append("@system@, @symbols@, @primary_grouping_size@, @secondary_grouping_size@, "); generator.append("@decimal_format@, @decimal_long_formats@, @decimal_short_formats@, "); generator.append("@currency_format@, @accounting_format@, @currency_unit_formats@, @currency_short_formats@, "); generator.append("@percent_format@, @scientific_format@ },"); @@ -767,18 +780,6 @@ static constexpr Array<Unit, @size@> @name@ { {)~~~"); generate_mapping(generator, locale_data.locales, "NumberSystem"sv, "s_number_systems"sv, "s_number_systems_{}", [&](auto const& name, auto const& value) { append_number_systems(name, value.number_systems); }); generate_mapping(generator, locale_data.locales, "Unit"sv, "s_units"sv, "s_units_{}", [&](auto const& name, auto const& value) { append_units(name, value.units); }); - auto append_from_string = [&](StringView enum_title, StringView enum_snake, auto const& values) { - HashValueMap<String> hashes; - hashes.ensure_capacity(values.size()); - - for (auto const& value : values) - hashes.set(value.hash(), format_identifier(enum_title, value)); - - generate_value_from_string(generator, "{}_from_string"sv, enum_title, enum_snake, move(hashes)); - }; - - append_from_string("NumericSymbol"sv, "numeric_symbol"sv, locale_data.numeric_symbols); - generator.append(R"~~~( static NumberSystem const* find_number_system(StringView locale, StringView system) { @@ -797,15 +798,16 @@ static NumberSystem const* find_number_system(StringView locale, StringView syst return nullptr; } -Optional<StringView> get_number_system_symbol(StringView locale, StringView system, StringView symbol) +Optional<StringView> get_number_system_symbol(StringView locale, StringView system, Unicode::NumericSymbol symbol) { - auto symbol_value = numeric_symbol_from_string(symbol); - if (!symbol_value.has_value()) - return {}; - if (auto const* number_system = find_number_system(locale, system); number_system != nullptr) { - auto symbol_index = to_underlying(*symbol_value); - return s_string_list[number_system->symbols[symbol_index]]; + auto symbols = s_numeric_symbol_lists.at(number_system->symbols); + + auto symbol_index = to_underlying(symbol); + if (symbol_index >= symbols.size()) + return {}; + + return s_string_list[symbols[symbol_index]]; } return {}; diff --git a/Userland/Libraries/LibJS/Runtime/Intl/DateTimeFormat.cpp b/Userland/Libraries/LibJS/Runtime/Intl/DateTimeFormat.cpp index 705388477b..b870464eba 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/DateTimeFormat.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/DateTimeFormat.cpp @@ -1021,7 +1021,7 @@ ThrowCompletionOr<Vector<PatternPartition>> format_date_time_pattern(GlobalObjec // Non-standard, TR-35 requires the decimal separator before injected {fractionalSecondDigits} partitions // to adhere to the selected locale. This depends on other generated data, so it is deferred to here. else if (part == "decimal"sv) { - auto decimal_symbol = Unicode::get_number_system_symbol(data_locale, date_time_format.numbering_system(), "decimal"sv).value_or("."sv); + auto decimal_symbol = Unicode::get_number_system_symbol(data_locale, date_time_format.numbering_system(), Unicode::NumericSymbol::Decimal).value_or("."sv); result.append({ "literal"sv, decimal_symbol }); } diff --git a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp index 2de65ec445..84ba644235 100644 --- a/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp +++ b/Userland/Libraries/LibJS/Runtime/Intl/NumberFormat.cpp @@ -605,12 +605,12 @@ Vector<PatternPartition> partition_number_pattern(NumberFormat& number_format, d // 2. If x is NaN, then if (Value(number).is_nan()) { // a. Let n be an implementation- and locale-dependent (ILD) String value indicating the NaN value. - formatted_string = Unicode::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), "nan"sv).value_or("NaN"sv); + formatted_string = Unicode::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), Unicode::NumericSymbol::NaN).value_or("NaN"sv); } // 3. Else if x is a non-finite Number, then else if (!Value(number).is_finite_number()) { // a. Let n be an ILD String value indicating infinity. - formatted_string = Unicode::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), "infinity"sv).value_or("infinity"sv); + formatted_string = Unicode::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), Unicode::NumericSymbol::Infinity).value_or("infinity"sv); } // 4. Else, else { @@ -669,7 +669,7 @@ Vector<PatternPartition> partition_number_pattern(NumberFormat& number_format, d // d. Else if p is equal to "plusSign", then else if (part == "plusSign"sv) { // i. Let plusSignSymbol be the ILND String representing the plus sign. - auto plus_sign_symbol = Unicode::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), "plusSign"sv).value_or("+"sv); + auto plus_sign_symbol = Unicode::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), Unicode::NumericSymbol::PlusSign).value_or("+"sv); // ii. Append a new Record { [[Type]]: "plusSign", [[Value]]: plusSignSymbol } as the last element of result. result.append({ "plusSign"sv, plus_sign_symbol }); } @@ -677,7 +677,7 @@ Vector<PatternPartition> partition_number_pattern(NumberFormat& number_format, d // e. Else if p is equal to "minusSign", then else if (part == "minusSign"sv) { // i. Let minusSignSymbol be the ILND String representing the minus sign. - auto minus_sign_symbol = Unicode::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), "minusSign"sv).value_or("-"sv); + auto minus_sign_symbol = Unicode::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), Unicode::NumericSymbol::MinusSign).value_or("-"sv); // ii. Append a new Record { [[Type]]: "minusSign", [[Value]]: minusSignSymbol } as the last element of result. result.append({ "minusSign"sv, minus_sign_symbol }); } @@ -685,7 +685,7 @@ Vector<PatternPartition> partition_number_pattern(NumberFormat& number_format, d // f. Else if p is equal to "percentSign" and numberFormat.[[Style]] is "percent", then else if ((part == "percentSign"sv) && (number_format.style() == NumberFormat::Style::Percent)) { // i. Let percentSignSymbol be the ILND String representing the percent sign. - auto percent_sign_symbol = Unicode::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), "percentSign"sv).value_or("%"sv); + auto percent_sign_symbol = Unicode::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), Unicode::NumericSymbol::PercentSign).value_or("%"sv); // ii. Append a new Record { [[Type]]: "percentSign", [[Value]]: percentSignSymbol } as the last element of result. result.append({ "percentSign"sv, percent_sign_symbol }); } @@ -937,7 +937,7 @@ Vector<PatternPartition> partition_notation_sub_pattern(NumberFormat& number_for // 6. If the numberFormat.[[UseGrouping]] is true, then if (use_grouping) { // a. Let groupSepSymbol be the implementation-, locale-, and numbering system-dependent (ILND) String representing the grouping separator. - auto group_sep_symbol = Unicode::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), "group"sv).value_or(","sv); + auto group_sep_symbol = Unicode::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), Unicode::NumericSymbol::Group).value_or(","sv); // b. Let groups be a List whose elements are, in left to right order, the substrings defined by ILND set of locations within the integer. auto groups = separate_integer_into_groups(*grouping_sizes, integer); @@ -969,7 +969,7 @@ Vector<PatternPartition> partition_notation_sub_pattern(NumberFormat& number_for // 8. If fraction is not undefined, then if (fraction.has_value()) { // a. Let decimalSepSymbol be the ILND String representing the decimal separator. - auto decimal_sep_symbol = Unicode::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), "decimal"sv).value_or("."sv); + auto decimal_sep_symbol = Unicode::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), Unicode::NumericSymbol::Decimal).value_or("."sv); // b. Append a new Record { [[Type]]: "decimal", [[Value]]: decimalSepSymbol } as the last element of result. result.append({ "decimal"sv, decimal_sep_symbol }); // c. Append a new Record { [[Type]]: "fraction", [[Value]]: fraction } as the last element of result. @@ -993,7 +993,7 @@ Vector<PatternPartition> partition_notation_sub_pattern(NumberFormat& number_for // vi. Else if p is equal to "scientificSeparator", then else if (part == "scientificSeparator"sv) { // 1. Let scientificSeparator be the ILND String representing the exponent separator. - auto scientific_separator = Unicode::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), "exponential"sv).value_or("E"sv); + auto scientific_separator = Unicode::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), Unicode::NumericSymbol::Exponential).value_or("E"sv); // 2. Append a new Record { [[Type]]: "exponentSeparator", [[Value]]: scientificSeparator } as the last element of result. result.append({ "exponentSeparator"sv, scientific_separator }); } @@ -1002,7 +1002,7 @@ Vector<PatternPartition> partition_notation_sub_pattern(NumberFormat& number_for // 1. If exponent < 0, then if (exponent < 0) { // a. Let minusSignSymbol be the ILND String representing the minus sign. - auto minus_sign_symbol = Unicode::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), "minusSign"sv).value_or("-"sv); + auto minus_sign_symbol = Unicode::get_number_system_symbol(number_format.data_locale(), number_format.numbering_system(), Unicode::NumericSymbol::MinusSign).value_or("-"sv); // b. Append a new Record { [[Type]]: "exponentMinusSign", [[Value]]: minusSignSymbol } as the last element of result. result.append({ "exponentMinusSign"sv, minus_sign_symbol }); diff --git a/Userland/Libraries/LibUnicode/NumberFormat.cpp b/Userland/Libraries/LibUnicode/NumberFormat.cpp index cffd0d4c04..7933dd005c 100644 --- a/Userland/Libraries/LibUnicode/NumberFormat.cpp +++ b/Userland/Libraries/LibUnicode/NumberFormat.cpp @@ -16,7 +16,7 @@ namespace Unicode { -Optional<StringView> get_number_system_symbol([[maybe_unused]] StringView locale, [[maybe_unused]] StringView system, [[maybe_unused]] StringView symbol) +Optional<StringView> get_number_system_symbol([[maybe_unused]] StringView locale, [[maybe_unused]] StringView system, [[maybe_unused]] NumericSymbol symbol) { #if ENABLE_UNICODE_DATA return Detail::get_number_system_symbol(locale, system, symbol); diff --git a/Userland/Libraries/LibUnicode/NumberFormat.h b/Userland/Libraries/LibUnicode/NumberFormat.h index b56e870ad7..c08d61097d 100644 --- a/Userland/Libraries/LibUnicode/NumberFormat.h +++ b/Userland/Libraries/LibUnicode/NumberFormat.h @@ -54,7 +54,18 @@ struct NumberFormat { Vector<StringView> identifiers {}; }; -Optional<StringView> get_number_system_symbol(StringView locale, StringView system, StringView symbol); +enum class NumericSymbol : u8 { + Decimal, + Exponential, + Group, + Infinity, + MinusSign, + NaN, + PercentSign, + PlusSign, +}; + +Optional<StringView> get_number_system_symbol(StringView locale, StringView system, NumericSymbol symbol); Optional<NumberGroupings> get_number_system_groupings(StringView locale, StringView system); Optional<NumberFormat> get_standard_number_system_format(StringView locale, StringView system, StandardNumberFormatType type); Vector<NumberFormat> get_compact_number_system_formats(StringView locale, StringView system, CompactNumberFormatType type); |