From 04e6b43f0558b6d0e00d097055b49a9ade6f6a53 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Fri, 12 Nov 2021 08:48:21 -0500 Subject: [PATCH] LibUnicode: Move (soon-to-be) common code out of GenerateUnicodeLocale The data used for number formatting is going to grow quite a bit when the cldr-units package is parsed. To prevent the generated UnicodeLocale file from growing outrageously large, the number formatting data can go into its own file. To prepare for this, move code that will be common between the generators for UnicodeLocale and UnicodeNumberFormat to the utility header. --- .../LibUnicode/GenerateUnicodeLocale.cpp | 275 +++--------------- .../CodeGenerators/LibUnicode/GeneratorUtil.h | 207 +++++++++++++ 2 files changed, 252 insertions(+), 230 deletions(-) diff --git a/Meta/Lagom/Tools/CodeGenerators/LibUnicode/GenerateUnicodeLocale.cpp b/Meta/Lagom/Tools/CodeGenerators/LibUnicode/GenerateUnicodeLocale.cpp index ac604dbe820..512ec3c103c 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibUnicode/GenerateUnicodeLocale.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibUnicode/GenerateUnicodeLocale.cpp @@ -20,7 +20,6 @@ #include #include #include -#include #include using StringIndexType = u16; @@ -87,21 +86,13 @@ struct Locale { Vector list_patterns; }; -struct CanonicalLanguageID { - StringIndexType language { 0 }; - StringIndexType script { 0 }; - StringIndexType region { 0 }; - Vector variants {}; -}; - struct LanguageMapping { - CanonicalLanguageID key {}; - CanonicalLanguageID alias {}; + CanonicalLanguageID key {}; + CanonicalLanguageID alias {}; }; struct UnicodeLocaleData { - Vector unique_strings; - HashMap unique_string_indices; + UniqueStringStorage unique_strings; HashMap locales; Vector languages; Vector territories; @@ -122,84 +113,13 @@ struct UnicodeLocaleData { size_t max_variant_size { 0 }; }; -static StringIndexType ensure_unique_string(UnicodeLocaleData& locale_data, String string) -{ - // We maintain a set of unique strings in two structures: a vector which owns the unique string, - // and a hash map which maps that string to its index in the vector. The vector is to ensure the - // strings are generated in an easily known order, and the map is to allow quickly deciding if a - // string is actually unique (otherwise, we'd have to linear-search the vector for each string). - // - // Also note that index 0 will be reserved for the empty string, so the index returned from this - // method is actually the real index in the vector + 1. - if (auto index = locale_data.unique_string_indices.get(string); index.has_value()) - return *index; - - locale_data.unique_strings.append(move(string)); - size_t index = locale_data.unique_strings.size(); - - // There are currently on the order of 46K unique strings in UnicodeLocale.cpp. - // If that number reaches 2^16, bump the StringIndexType alias to a u32. - VERIFY(index < NumericLimits::max()); - - auto string_index = static_cast(index); - locale_data.unique_string_indices.set(locale_data.unique_strings.last(), string_index); - - return string_index; -} - -static StringView get_unique_string(UnicodeLocaleData& locale_data, StringIndexType index) -{ - if (index == 0) - return {}; - - VERIFY(index <= locale_data.unique_strings.size()); - return locale_data.unique_strings.at(index - 1); -} - -static Optional parse_language(UnicodeLocaleData& locale_data, StringView language) -{ - CanonicalLanguageID language_id {}; - - auto segments = language.split_view('-'); - VERIFY(!segments.is_empty()); - size_t index = 0; - - if (Unicode::is_unicode_language_subtag(segments[index])) { - language_id.language = ensure_unique_string(locale_data, segments[index]); - if (segments.size() == ++index) - return language_id; - } else { - return {}; - } - - if (Unicode::is_unicode_script_subtag(segments[index])) { - language_id.script = ensure_unique_string(locale_data, segments[index]); - if (segments.size() == ++index) - return language_id; - } - - if (Unicode::is_unicode_region_subtag(segments[index])) { - language_id.region = ensure_unique_string(locale_data, segments[index]); - if (segments.size() == ++index) - return language_id; - } - - while (index < segments.size()) { - if (!Unicode::is_unicode_variant_subtag(segments[index])) - return {}; - language_id.variants.append(ensure_unique_string(locale_data, segments[index++])); - } - - return language_id; -} - static Optional parse_language_mapping(UnicodeLocaleData& locale_data, StringView key, StringView alias) { - auto parsed_key = parse_language(locale_data, key); + auto parsed_key = CanonicalLanguageID::parse(locale_data.unique_strings, key); if (!parsed_key.has_value()) return {}; - auto parsed_alias = parse_language(locale_data, alias); + auto parsed_alias = CanonicalLanguageID::parse(locale_data.unique_strings, alias); if (!parsed_alias.has_value()) return {}; @@ -235,7 +155,7 @@ static void parse_core_aliases(String core_supplemental_path, UnicodeLocaleData& locale_data.max_variant_size = max(mapping->alias.variants.size(), locale_data.max_variant_size); locale_data.complex_mappings.append(mapping.release_value()); } else { - alias_map.set(key, ensure_unique_string(locale_data, alias)); + alias_map.set(key, locale_data.unique_strings.ensure(alias)); } }); }; @@ -330,7 +250,7 @@ static void parse_locale_languages(String locale_path, UnicodeLocaleData& locale if (!locale_data.languages.contains_slow(key)) return; - auto index = ensure_unique_string(locale_data, value.as_string()); + auto index = locale_data.unique_strings.ensure(value.as_string()); locale.languages.set(key, index); }); } @@ -356,7 +276,7 @@ static void parse_locale_territories(String locale_path, UnicodeLocaleData& loca if (!locale_data.territories.contains_slow(key)) return; - auto index = ensure_unique_string(locale_data, value.as_string()); + auto index = locale_data.unique_strings.ensure(value.as_string()); locale.territories.set(key, index); }); } @@ -379,7 +299,7 @@ static void parse_locale_scripts(String locale_path, UnicodeLocaleData& locale_d auto const& scripts_object = locale_display_names_object.as_object().get("scripts"sv); scripts_object.as_object().for_each_member([&](auto const& key, JsonValue const& value) { - auto index = ensure_unique_string(locale_data, value.as_string()); + auto index = locale_data.unique_strings.ensure(value.as_string()); locale.scripts.set(key, index); if (!locale_data.scripts.contains_slow(key)) @@ -425,10 +345,10 @@ static void parse_locale_list_patterns(String misc_path, UnicodeLocaleData& loca auto type = list_pattern_type(key); auto style = list_pattern_style(key); - auto start = ensure_unique_string(locale_data, value.as_object().get("start"sv).as_string()); - auto middle = ensure_unique_string(locale_data, value.as_object().get("middle"sv).as_string()); - auto end = ensure_unique_string(locale_data, value.as_object().get("end"sv).as_string()); - auto pair = ensure_unique_string(locale_data, value.as_object().get("2"sv).as_string()); + auto start = locale_data.unique_strings.ensure(value.as_object().get("start"sv).as_string()); + auto middle = locale_data.unique_strings.ensure(value.as_object().get("middle"sv).as_string()); + auto end = locale_data.unique_strings.ensure(value.as_object().get("end"sv).as_string()); + auto pair = locale_data.unique_strings.ensure(value.as_object().get("2"sv).as_string()); if (!locale_data.list_pattern_types.contains_slow(type)) locale_data.list_pattern_types.append(type); @@ -459,7 +379,7 @@ static void parse_locale_currencies(String numbers_path, UnicodeLocaleData& loca currencies_object.as_object().for_each_member([&](auto const& key, JsonValue const& value) { auto const& display_name = value.as_object().get("displayName"sv); - auto index = ensure_unique_string(locale_data, display_name.as_string()); + auto index = locale_data.unique_strings.ensure(display_name.as_string()); locale.currencies.set(key, index); if (!locale_data.currencies.contains_slow(key)) @@ -508,7 +428,7 @@ static void parse_numeric_keywords(String locale_numbers_path, UnicodeLocaleData StringBuilder builder; builder.join(',', keyword_values); - auto index = ensure_unique_string(locale_data, builder.build()); + auto index = locale_data.unique_strings.ensure(builder.build()); locale.keywords.set(key, index); if (!locale_data.keywords.contains_slow(key)) @@ -558,16 +478,16 @@ static void parse_number_pattern(String pattern, UnicodeLocaleData& locale_data, } auto zero_format = replace_patterns(move(patterns[0])); - format.positive_format_index = ensure_unique_string(locale_data, String::formatted("{{plusSign}}{}", zero_format)); + format.positive_format_index = locale_data.unique_strings.ensure(String::formatted("{{plusSign}}{}", zero_format)); if (patterns.size() == 2) { auto negative_format = replace_patterns(move(patterns[1])); - format.negative_format_index = ensure_unique_string(locale_data, move(negative_format)); + format.negative_format_index = locale_data.unique_strings.ensure(move(negative_format)); } else { - format.negative_format_index = ensure_unique_string(locale_data, String::formatted("{{minusSign}}{}", zero_format)); + format.negative_format_index = locale_data.unique_strings.ensure(String::formatted("{{minusSign}}{}", zero_format)); } - format.zero_format_index = ensure_unique_string(locale_data, move(zero_format)); + format.zero_format_index = locale_data.unique_strings.ensure(move(zero_format)); } static void parse_number_systems(String locale_numbers_path, UnicodeLocaleData& locale_data, Locale& locale) @@ -588,7 +508,7 @@ static void parse_number_systems(String locale_numbers_path, UnicodeLocaleData& auto ensure_number_system = [&](auto const& system) -> NumberSystem& { return locale.number_systems.ensure(system, [&]() { - auto system_index = ensure_unique_string(locale_data, system); + auto system_index = locale_data.unique_strings.ensure(system); return NumberSystem { .system = system_index }; }); }; @@ -626,7 +546,7 @@ static void parse_number_systems(String locale_numbers_path, UnicodeLocaleData& auto& number_system = ensure_number_system(system); value.as_object().for_each_member([&](auto const& symbol, JsonValue const& localization) { - auto symbol_index = ensure_unique_string(locale_data, localization.as_string()); + auto symbol_index = locale_data.unique_strings.ensure(localization.as_string()); number_system.symbols.set(symbol, symbol_index); if (!locale_data.numeric_symbols.contains_slow(symbol)) @@ -701,21 +621,6 @@ static void parse_default_content_locales(String core_path, UnicodeLocaleData& l }); } -static Core::DirIterator path_to_dir_iterator(String path) -{ - LexicalPath lexical_path(move(path)); - lexical_path = lexical_path.append("main"sv); - VERIFY(Core::File::is_directory(lexical_path.string())); - - Core::DirIterator iterator(lexical_path.string(), Core::DirIterator::SkipParentAndBaseDir); - if (iterator.has_error()) { - warnln("{}: {}", lexical_path.string(), iterator.error_string()); - VERIFY_NOT_REACHED(); - } - - return iterator; -} - static void parse_all_locales(String core_path, String locale_names_path, String misc_path, String numbers_path, UnicodeLocaleData& locale_data) { auto identity_iterator = path_to_dir_iterator(locale_names_path); @@ -731,15 +636,15 @@ static void parse_all_locales(String core_path, String locale_names_path, String parse_likely_subtags(core_supplemental_path.string(), locale_data); auto remove_variants_from_path = [&](String path) -> Optional { - auto parsed_locale = parse_language(locale_data, LexicalPath::basename(path)); + auto parsed_locale = CanonicalLanguageID::parse(locale_data.unique_strings, LexicalPath::basename(path)); if (!parsed_locale.has_value()) return {}; StringBuilder builder; - builder.append(get_unique_string(locale_data, parsed_locale->language)); - if (auto script = get_unique_string(locale_data, parsed_locale->script); !script.is_empty()) + builder.append(locale_data.unique_strings.get(parsed_locale->language)); + if (auto script = locale_data.unique_strings.get(parsed_locale->script); !script.is_empty()) builder.appendff("-{}", script); - if (auto region = get_unique_string(locale_data, parsed_locale->region); !region.is_empty()) + if (auto region = locale_data.unique_strings.get(parsed_locale->region); !region.is_empty()) builder.appendff("-{}", region); return builder.build(); @@ -816,32 +721,6 @@ static void generate_unicode_locale_header(Core::File& file, UnicodeLocaleData& StringBuilder builder; SourceGenerator generator { builder }; - auto generate_enum = [&](StringView name, StringView default_, Vector& values) { - quick_sort(values); - - generator.set("name", name); - generator.set("underlying", ((values.size() + !default_.is_empty()) < 256) ? "u8"sv : "u16"sv); - - generator.append(R"~~~( -enum class @name@ : @underlying@ {)~~~"); - - if (!default_.is_empty()) { - generator.set("default", default_); - generator.append(R"~~~( - @default@,)~~~"); - } - - for (auto const& value : values) { - generator.set("value", format_identifier(name, value)); - generator.append(R"~~~( - @value@,)~~~"); - } - - generator.append(R"~~~( -}; -)~~~"); - }; - generator.append(R"~~~( #pragma once @@ -855,16 +734,16 @@ namespace Unicode { )~~~"); auto locales = locale_data.locales.keys(); - generate_enum("Locale"sv, "None"sv, locales); - generate_enum("Language"sv, {}, locale_data.languages); - generate_enum("Territory"sv, {}, locale_data.territories); - generate_enum("ScriptTag"sv, {}, locale_data.scripts); - generate_enum("Currency"sv, {}, locale_data.currencies); - generate_enum("Key"sv, {}, locale_data.keywords); - generate_enum("NumericSymbol"sv, {}, locale_data.numeric_symbols); - generate_enum("Variant"sv, {}, locale_data.variants); - generate_enum("ListPatternType"sv, {}, locale_data.list_pattern_types); - generate_enum("ListPatternStyle"sv, {}, locale_data.list_pattern_styles); + generate_enum(generator, format_identifier, "Locale"sv, "None"sv, locales); + generate_enum(generator, format_identifier, "Language"sv, {}, locale_data.languages); + generate_enum(generator, format_identifier, "Territory"sv, {}, locale_data.territories); + generate_enum(generator, format_identifier, "ScriptTag"sv, {}, locale_data.scripts); + generate_enum(generator, format_identifier, "Currency"sv, {}, locale_data.currencies); + generate_enum(generator, format_identifier, "Key"sv, {}, locale_data.keywords); + generate_enum(generator, format_identifier, "NumericSymbol"sv, {}, locale_data.numeric_symbols); + generate_enum(generator, format_identifier, "Variant"sv, {}, locale_data.variants); + generate_enum(generator, format_identifier, "ListPatternType"sv, {}, locale_data.list_pattern_types); + generate_enum(generator, format_identifier, "ListPatternStyle"sv, {}, locale_data.list_pattern_styles); generator.append(R"~~~( namespace Detail { @@ -919,7 +798,6 @@ static void generate_unicode_locale_implementation(Core::File& file, UnicodeLoca StringBuilder builder; SourceGenerator generator { builder }; generator.set("string_index_type"sv, s_string_index_type); - generator.set("strings_size"sv, String::number(locale_data.unique_strings.size())); generator.set("locales_size"sv, String::number(locale_data.locales.size())); generator.set("territories_size", String::number(locale_data.territories.size())); generator.set("variants_size", String::number(locale_data.max_variant_size)); @@ -944,28 +822,9 @@ struct Patterns { }; )~~~"); - generator.append(R"~~~( -static constexpr Array s_string_list { { - {})~~~"); - - constexpr size_t max_strings_per_row = 30; - size_t strings_in_current_row = 1; - - for (auto const& string : locale_data.unique_strings) { - if (strings_in_current_row++ > 0) - generator.append(", "); - - generator.append(String::formatted("\"{}\"sv", string)); - - if (strings_in_current_row == max_strings_per_row) { - strings_in_current_row = 0; - generator.append(",\n "); - } - } + locale_data.unique_strings.generate(generator); generator.append(R"~~~( -} }; - struct NumberFormat { Unicode::NumberFormat to_unicode_number_format() const { Unicode::NumberFormat number_format {}; @@ -1001,11 +860,6 @@ struct NumberSystem { }; )~~~"); - auto format_mapping_name = [](StringView format, StringView name) { - auto mapping_name = name.to_lowercase_string().replace("-"sv, "_"sv, true); - return String::formatted(format, mapping_name); - }; - auto append_index = [&](auto index) { generator.append(String::formatted(", {}", index)); }; @@ -1167,52 +1021,13 @@ static constexpr Array @name@ { {)~~~"); )~~~"); }; - auto append_mapping = [&](StringView type, StringView name, StringView format, auto format_list_callback) { - Vector mapping_names; - - for (auto const& locale : locale_data.locales) { - auto mapping_name = format_mapping_name(format, locale.key); - format_list_callback(mapping_name, locale.value); - mapping_names.append(move(mapping_name)); - } - - quick_sort(mapping_names); - - generator.set("type", type); - generator.set("name", name); - generator.set("size", String::number(locale_data.locales.size())); - generator.append(R"~~~( -static constexpr Array, @size@> @name@ { { - )~~~"); - - constexpr size_t max_values_per_row = 10; - size_t values_in_current_row = 0; - - for (auto& mapping_name : mapping_names) { - if (values_in_current_row++ > 0) - generator.append(" "); - - generator.set("name", move(mapping_name)); - generator.append("@name@.span(),"); - - if (values_in_current_row == max_values_per_row) { - values_in_current_row = 0; - generator.append("\n "); - } - } - - generator.append(R"~~~( -} }; -)~~~"); - }; - - append_mapping(s_string_index_type, "s_languages"sv, "s_languages_{}", [&](auto const& name, auto const& value) { append_string_index_list(name, locale_data.languages, value.languages); }); - append_mapping(s_string_index_type, "s_territories"sv, "s_territories_{}", [&](auto const& name, auto const& value) { append_string_index_list(name, locale_data.territories, value.territories); }); - append_mapping(s_string_index_type, "s_scripts"sv, "s_scripts_{}", [&](auto const& name, auto const& value) { append_string_index_list(name, locale_data.scripts, value.scripts); }); - append_mapping(s_string_index_type, "s_currencies"sv, "s_currencies_{}", [&](auto const& name, auto const& value) { append_string_index_list(name, locale_data.currencies, value.currencies); }); - append_mapping(s_string_index_type, "s_keywords"sv, "s_keywords_{}", [&](auto const& name, auto const& value) { append_string_index_list(name, locale_data.keywords, value.keywords); }); - append_mapping("NumberSystem"sv, "s_number_systems"sv, "s_number_systems_{}", [&](auto const& name, auto const& value) { append_number_systems(name, value.number_systems); }); - append_mapping("Patterns"sv, "s_list_patterns"sv, "s_list_patterns_{}", [&](auto const& name, auto const& value) { append_list_patterns(name, value.list_patterns); }); + generate_mapping(generator, locale_data.locales, s_string_index_type, "s_languages"sv, "s_languages_{}", [&](auto const& name, auto const& value) { append_string_index_list(name, locale_data.languages, value.languages); }); + generate_mapping(generator, locale_data.locales, s_string_index_type, "s_territories"sv, "s_territories_{}", [&](auto const& name, auto const& value) { append_string_index_list(name, locale_data.territories, value.territories); }); + generate_mapping(generator, locale_data.locales, s_string_index_type, "s_scripts"sv, "s_scripts_{}", [&](auto const& name, auto const& value) { append_string_index_list(name, locale_data.scripts, value.scripts); }); + generate_mapping(generator, locale_data.locales, s_string_index_type, "s_currencies"sv, "s_currencies_{}", [&](auto const& name, auto const& value) { append_string_index_list(name, locale_data.currencies, value.currencies); }); + generate_mapping(generator, locale_data.locales, s_string_index_type, "s_keywords"sv, "s_keywords_{}", [&](auto const& name, auto const& value) { append_string_index_list(name, locale_data.keywords, value.keywords); }); + 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, "Patterns"sv, "s_list_patterns"sv, "s_list_patterns_{}", [&](auto const& name, auto const& value) { append_list_patterns(name, value.list_patterns); }); generator.append(R"~~~( struct CanonicalLanguageID { @@ -1269,8 +1084,8 @@ static constexpr Array s_@name@ { { )~~~"); quick_sort(mappings, [&](auto const& lhs, auto const& rhs) { - auto const& lhs_language = get_unique_string(locale_data, lhs.key.language); - auto const& rhs_language = get_unique_string(locale_data, rhs.key.language); + auto const& lhs_language = locale_data.unique_strings.get(lhs.key.language); + auto const& rhs_language = locale_data.unique_strings.get(rhs.key.language); // Sort the keys such that "und" language tags are at the end, as those are less specific. if (lhs_language.starts_with("und"sv) && !rhs_language.starts_with("und"sv)) diff --git a/Meta/Lagom/Tools/CodeGenerators/LibUnicode/GeneratorUtil.h b/Meta/Lagom/Tools/CodeGenerators/LibUnicode/GeneratorUtil.h index 59f31033610..a512d1b6743 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibUnicode/GeneratorUtil.h +++ b/Meta/Lagom/Tools/CodeGenerators/LibUnicode/GeneratorUtil.h @@ -6,13 +6,146 @@ #pragma once +#include #include +#include #include #include #include #include #include #include +#include +#include +#include + +template +class UniqueStringStorage { +public: + StringIndexType ensure(String string) + { + // We maintain a set of unique strings in two structures: a vector which owns the unique string, + // and a hash map which maps that string to its index in the vector. The vector is to ensure the + // strings are generated in an easily known order, and the map is to allow quickly deciding if a + // string is actually unique (otherwise, we'd have to linear-search the vector for each string). + // + // Also note that index 0 will be reserved for the empty string, so the index returned from this + // method is actually the real index in the vector + 1. + if (auto index = m_unique_string_indices.get(string); index.has_value()) + return *index; + + m_unique_strings.append(move(string)); + size_t index = m_unique_strings.size(); + + VERIFY(index < NumericLimits::max()); + + auto string_index = static_cast(index); + m_unique_string_indices.set(m_unique_strings.last(), string_index); + + return string_index; + } + + StringView get(StringIndexType index) const + { + if (index == 0) + return {}; + + VERIFY(index <= m_unique_strings.size()); + return m_unique_strings.at(index - 1); + } + + void generate(SourceGenerator& generator) + { + generator.set("size"sv, String::number(m_unique_strings.size())); + + generator.append(R"~~~( +static constexpr Array s_string_list { { + {})~~~"); + + constexpr size_t max_strings_per_row = 40; + size_t strings_in_current_row = 1; + + for (auto const& string : m_unique_strings) { + if (strings_in_current_row++ > 0) + generator.append(", "); + + generator.append(String::formatted("\"{}\"sv", string)); + + if (strings_in_current_row == max_strings_per_row) { + strings_in_current_row = 0; + generator.append(",\n "); + } + } + + generator.append(R"~~~( +} }; +)~~~"); + } + +private: + Vector m_unique_strings; + HashMap m_unique_string_indices; +}; + +template +struct CanonicalLanguageID { + static Optional parse(UniqueStringStorage& unique_strings, StringView language) + { + CanonicalLanguageID language_id {}; + + auto segments = language.split_view('-'); + VERIFY(!segments.is_empty()); + size_t index = 0; + + if (Unicode::is_unicode_language_subtag(segments[index])) { + language_id.language = unique_strings.ensure(segments[index]); + if (segments.size() == ++index) + return language_id; + } else { + return {}; + } + + if (Unicode::is_unicode_script_subtag(segments[index])) { + language_id.script = unique_strings.ensure(segments[index]); + if (segments.size() == ++index) + return language_id; + } + + if (Unicode::is_unicode_region_subtag(segments[index])) { + language_id.region = unique_strings.ensure(segments[index]); + if (segments.size() == ++index) + return language_id; + } + + while (index < segments.size()) { + if (!Unicode::is_unicode_variant_subtag(segments[index])) + return {}; + language_id.variants.append(unique_strings.ensure(segments[index++])); + } + + return language_id; + } + + StringIndexType language { 0 }; + StringIndexType script { 0 }; + StringIndexType region { 0 }; + Vector variants {}; +}; + +inline Core::DirIterator path_to_dir_iterator(String path) +{ + LexicalPath lexical_path(move(path)); + lexical_path = lexical_path.append("main"sv); + VERIFY(Core::File::is_directory(lexical_path.string())); + + Core::DirIterator iterator(lexical_path.string(), Core::DirIterator::SkipParentAndBaseDir); + if (iterator.has_error()) { + warnln("{}: {}", lexical_path.string(), iterator.error_string()); + VERIFY_NOT_REACHED(); + } + + return iterator; +} inline void ensure_from_string_types_are_generated(SourceGenerator& generator) { @@ -98,3 +231,77 @@ Optional<@return_type@> @method_name@(StringView key) } )~~~"); } + +template +void generate_enum(SourceGenerator& generator, IdentifierFormatter&& format_identifier, StringView name, StringView default_, Vector& values) +{ + quick_sort(values); + + generator.set("name", name); + generator.set("underlying", ((values.size() + !default_.is_empty()) < 256) ? "u8"sv : "u16"sv); + + generator.append(R"~~~( +enum class @name@ : @underlying@ {)~~~"); + + if (!default_.is_empty()) { + generator.set("default", default_); + generator.append(R"~~~( + @default@,)~~~"); + } + + for (auto const& value : values) { + generator.set("value", format_identifier(name, value)); + generator.append(R"~~~( + @value@,)~~~"); + } + + generator.append(R"~~~( +}; +)~~~"); +} + +template +void generate_mapping(SourceGenerator& generator, LocalesType const& locales, StringView type, StringView name, StringView format, ListFormatter&& format_list) +{ + auto format_mapping_name = [](StringView format, StringView name) { + auto mapping_name = name.to_lowercase_string().replace("-"sv, "_"sv, true); + return String::formatted(format, mapping_name); + }; + + Vector mapping_names; + + for (auto const& locale : locales) { + auto mapping_name = format_mapping_name(format, locale.key); + format_list(mapping_name, locale.value); + mapping_names.append(move(mapping_name)); + } + + quick_sort(mapping_names); + + generator.set("type", type); + generator.set("name", name); + generator.set("size", String::number(locales.size())); + generator.append(R"~~~( +static constexpr Array, @size@> @name@ { { + )~~~"); + + constexpr size_t max_values_per_row = 10; + size_t values_in_current_row = 0; + + for (auto& mapping_name : mapping_names) { + if (values_in_current_row++ > 0) + generator.append(" "); + + generator.set("name", move(mapping_name)); + generator.append("@name@.span(),"); + + if (values_in_current_row == max_values_per_row) { + values_in_current_row = 0; + generator.append("\n "); + } + } + + generator.append(R"~~~( +} }; +)~~~"); +}