diff --git a/Meta/Lagom/Tools/CodeGenerators/LibUnicode/GenerateUnicodeData.cpp b/Meta/Lagom/Tools/CodeGenerators/LibUnicode/GenerateUnicodeData.cpp index 5a029c597e..01e4d8f261 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibUnicode/GenerateUnicodeData.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibUnicode/GenerateUnicodeData.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include "GeneratorUtil.h" #include #include #include @@ -560,7 +561,6 @@ static void generate_unicode_data_implementation(Core::File& file, UnicodeData c #include #include #include -#include #include #include #include @@ -810,33 +810,15 @@ bool code_point_has_@enum_snake@(u32 code_point, @enum_title@ @enum_snake@) }; auto append_from_string = [&](StringView enum_title, StringView enum_snake, PropList const& prop_list, Vector const& aliases) { - generator.set("enum_title", enum_title); - generator.set("enum_snake", enum_snake); + HashValueMap hashes; + hashes.ensure_capacity(prop_list.size() + aliases.size()); - auto properties = prop_list.keys(); + for (auto const& prop : prop_list) + hashes.set(prop.key.hash(), prop.key); for (auto const& alias : aliases) - properties.append(alias.alias); - quick_sort(properties); + hashes.set(alias.alias.hash(), alias.alias); - generator.append(R"~~~( -Optional<@enum_title@> @enum_snake@_from_string(StringView const& @enum_snake@) -{ - static HashMap @enum_snake@_values { {)~~~"); - - for (auto const& property : properties) { - generator.set("property", property); - generator.append(R"~~~( - { "@property@"sv, @enum_title@::@property@ },)~~~"); - } - - generator.append(R"~~~( - } }; - - if (auto value = @enum_snake@_values.get(@enum_snake@); value.has_value()) - return value.value(); - return {}; -} -)~~~"); + generate_value_from_string(generator, "{}_from_string"sv, enum_title, enum_snake, move(hashes)); }; append_prop_search("GeneralCategory"sv, "general_category"sv, "s_general_categories"sv); diff --git a/Meta/Lagom/Tools/CodeGenerators/LibUnicode/GenerateUnicodeLocale.cpp b/Meta/Lagom/Tools/CodeGenerators/LibUnicode/GenerateUnicodeLocale.cpp index 3a119bcb48..65aed82c9e 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibUnicode/GenerateUnicodeLocale.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibUnicode/GenerateUnicodeLocale.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include "GeneratorUtil.h" #include #include #include @@ -666,7 +667,7 @@ static void generate_unicode_locale_implementation(Core::File& file, UnicodeLoca generator.append(R"~~~( #include -#include +#include #include #include #include @@ -1043,67 +1044,24 @@ Optional get_locale_@enum_snake@_mapping(StringView locale, StringVi )~~~"); }; - auto append_from_string = [&](StringView enum_title, StringView enum_snake, Vector const& values) { - generator.set("enum_title", enum_title); - generator.set("enum_snake", enum_snake); + auto append_from_string = [&](StringView enum_title, StringView enum_snake, auto const& values) { + HashValueMap hashes; + hashes.ensure_capacity(values.size()); - generator.append(R"~~~( -Optional<@enum_title@> @enum_snake@_from_string(StringView const& @enum_snake@) -{ - static HashMap @enum_snake@_values { {)~~~"); + for (auto const& value : values) + hashes.set(value.hash(), format_identifier(enum_title, value)); - for (auto const& value : values) { - generator.set("key"sv, value); - generator.set("value"sv, format_identifier(enum_title, value)); - - generator.append(R"~~~( - { "@key@"sv, @enum_title@::@value@ },)~~~"); - } - - generator.append(R"~~~( - } }; - - if (auto value = @enum_snake@_values.get(@enum_snake@); value.has_value()) - return value.value(); - return {}; -} -)~~~"); + generate_value_from_string(generator, "{}_from_string"sv, enum_title, enum_snake, move(hashes)); }; auto append_alias_search = [&](StringView enum_snake, auto const& aliases) { - generator.set("enum_snake", enum_snake); + HashValueMap hashes; + hashes.ensure_capacity(aliases.size()); - generator.append(R"~~~( -Optional resolve_@enum_snake@_alias(StringView const& @enum_snake@) -{ - static HashMap @enum_snake@_aliases { { - )~~~"); + for (auto const& alias : aliases) + hashes.set(alias.key.hash(), alias.value); - constexpr size_t max_values_per_row = 10; - size_t values_in_current_row = 0; - - for (auto const& alias : aliases) { - if (values_in_current_row++ > 0) - generator.append(" "); - - generator.set("key"sv, alias.key); - generator.set("alias"sv, String::number(alias.value)); - generator.append("{ \"@key@\"sv, @alias@ },"); - - if (values_in_current_row == max_values_per_row) { - generator.append("\n "); - values_in_current_row = 0; - } - } - - generator.append(R"~~~( - } }; - - if (auto alias = @enum_snake@_aliases.get(@enum_snake@); alias.has_value()) - return s_string_list[alias.value()]; - return {}; -} -)~~~"); + generate_value_from_string(generator, "resolve_{}_alias"sv, "size_t"sv, enum_snake, move(hashes), "StringView"sv, "s_string_list[{}]"sv); }; append_from_string("Locale"sv, "locale"sv, locale_data.locales.keys()); diff --git a/Meta/Lagom/Tools/CodeGenerators/LibUnicode/GeneratorUtil.h b/Meta/Lagom/Tools/CodeGenerators/LibUnicode/GeneratorUtil.h new file mode 100644 index 0000000000..5b6b126f2f --- /dev/null +++ b/Meta/Lagom/Tools/CodeGenerators/LibUnicode/GeneratorUtil.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2021, Tim Flynn + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +inline void ensure_from_string_types_are_generated(SourceGenerator& generator) +{ + static bool generated_from_string_types = false; + if (generated_from_string_types) + return; + + generator.append(R"~~~( +template +struct HashValuePair { + unsigned hash { 0 }; + ValueType value {}; +}; + +template +struct HashValueComparator +{ + constexpr int operator()(unsigned hash, HashValuePair const& pair) + { + if (hash > pair.hash) + return 1; + if (hash < pair.hash) + return -1; + return 0; + } +}; +)~~~"); + + generated_from_string_types = true; +} + +template +using HashValueMap = HashMap; + +template +void generate_value_from_string(SourceGenerator& generator, StringView method_name_format, StringView value_type, StringView value_name, HashValueMap hashes, Optional return_type = {}, StringView return_format = "{}"sv) +{ + ensure_from_string_types_are_generated(generator); + + generator.set("method_name", String::formatted(method_name_format, value_name)); + generator.set("value_type", value_type); + generator.set("value_name", value_name); + generator.set("return_type", return_type.has_value() ? *return_type : value_type); + generator.set("size", String::number(hashes.size())); + + generator.append(R"~~~( +Optional<@return_type@> @method_name@(StringView const& key) +{ + constexpr Array, @size@> hash_pairs { { + )~~~"); + + auto hash_keys = hashes.keys(); + quick_sort(hash_keys); + + constexpr size_t max_values_per_row = 10; + size_t values_in_current_row = 0; + + for (auto hash_key : hash_keys) { + if (values_in_current_row++ > 0) + generator.append(" "); + + if constexpr (IsIntegral) + generator.set("value"sv, String::number(hashes.get(hash_key).value())); + else + generator.set("value"sv, String::formatted("{}::{}", value_type, hashes.get(hash_key).value())); + + generator.set("hash"sv, String::number(hash_key)); + generator.append("{ @hash@U, @value@ },"sv); + + if (values_in_current_row == max_values_per_row) { + generator.append("\n "); + values_in_current_row = 0; + } + } + + generator.set("return_statement", String::formatted(return_format, "value->value"sv)); + generator.append(R"~~~( + } }; + + if (auto const* value = binary_search(hash_pairs, key.hash(), nullptr, HashValueComparator<@value_type@> {})) + return @return_statement@; + return {}; +} +)~~~"); +}