LibUnicode: Generate unique units

This commit is contained in:
Timothy Flynn 2021-12-11 08:30:50 -05:00 committed by Linus Groh
parent 4c2c8b8e33
commit 1e95e7716b
Notes: sideshowbarker 2024-07-17 22:59:14 +09:00

View file

@ -44,6 +44,9 @@ constexpr auto s_numeric_symbol_list_index_type = "u8"sv;
using NumberSystemIndexType = u8;
constexpr auto s_number_system_index_type = "u8"sv;
using UnitIndexType = u16;
constexpr auto s_unit_index_type = "u16"sv;
enum class NumberFormatType {
Standard,
Compact,
@ -225,15 +228,50 @@ struct AK::Traits<NumberSystem> : public GenericTraits<NumberSystem> {
};
struct Unit {
unsigned hash() const
{
auto hash = int_hash(unit);
hash = pair_int_hash(hash, long_formats);
hash = pair_int_hash(hash, short_formats);
hash = pair_int_hash(hash, narrow_formats);
return hash;
}
bool operator==(Unit const& other) const
{
return (unit == other.unit)
&& (long_formats == other.long_formats)
&& (short_formats == other.short_formats)
&& (narrow_formats == other.narrow_formats);
}
StringIndexType unit { 0 };
NumberFormatListIndexType long_formats { 0 };
NumberFormatListIndexType short_formats { 0 };
NumberFormatListIndexType narrow_formats { 0 };
};
template<>
struct AK::Formatter<Unit> : Formatter<FormatString> {
ErrorOr<void> format(FormatBuilder& builder, Unit const& system)
{
return Formatter<FormatString>::format(builder,
"{{ {}, {}, {}, {} }}",
system.unit,
system.long_formats,
system.short_formats,
system.narrow_formats);
}
};
template<>
struct AK::Traits<Unit> : public GenericTraits<Unit> {
static unsigned hash(Unit const& u) { return u.hash(); }
};
struct Locale {
HashMap<String, NumberSystemIndexType> number_systems;
HashMap<String, Unit> units {};
HashMap<String, UnitIndexType> units {};
};
struct UnicodeLocaleData {
@ -242,6 +280,7 @@ struct UnicodeLocaleData {
UniqueStorage<NumberFormatList, NumberFormatListIndexType> unique_format_lists;
UniqueStorage<NumericSymbolList, NumericSymbolListIndexType> unique_symbols;
UniqueStorage<NumberSystem, NumberSystemIndexType> unique_systems;
UniqueStorage<Unit, UnitIndexType> unique_units;
HashMap<String, Locale> locales;
size_t max_identifier_count { 0 };
@ -545,17 +584,19 @@ static ErrorOr<void> parse_units(String locale_units_path, UnicodeLocaleData& lo
units_path = units_path.append("units.json"sv);
auto units_file = TRY(Core::File::open(units_path.string(), Core::OpenMode::ReadOnly));
auto units = TRY(JsonValue::from_string(units_file->read_all()));
auto locale_units = TRY(JsonValue::from_string(units_file->read_all()));
auto const& main_object = units.as_object().get("main"sv);
auto const& main_object = locale_units.as_object().get("main"sv);
auto const& locale_object = main_object.as_object().get(units_path.parent().basename());
auto const& locale_units_object = locale_object.as_object().get("units"sv);
auto const& long_object = locale_units_object.as_object().get("long"sv);
auto const& short_object = locale_units_object.as_object().get("short"sv);
auto const& narrow_object = locale_units_object.as_object().get("narrow"sv);
HashMap<String, Unit> units;
auto ensure_unit = [&](auto const& unit) -> Unit& {
return locale.units.ensure(unit, [&]() {
return units.ensure(unit, [&]() {
auto unit_index = locale_data.unique_strings.ensure(unit);
return Unit { .unit = unit_index };
});
@ -636,6 +677,11 @@ static ErrorOr<void> parse_units(String locale_units_path, UnicodeLocaleData& lo
parse_units_object(short_object.as_object(), Unicode::Style::Short);
parse_units_object(narrow_object.as_object(), Unicode::Style::Narrow);
for (auto& unit : units) {
auto unit_index = locale_data.unique_units.ensure(move(unit.value));
locale.units.set(unit.key, unit_index);
}
return {};
}
@ -793,6 +839,7 @@ struct Unit {
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);
locale_data.unique_systems.generate(generator, "NumberSystem"sv, "s_number_systems"sv, 10);
locale_data.unique_units.generate(generator, "Unit"sv, "s_units"sv, 10);
auto append_map = [&](String name, auto type, auto const& map) {
generator.set("name", name);
@ -812,30 +859,8 @@ static constexpr Array<@type@, @size@> @name@ { {)~~~");
generator.append(" } };");
};
auto append_units = [&](String name, auto const& units) {
generator.set("name", name);
generator.set("size", String::number(units.size()));
generator.append(R"~~~(
static constexpr Array<Unit, @size@> @name@ { {)~~~");
bool first = true;
for (auto const& unit : units) {
generator.set("unit"sv, String::number(unit.value.unit));
generator.set("long_formats"sv, String::number(unit.value.long_formats));
generator.set("short_formats"sv, String::number(unit.value.short_formats));
generator.set("narrow_formats"sv, String::number(unit.value.narrow_formats));
generator.append(first ? " " : ", ");
generator.append("{ @unit@, @long_formats@, @short_formats@, @narrow_formats@ }");
first = false;
}
generator.append(" } };");
};
generate_mapping(generator, locale_data.locales, s_number_system_index_type, "s_locale_number_systems"sv, "s_number_systems_{}", [&](auto const& name, auto const& value) { append_map(name, s_number_system_index_type, 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); });
generate_mapping(generator, locale_data.locales, s_unit_index_type, "s_locale_units"sv, "s_units_{}", [&](auto const& name, auto const& value) { append_map(name, s_unit_index_type, value.units); });
generator.append(R"~~~(
static NumberSystem const* find_number_system(StringView locale, StringView system)
@ -947,9 +972,11 @@ static Unit const* find_units(StringView locale, StringView unit)
return nullptr;
auto locale_index = to_underlying(*locale_value) - 1; // Subtract 1 because 0 == Locale::None.
auto const& locale_units = s_units.at(locale_index);
auto const& locale_units = s_locale_units.at(locale_index);
for (auto unit_index : locale_units) {
auto const& units = s_units.at(unit_index);
for (auto const& units : locale_units) {
if (unit == s_string_list[units.unit])
return &units;
};