Title: [264537] trunk/Source/_javascript_Core
Revision
264537
Author
[email protected]
Date
2020-07-17 15:05:30 -0700 (Fri, 17 Jul 2020)

Log Message

[JSC] Clean up resolveLocale
https://bugs.webkit.org/show_bug.cgi?id=214446

Reviewed by Darin Adler.

Introduce RelevantExtensionKey and optimize resolveLocale implementation which avoids using HashMap for input and output.
We instead use std::array<T, numberOfRelevantExtensionKeys> since # of RelevantExtensionKeys is only 6.

For input option, we use std::array<Optional<String>, numberOfRelevantExtensionKeys> since this distinguish non-set-option and null String().
For output extension values, we simply use std::array<String, numberOfRelevantExtensionKeys>.

* runtime/IntlCollator.cpp:
(JSC::IntlCollator::sortLocaleData):
(JSC::IntlCollator::searchLocaleData):
(JSC::IntlCollator::initializeCollator):
* runtime/IntlCollator.h:
* runtime/IntlDateTimeFormat.cpp:
(JSC::IntlDateTimeFormat::localeData):
(JSC::IntlDateTimeFormat::initializeDateTimeFormat):
* runtime/IntlDateTimeFormat.h:
* runtime/IntlNumberFormat.cpp:
(JSC::IntlNumberFormat::localeData):
(JSC::IntlNumberFormat::initializeNumberFormat):
* runtime/IntlNumberFormat.h:
* runtime/IntlObject.cpp:
(JSC::relevantExtensionKeyString):
(JSC::resolveLocale):
* runtime/IntlObject.h:
* runtime/IntlPluralRules.cpp:
(JSC::IntlPluralRules::localeData):
(JSC::IntlPluralRules::initializePluralRules):
* runtime/IntlPluralRules.h:
* runtime/IntlRelativeTimeFormat.cpp:
(JSC::IntlRelativeTimeFormat::localeData):
(JSC::IntlRelativeTimeFormat::initializeRelativeTimeFormat):
* runtime/IntlRelativeTimeFormat.h:

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (264536 => 264537)


--- trunk/Source/_javascript_Core/ChangeLog	2020-07-17 22:01:45 UTC (rev 264536)
+++ trunk/Source/_javascript_Core/ChangeLog	2020-07-17 22:05:30 UTC (rev 264537)
@@ -1,3 +1,42 @@
+2020-07-17  Yusuke Suzuki  <[email protected]>
+
+        [JSC] Clean up resolveLocale
+        https://bugs.webkit.org/show_bug.cgi?id=214446
+
+        Reviewed by Darin Adler.
+
+        Introduce RelevantExtensionKey and optimize resolveLocale implementation which avoids using HashMap for input and output.
+        We instead use std::array<T, numberOfRelevantExtensionKeys> since # of RelevantExtensionKeys is only 6.
+
+        For input option, we use std::array<Optional<String>, numberOfRelevantExtensionKeys> since this distinguish non-set-option and null String().
+        For output extension values, we simply use std::array<String, numberOfRelevantExtensionKeys>.
+
+        * runtime/IntlCollator.cpp:
+        (JSC::IntlCollator::sortLocaleData):
+        (JSC::IntlCollator::searchLocaleData):
+        (JSC::IntlCollator::initializeCollator):
+        * runtime/IntlCollator.h:
+        * runtime/IntlDateTimeFormat.cpp:
+        (JSC::IntlDateTimeFormat::localeData):
+        (JSC::IntlDateTimeFormat::initializeDateTimeFormat):
+        * runtime/IntlDateTimeFormat.h:
+        * runtime/IntlNumberFormat.cpp:
+        (JSC::IntlNumberFormat::localeData):
+        (JSC::IntlNumberFormat::initializeNumberFormat):
+        * runtime/IntlNumberFormat.h:
+        * runtime/IntlObject.cpp:
+        (JSC::relevantExtensionKeyString):
+        (JSC::resolveLocale):
+        * runtime/IntlObject.h:
+        * runtime/IntlPluralRules.cpp:
+        (JSC::IntlPluralRules::localeData):
+        (JSC::IntlPluralRules::initializePluralRules):
+        * runtime/IntlPluralRules.h:
+        * runtime/IntlRelativeTimeFormat.cpp:
+        (JSC::IntlRelativeTimeFormat::localeData):
+        (JSC::IntlRelativeTimeFormat::initializeRelativeTimeFormat):
+        * runtime/IntlRelativeTimeFormat.h:
+
 2020-07-17  Xan López  <[email protected]>
 
         Math.max() can yield the wrong result for max(0, -0).

Modified: trunk/Source/_javascript_Core/runtime/IntlCollator.cpp (264536 => 264537)


--- trunk/Source/_javascript_Core/runtime/IntlCollator.cpp	2020-07-17 22:01:45 UTC (rev 264536)
+++ trunk/Source/_javascript_Core/runtime/IntlCollator.cpp	2020-07-17 22:05:30 UTC (rev 264537)
@@ -39,10 +39,6 @@
 const ClassInfo IntlCollator::s_info = { "Object", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(IntlCollator) };
 
 namespace IntlCollatorInternal {
-constexpr const char* relevantExtensionKeys[3] = { "co", "kf", "kn" };
-constexpr size_t collationIndex = 0;
-constexpr size_t caseFirstIndex = 1;
-constexpr size_t numericIndex = 2;
 constexpr bool verbose = false;
 }
 
@@ -85,12 +81,12 @@
     visitor.append(thisObject->m_boundCompare);
 }
 
-Vector<String> IntlCollator::sortLocaleData(const String& locale, size_t keyIndex)
+Vector<String> IntlCollator::sortLocaleData(const String& locale, RelevantExtensionKey key)
 {
     // 9.1 Internal slots of Service Constructors & 10.2.3 Internal slots (ECMA-402 2.0)
     Vector<String> keyLocaleData;
-    switch (keyIndex) {
-    case IntlCollatorInternal::collationIndex: {
+    switch (key) {
+    case RelevantExtensionKey::Co: {
         // 10.2.3 "The first element of [[sortLocaleData]][locale].co and [[searchLocaleData]][locale].co must be null for all locale values."
         keyLocaleData.append({ });
 
@@ -119,13 +115,13 @@
         }
         break;
     }
-    case IntlCollatorInternal::caseFirstIndex:
+    case RelevantExtensionKey::Kf:
         keyLocaleData.reserveInitialCapacity(3);
         keyLocaleData.uncheckedAppend("false"_s);
         keyLocaleData.uncheckedAppend("lower"_s);
         keyLocaleData.uncheckedAppend("upper"_s);
         break;
-    case IntlCollatorInternal::numericIndex:
+    case RelevantExtensionKey::Kn:
         keyLocaleData.reserveInitialCapacity(2);
         keyLocaleData.uncheckedAppend("false"_s);
         keyLocaleData.uncheckedAppend("true"_s);
@@ -136,23 +132,23 @@
     return keyLocaleData;
 }
 
-Vector<String> IntlCollator::searchLocaleData(const String&, size_t keyIndex)
+Vector<String> IntlCollator::searchLocaleData(const String&, RelevantExtensionKey key)
 {
     // 9.1 Internal slots of Service Constructors & 10.2.3 Internal slots (ECMA-402 2.0)
     Vector<String> keyLocaleData;
-    switch (keyIndex) {
-    case IntlCollatorInternal::collationIndex:
+    switch (key) {
+    case RelevantExtensionKey::Co:
         // 10.2.3 "The first element of [[sortLocaleData]][locale].co and [[searchLocaleData]][locale].co must be null for all locale values."
         keyLocaleData.reserveInitialCapacity(1);
         keyLocaleData.append({ });
         break;
-    case IntlCollatorInternal::caseFirstIndex:
+    case RelevantExtensionKey::Kf:
         keyLocaleData.reserveInitialCapacity(3);
         keyLocaleData.uncheckedAppend("false"_s);
         keyLocaleData.uncheckedAppend("lower"_s);
         keyLocaleData.uncheckedAppend("upper"_s);
         break;
-    case IntlCollatorInternal::numericIndex:
+    case RelevantExtensionKey::Kn:
         keyLocaleData.reserveInitialCapacity(2);
         keyLocaleData.uncheckedAppend("false"_s);
         keyLocaleData.uncheckedAppend("true"_s);
@@ -183,7 +179,7 @@
 
     auto localeData = (m_usage == Usage::Sort) ? sortLocaleData : searchLocaleData;
 
-    HashMap<String, String> opt;
+    ResolveLocaleOptions localeOptions;
 
     LocaleMatcher localeMatcher = intlOption<LocaleMatcher>(globalObject, options, vm.propertyNames->localeMatcher, { { "lookup"_s, LocaleMatcher::Lookup }, { "best fit"_s, LocaleMatcher::BestFit } }, "localeMatcher must be either \"lookup\" or \"best fit\""_s, LocaleMatcher::BestFit);
     RETURN_IF_EXCEPTION(scope, void());
@@ -191,27 +187,27 @@
     TriState numeric = intlBooleanOption(globalObject, options, vm.propertyNames->numeric);
     RETURN_IF_EXCEPTION(scope, void());
     if (numeric != TriState::Indeterminate)
-        opt.add("kn"_s, numeric == TriState::True ? "true"_s : "false"_s);
+        localeOptions[static_cast<unsigned>(RelevantExtensionKey::Kn)] = String(numeric == TriState::True ? "true"_s : "false"_s);
 
     String caseFirstOption = intlStringOption(globalObject, options, vm.propertyNames->caseFirst, { "upper", "lower", "false" }, "caseFirst must be either \"upper\", \"lower\", or \"false\"", nullptr);
     RETURN_IF_EXCEPTION(scope, void());
     if (!caseFirstOption.isNull())
-        opt.add("kf"_s, caseFirstOption);
+        localeOptions[static_cast<unsigned>(RelevantExtensionKey::Kf)] = caseFirstOption;
 
     auto& availableLocales = intlCollatorAvailableLocales();
-    auto result = resolveLocale(globalObject, availableLocales, requestedLocales, localeMatcher, opt, IntlCollatorInternal::relevantExtensionKeys, WTF_ARRAY_LENGTH(IntlCollatorInternal::relevantExtensionKeys), localeData);
+    auto resolved = resolveLocale(globalObject, availableLocales, requestedLocales, localeMatcher, localeOptions, { RelevantExtensionKey::Co, RelevantExtensionKey::Kf, RelevantExtensionKey::Kn }, localeData);
 
-    m_locale = result.get("locale"_s);
+    m_locale = resolved.locale;
     if (m_locale.isEmpty()) {
         throwTypeError(globalObject, scope, "failed to initialize Collator due to invalid locale"_s);
         return;
     }
 
-    const String& collation = result.get("co"_s);
+    const String& collation = resolved.extensions[static_cast<unsigned>(RelevantExtensionKey::Co)];
     m_collation = collation.isNull() ? "default"_s : collation;
-    m_numeric = result.get("kn"_s) == "true";
+    m_numeric = resolved.extensions[static_cast<unsigned>(RelevantExtensionKey::Kn)] == "true"_s;
 
-    const String& caseFirstString = result.get("kf"_s);
+    const String& caseFirstString = resolved.extensions[static_cast<unsigned>(RelevantExtensionKey::Kf)];
     if (caseFirstString == "lower")
         m_caseFirst = CaseFirst::Lower;
     else if (caseFirstString == "upper")
@@ -236,7 +232,7 @@
         // searchLocaleData filters out "co" unicode extension. However, we need to pass "co" to ICU when Usage::Search is specified.
         // So we need to pass "co" unicode extension through locale. Since the other relevant extensions are handled via ucol_setAttribute,
         // we can just use dataLocale
-        dataLocaleWithExtensions = makeString(result.get("dataLocale"_s), "-u-co-search").utf8();
+        dataLocaleWithExtensions = makeString(resolved.dataLocale, "-u-co-search").utf8();
         break;
     }
     dataLogLnIf(IntlCollatorInternal::verbose, "dataLocaleWithExtensions:(", dataLocaleWithExtensions, ")");

Modified: trunk/Source/_javascript_Core/runtime/IntlCollator.h (264536 => 264537)


--- trunk/Source/_javascript_Core/runtime/IntlCollator.h	2020-07-17 22:01:45 UTC (rev 264536)
+++ trunk/Source/_javascript_Core/runtime/IntlCollator.h	2020-07-17 22:05:30 UTC (rev 264537)
@@ -31,6 +31,8 @@
 
 namespace JSC {
 
+enum class RelevantExtensionKey : uint8_t;
+
 class JSBoundFunction;
 
 class IntlCollator final : public JSNonFinalObject {
@@ -67,8 +69,8 @@
     void finishCreation(VM&);
     static void visitChildren(JSCell*, SlotVisitor&);
 
-    static Vector<String> sortLocaleData(const String&, size_t);
-    static Vector<String> searchLocaleData(const String&, size_t);
+    static Vector<String> sortLocaleData(const String&, RelevantExtensionKey);
+    static Vector<String> searchLocaleData(const String&, RelevantExtensionKey);
 
     enum class Usage : uint8_t { Sort, Search };
     enum class Sensitivity : uint8_t { Base, Accent, Case, Variant };

Modified: trunk/Source/_javascript_Core/runtime/IntlDateTimeFormat.cpp (264536 => 264537)


--- trunk/Source/_javascript_Core/runtime/IntlDateTimeFormat.cpp	2020-07-17 22:01:45 UTC (rev 264536)
+++ trunk/Source/_javascript_Core/runtime/IntlDateTimeFormat.cpp	2020-07-17 22:05:30 UTC (rev 264537)
@@ -44,10 +44,6 @@
 const ClassInfo IntlDateTimeFormat::s_info = { "Object", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(IntlDateTimeFormat) };
 
 namespace IntlDateTimeFormatInternal {
-constexpr const char* relevantExtensionKeys[3] = { "ca", "hc", "nu" };
-constexpr size_t calendarIndex = 0;
-constexpr size_t hourCycleIndex = 1;
-constexpr size_t numberingSystemIndex = 2;
 }
 
 void IntlDateTimeFormat::UDateFormatDeleter::operator()(UDateFormat* dateFormat) const
@@ -163,11 +159,11 @@
     return canonical;
 }
 
-Vector<String> IntlDateTimeFormat::localeData(const String& locale, size_t keyIndex)
+Vector<String> IntlDateTimeFormat::localeData(const String& locale, RelevantExtensionKey key)
 {
     Vector<String> keyLocaleData;
-    switch (keyIndex) {
-    case IntlDateTimeFormatInternal::calendarIndex: {
+    switch (key) {
+    case RelevantExtensionKey::Ca: {
         UErrorCode status = U_ZERO_ERROR;
         UEnumeration* calendars = ucal_getKeywordValuesForLocale("calendar", locale.utf8().data(), false, &status);
         ASSERT(U_SUCCESS(status));
@@ -188,7 +184,7 @@
         uenum_close(calendars);
         break;
     }
-    case IntlDateTimeFormatInternal::hourCycleIndex:
+    case RelevantExtensionKey::Hc:
         // Null default so we know to use 'j' in pattern.
         keyLocaleData.append(String());
         keyLocaleData.append("h11"_s);
@@ -196,7 +192,7 @@
         keyLocaleData.append("h23"_s);
         keyLocaleData.append("h24"_s);
         break;
-    case IntlDateTimeFormatInternal::numberingSystemIndex:
+    case RelevantExtensionKey::Nu:
         keyLocaleData = numberingSystemsForLocale(locale);
         break;
     default:
@@ -419,7 +415,7 @@
     JSObject* options = toDateTimeOptionsAnyDate(globalObject, originalOptions);
     RETURN_IF_EXCEPTION(scope, void());
 
-    HashMap<String, String> opt;
+    ResolveLocaleOptions localeOptions;
 
     LocaleMatcher localeMatcher = intlOption<LocaleMatcher>(globalObject, options, vm.propertyNames->localeMatcher, { { "lookup"_s, LocaleMatcher::Lookup }, { "best fit"_s, LocaleMatcher::BestFit } }, "localeMatcher must be either \"lookup\" or \"best fit\""_s, LocaleMatcher::BestFit);
     RETURN_IF_EXCEPTION(scope, void());
@@ -431,7 +427,7 @@
             throwRangeError(globalObject, scope, "calendar is not a well-formed calendar value"_s);
             return;
         }
-        opt.add("ca"_s, calendar);
+        localeOptions[static_cast<unsigned>(RelevantExtensionKey::Ca)] = calendar;
     }
 
     String numberingSystem = intlStringOption(globalObject, options, vm.propertyNames->numberingSystem, { }, nullptr, nullptr);
@@ -441,7 +437,7 @@
             throwRangeError(globalObject, scope, "numberingSystem is not a well-formed numbering system value"_s);
             return;
         }
-        opt.add("nu"_s, numberingSystem);
+        localeOptions[static_cast<unsigned>(RelevantExtensionKey::Nu)] = numberingSystem;
     }
 
     TriState hour12 = intlBooleanOption(globalObject, options, vm.propertyNames->hour12);
@@ -454,20 +450,20 @@
         // Set hour12 here to simplify hour logic later.
         hour12 = triState(hourCycle == "h11" || hourCycle == "h12");
         if (!hourCycle.isNull())
-            opt.add("hc"_s, hourCycle);
+            localeOptions[static_cast<unsigned>(RelevantExtensionKey::Hc)] = hourCycle;
     } else
-        opt.add("hc"_s, String());
+        localeOptions[static_cast<unsigned>(RelevantExtensionKey::Hc)] = String();
 
     const HashSet<String>& availableLocales = intlDateTimeFormatAvailableLocales();
-    HashMap<String, String> resolved = resolveLocale(globalObject, availableLocales, requestedLocales, localeMatcher, opt, IntlDateTimeFormatInternal::relevantExtensionKeys, WTF_ARRAY_LENGTH(IntlDateTimeFormatInternal::relevantExtensionKeys), localeData);
+    auto resolved = resolveLocale(globalObject, availableLocales, requestedLocales, localeMatcher, localeOptions, { RelevantExtensionKey::Ca, RelevantExtensionKey::Hc, RelevantExtensionKey::Nu }, localeData);
 
-    m_locale = resolved.get(vm.propertyNames->locale.string());
+    m_locale = resolved.locale;
     if (m_locale.isEmpty()) {
         throwTypeError(globalObject, scope, "failed to initialize DateTimeFormat due to invalid locale"_s);
         return;
     }
 
-    m_calendar = resolved.get("ca"_s);
+    m_calendar = resolved.extensions[static_cast<unsigned>(RelevantExtensionKey::Ca)];
     if (m_calendar == "gregorian")
         m_calendar = "gregory"_s;
     else if (m_calendar == "islamicc")
@@ -475,9 +471,9 @@
     else if (m_calendar == "ethioaa")
         m_calendar = "ethiopic-amete-alem"_s;
 
-    m_hourCycle = resolved.get("hc"_s);
-    m_numberingSystem = resolved.get("nu"_s);
-    CString dataLocaleWithExtensions = makeString(resolved.get("dataLocale"_s), "-u-ca-", m_calendar, "-nu-", m_numberingSystem).utf8();
+    m_hourCycle = resolved.extensions[static_cast<unsigned>(RelevantExtensionKey::Hc)];
+    m_numberingSystem = resolved.extensions[static_cast<unsigned>(RelevantExtensionKey::Nu)];
+    CString dataLocaleWithExtensions = makeString(resolved.dataLocale, "-u-ca-", m_calendar, "-nu-", m_numberingSystem).utf8();
 
     JSValue tzValue = options->get(globalObject, vm.propertyNames->timeZone);
     RETURN_IF_EXCEPTION(scope, void());

Modified: trunk/Source/_javascript_Core/runtime/IntlDateTimeFormat.h (264536 => 264537)


--- trunk/Source/_javascript_Core/runtime/IntlDateTimeFormat.h	2020-07-17 22:01:45 UTC (rev 264536)
+++ trunk/Source/_javascript_Core/runtime/IntlDateTimeFormat.h	2020-07-17 22:05:30 UTC (rev 264537)
@@ -30,6 +30,8 @@
 
 namespace JSC {
 
+enum class RelevantExtensionKey : uint8_t;
+
 class JSBoundFunction;
 
 class IntlDateTimeFormat final : public JSNonFinalObject {
@@ -67,7 +69,7 @@
     void finishCreation(VM&);
     static void visitChildren(JSCell*, SlotVisitor&);
 
-    static Vector<String> localeData(const String&, size_t);
+    static Vector<String> localeData(const String&, RelevantExtensionKey);
 
     enum class Weekday : uint8_t { None, Narrow, Short, Long };
     enum class Era : uint8_t { None, Narrow, Short, Long };

Modified: trunk/Source/_javascript_Core/runtime/IntlNumberFormat.cpp (264536 => 264537)


--- trunk/Source/_javascript_Core/runtime/IntlNumberFormat.cpp	2020-07-17 22:01:45 UTC (rev 264536)
+++ trunk/Source/_javascript_Core/runtime/IntlNumberFormat.cpp	2020-07-17 22:05:30 UTC (rev 264537)
@@ -41,7 +41,6 @@
 const ClassInfo IntlNumberFormat::s_info = { "Object", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(IntlNumberFormat) };
 
 namespace IntlNumberFormatInternal {
-constexpr const char* relevantExtensionKeys[1] = { "nu" };
 constexpr bool verbose = false;
 }
 
@@ -89,10 +88,10 @@
     visitor.append(thisObject->m_boundFormat);
 }
 
-Vector<String> IntlNumberFormat::localeData(const String& locale, size_t keyIndex)
+Vector<String> IntlNumberFormat::localeData(const String& locale, RelevantExtensionKey key)
 {
     // 9.1 Internal slots of Service Constructors & 11.2.3 Internal slots (ECMA-402 2.0)
-    ASSERT_UNUSED(keyIndex, !keyIndex); // The index of the extension key "nu" in relevantExtensionKeys is 0.
+    ASSERT_UNUSED(key, key == RelevantExtensionKey::Nu);
     return numberingSystemsForLocale(locale);
 }
 
@@ -171,7 +170,7 @@
         RETURN_IF_EXCEPTION(scope, void());
     }
 
-    HashMap<String, String> opt;
+    ResolveLocaleOptions localeOptions;
 
     LocaleMatcher localeMatcher = intlOption<LocaleMatcher>(globalObject, options, vm.propertyNames->localeMatcher, { { "lookup"_s, LocaleMatcher::Lookup }, { "best fit"_s, LocaleMatcher::BestFit } }, "localeMatcher must be either \"lookup\" or \"best fit\""_s, LocaleMatcher::BestFit);
     RETURN_IF_EXCEPTION(scope, void());
@@ -183,19 +182,19 @@
             throwRangeError(globalObject, scope, "numberingSystem is not a well-formed numbering system value"_s);
             return;
         }
-        opt.add("nu"_s, numberingSystem);
+        localeOptions[static_cast<unsigned>(RelevantExtensionKey::Nu)] = numberingSystem;
     }
 
     auto& availableLocales = intlNumberFormatAvailableLocales();
-    auto result = resolveLocale(globalObject, availableLocales, requestedLocales, localeMatcher, opt, IntlNumberFormatInternal::relevantExtensionKeys, WTF_ARRAY_LENGTH(IntlNumberFormatInternal::relevantExtensionKeys), localeData);
+    auto resolved = resolveLocale(globalObject, availableLocales, requestedLocales, localeMatcher, localeOptions, { RelevantExtensionKey::Nu }, localeData);
 
-    m_locale = result.get("locale"_s);
+    m_locale = resolved.locale;
     if (m_locale.isEmpty()) {
         throwTypeError(globalObject, scope, "failed to initialize NumberFormat due to invalid locale"_s);
         return;
     }
 
-    m_numberingSystem = result.get("nu"_s);
+    m_numberingSystem = resolved.extensions[static_cast<unsigned>(RelevantExtensionKey::Nu)];
 
     m_style = intlOption<Style>(globalObject, options, vm.propertyNames->style, { { "decimal"_s, Style::Decimal }, { "percent"_s, Style::Percent }, { "currency"_s, Style::Currency } }, "style must be either \"decimal\", \"percent\", or \"currency\""_s, Style::Decimal);
     RETURN_IF_EXCEPTION(scope, void());
@@ -292,7 +291,7 @@
         ASSERT_NOT_REACHED();
     }
 
-    CString dataLocaleWithExtensions = makeString(result.get("dataLocale"_s), "-u-nu-", m_numberingSystem).utf8();
+    CString dataLocaleWithExtensions = makeString(resolved.dataLocale, "-u-nu-", m_numberingSystem).utf8();
     dataLogLnIf(IntlNumberFormatInternal::verbose, "dataLocaleWithExtensions:(", dataLocaleWithExtensions , ")");
 
     UErrorCode status = U_ZERO_ERROR;

Modified: trunk/Source/_javascript_Core/runtime/IntlNumberFormat.h (264536 => 264537)


--- trunk/Source/_javascript_Core/runtime/IntlNumberFormat.h	2020-07-17 22:01:45 UTC (rev 264536)
+++ trunk/Source/_javascript_Core/runtime/IntlNumberFormat.h	2020-07-17 22:05:30 UTC (rev 264537)
@@ -32,6 +32,7 @@
 namespace JSC {
 
 class JSBoundFunction;
+enum class RelevantExtensionKey : uint8_t;
 
 class IntlNumberFormat final : public JSNonFinalObject {
 public:
@@ -71,7 +72,7 @@
     void finishCreation(VM&);
     static void visitChildren(JSCell*, SlotVisitor&);
 
-    static Vector<String> localeData(const String&, size_t);
+    static Vector<String> localeData(const String&, RelevantExtensionKey);
 
     enum class Style : uint8_t { Decimal, Percent, Currency };
     enum class CurrencyDisplay : uint8_t { Code, Symbol, Name };

Modified: trunk/Source/_javascript_Core/runtime/IntlObject.cpp (264536 => 264537)


--- trunk/Source/_javascript_Core/runtime/IntlObject.cpp	2020-07-17 22:01:45 UTC (rev 264536)
+++ trunk/Source/_javascript_Core/runtime/IntlObject.cpp	2020-07-17 22:05:30 UTC (rev 264537)
@@ -629,8 +629,21 @@
     subtags.append(extension.substring(valueStart, extensionLength - valueStart));
 }
 
-HashMap<String, String> resolveLocale(JSGlobalObject* globalObject, const HashSet<String>& availableLocales, const Vector<String>& requestedLocales, LocaleMatcher localeMatcher, const HashMap<String, String>& options, const char* const relevantExtensionKeys[], size_t relevantExtensionKeyCount, Vector<String> (*localeData)(const String&, size_t))
+constexpr ASCIILiteral relevantExtensionKeyString(RelevantExtensionKey key)
 {
+    switch (key) {
+#define JSC_RETURN_INTL_RELEVANT_EXTENSION_KEYS(lowerName, capitalizedName) \
+    case RelevantExtensionKey::capitalizedName: \
+        return #lowerName ""_s;
+    JSC_INTL_RELEVANT_EXTENSION_KEYS(JSC_RETURN_INTL_RELEVANT_EXTENSION_KEYS)
+#undef JSC_RETURN_INTL_RELEVANT_EXTENSION_KEYS
+    }
+    ASSERT_UNDER_CONSTEXPR_CONTEXT(0);
+    return ASCIILiteral::null();
+}
+
+ResolvedLocale resolveLocale(JSGlobalObject* globalObject, const HashSet<String>& availableLocales, const Vector<String>& requestedLocales, LocaleMatcher localeMatcher, const ResolveLocaleOptions& options, std::initializer_list<RelevantExtensionKey> relevantExtensionKeys, Vector<String> (*localeData)(const String&, RelevantExtensionKey))
+{
     // ResolveLocale (availableLocales, requestedLocales, options, relevantExtensionKeys, localeData)
     // https://tc39.github.io/ecma402/#sec-resolvelocale
 
@@ -644,13 +657,13 @@
     if (!matcherResult.extension.isNull())
         unicodeExtensionSubTags(matcherResult.extension, extensionSubtags);
 
-    HashMap<String, String> result;
-    result.add("dataLocale"_s, foundLocale);
+    ResolvedLocale resolved;
+    resolved.dataLocale = foundLocale;
 
     String supportedExtension = "-u"_s;
-    for (size_t keyIndex = 0; keyIndex < relevantExtensionKeyCount; ++keyIndex) {
-        const char* key = relevantExtensionKeys[keyIndex];
-        Vector<String> keyLocaleData = localeData(foundLocale, keyIndex);
+    for (RelevantExtensionKey key : relevantExtensionKeys) {
+        ASCIILiteral keyString = relevantExtensionKeyString(key);
+        Vector<String> keyLocaleData = localeData(foundLocale, key);
         ASSERT(!keyLocaleData.isEmpty());
 
         String value = keyLocaleData[0];
@@ -657,43 +670,40 @@
         String supportedExtensionAddition;
 
         if (!extensionSubtags.isEmpty()) {
-            size_t keyPos = extensionSubtags.find(key);
+            size_t keyPos = extensionSubtags.find(keyString);
             if (keyPos != notFound) {
                 if (keyPos + 1 < extensionSubtags.size() && extensionSubtags[keyPos + 1].length() > 2) {
                     const String& requestedValue = extensionSubtags[keyPos + 1];
                     if (keyLocaleData.contains(requestedValue)) {
                         value = requestedValue;
-                        supportedExtensionAddition = makeString('-', key, '-', value);
+                        supportedExtensionAddition = makeString('-', keyString, '-', value);
                     }
                 } else if (keyLocaleData.contains("true"_s)) {
                     value = "true"_s;
-                    supportedExtensionAddition = makeString('-', key);
+                    supportedExtensionAddition = makeString('-', keyString);
                 }
             }
         }
 
-        HashMap<String, String>::const_iterator iterator = options.find(key);
-        if (iterator != options.end()) {
-            const String& optionsValue = iterator->value;
+        if (auto optionsValue = options[static_cast<unsigned>(key)]) {
             // Undefined should not get added to the options, it won't displace the extension.
             // Null will remove the extension.
-            if ((optionsValue.isNull() || keyLocaleData.contains(optionsValue)) && optionsValue != value) {
-                value = optionsValue;
+            if ((optionsValue->isNull() || keyLocaleData.contains(*optionsValue)) && *optionsValue != value) {
+                value = optionsValue.value();
                 supportedExtensionAddition = String();
             }
         }
-        result.add(key, value);
+        resolved.extensions[static_cast<unsigned>(key)] = value;
         supportedExtension.append(supportedExtensionAddition);
     }
 
     if (supportedExtension.length() > 2) {
-        String preExtension = foundLocale.substring(0, matcherResult.extensionIndex);
-        String postExtension = foundLocale.substring(matcherResult.extensionIndex);
-        foundLocale = preExtension + supportedExtension + postExtension;
+        StringView foundLocaleView(foundLocale);
+        foundLocale = makeString(foundLocaleView.substring(0, matcherResult.extensionIndex), supportedExtension, foundLocaleView.substring(matcherResult.extensionIndex));
     }
 
-    result.add("locale"_s, foundLocale);
-    return result;
+    resolved.locale = WTFMove(foundLocale);
+    return resolved;
 }
 
 static JSArray* lookupSupportedLocales(JSGlobalObject* globalObject, const HashSet<String>& availableLocales, const Vector<String>& requestedLocales)

Modified: trunk/Source/_javascript_Core/runtime/IntlObject.h (264536 => 264537)


--- trunk/Source/_javascript_Core/runtime/IntlObject.h	2020-07-17 22:01:45 UTC (rev 264536)
+++ trunk/Source/_javascript_Core/runtime/IntlObject.h	2020-07-17 22:05:30 UTC (rev 264537)
@@ -39,6 +39,23 @@
     BestFit,
 };
 
+#define JSC_INTL_RELEVANT_EXTENSION_KEYS(macro) \
+    macro(ca, Ca) /* calendar */ \
+    macro(co, Co) /* collation */ \
+    macro(hc, Hc) /* hour-cycle */ \
+    macro(kf, Kf) /* case-first */ \
+    macro(kn, Kn) /* numeric */ \
+    macro(nu, Nu) /* numbering-system */ \
+
+enum class RelevantExtensionKey : uint8_t {
+#define JSC_DECLARE_INTL_RELEVANT_EXTENSION_KEYS(lowerName, capitalizedName) capitalizedName,
+JSC_INTL_RELEVANT_EXTENSION_KEYS(JSC_DECLARE_INTL_RELEVANT_EXTENSION_KEYS)
+#undef JSC_DECLARE_INTL_RELEVANT_EXTENSION_KEYS
+};
+#define JSC_COUNT_INTL_RELEVANT_EXTENSION_KEYS(lowerName, capitalizedName) + 1
+static constexpr uint8_t numberOfRelevantExtensionKeys = 0 JSC_INTL_RELEVANT_EXTENSION_KEYS(JSC_COUNT_INTL_RELEVANT_EXTENSION_KEYS);
+#undef JSC_COUNT_INTL_RELEVANT_EXTENSION_KEYS
+
 class IntlObject final : public JSNonFinalObject {
 public:
     using Base = JSNonFinalObject;
@@ -76,7 +93,16 @@
 Vector<char, 32> localeIDBufferForLanguageTag(const CString&);
 String languageTagForLocaleID(const char*, bool isImmortal = false);
 Vector<String> canonicalizeLocaleList(JSGlobalObject*, JSValue locales);
-HashMap<String, String> resolveLocale(JSGlobalObject*, const HashSet<String>& availableLocales, const Vector<String>& requestedLocales, LocaleMatcher, const HashMap<String, String>& options, const char* const relevantExtensionKeys[], size_t relevantExtensionKeyCount, Vector<String> (*localeData)(const String&, size_t));
+
+using ResolveLocaleOptions = std::array<Optional<String>, numberOfRelevantExtensionKeys>;
+using RelevantExtensions = std::array<String, numberOfRelevantExtensionKeys>;
+struct ResolvedLocale {
+    String locale;
+    String dataLocale;
+    RelevantExtensions extensions;
+};
+
+ResolvedLocale resolveLocale(JSGlobalObject*, const HashSet<String>& availableLocales, const Vector<String>& requestedLocales, LocaleMatcher, const ResolveLocaleOptions&, std::initializer_list<RelevantExtensionKey> relevantExtensionKeys, Vector<String> (*localeData)(const String&, RelevantExtensionKey));
 JSValue supportedLocales(JSGlobalObject*, const HashSet<String>& availableLocales, const Vector<String>& requestedLocales, JSValue options);
 String removeUnicodeLocaleExtension(const String& locale);
 String bestAvailableLocale(const HashSet<String>& availableLocales, const String& requestedLocale);

Modified: trunk/Source/_javascript_Core/runtime/IntlPluralRules.cpp (264536 => 264537)


--- trunk/Source/_javascript_Core/runtime/IntlPluralRules.cpp	2020-07-17 22:01:45 UTC (rev 264536)
+++ trunk/Source/_javascript_Core/runtime/IntlPluralRules.cpp	2020-07-17 22:05:30 UTC (rev 264537)
@@ -86,7 +86,7 @@
     Base::visitChildren(thisObject, visitor);
 }
 
-Vector<String> IntlPluralRules::localeData(const String&, size_t)
+Vector<String> IntlPluralRules::localeData(const String&, RelevantExtensionKey)
 {
     return { };
 }
@@ -108,13 +108,13 @@
         RETURN_IF_EXCEPTION(scope, void());
     }
 
-    HashMap<String, String> localeOpt;
+    ResolveLocaleOptions localeOptions;
     LocaleMatcher localeMatcher = intlOption<LocaleMatcher>(globalObject, options, vm.propertyNames->localeMatcher, { { "lookup"_s, LocaleMatcher::Lookup }, { "best fit"_s, LocaleMatcher::BestFit } }, "localeMatcher must be either \"lookup\" or \"best fit\""_s, LocaleMatcher::BestFit);
     RETURN_IF_EXCEPTION(scope, void());
 
     const HashSet<String>& availableLocales = intlPluralRulesAvailableLocales();
-    HashMap<String, String> resolved = resolveLocale(globalObject, availableLocales, requestedLocales, localeMatcher, localeOpt, nullptr, 0, localeData);
-    m_locale = resolved.get(vm.propertyNames->locale.string());
+    auto resolved = resolveLocale(globalObject, availableLocales, requestedLocales, localeMatcher, localeOptions, { }, localeData);
+    m_locale = resolved.locale;
     if (m_locale.isEmpty()) {
         throwTypeError(globalObject, scope, "failed to initialize PluralRules due to invalid locale"_s);
         return;

Modified: trunk/Source/_javascript_Core/runtime/IntlPluralRules.h (264536 => 264537)


--- trunk/Source/_javascript_Core/runtime/IntlPluralRules.h	2020-07-17 22:01:45 UTC (rev 264536)
+++ trunk/Source/_javascript_Core/runtime/IntlPluralRules.h	2020-07-17 22:05:30 UTC (rev 264537)
@@ -31,6 +31,8 @@
 
 namespace JSC {
 
+enum class RelevantExtensionKey : uint8_t;
+
 class IntlPluralRules final : public JSNonFinalObject {
 public:
     using Base = JSNonFinalObject;
@@ -62,7 +64,7 @@
     void finishCreation(VM&);
     static void visitChildren(JSCell*, SlotVisitor&);
 
-    static Vector<String> localeData(const String&, size_t);
+    static Vector<String> localeData(const String&, RelevantExtensionKey);
 
     enum class Type : bool { Cardinal, Ordinal };
 

Modified: trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormat.cpp (264536 => 264537)


--- trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormat.cpp	2020-07-17 22:01:45 UTC (rev 264536)
+++ trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormat.cpp	2020-07-17 22:05:30 UTC (rev 264537)
@@ -37,7 +37,6 @@
 const ClassInfo IntlRelativeTimeFormat::s_info = { "Object", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(IntlRelativeTimeFormat) };
 
 namespace IntlRelativeTimeFormatInternal {
-constexpr const char* relevantExtensionKeys[1] = { "nu" };
 }
 
 void IntlRelativeTimeFormat::URelativeDateTimeFormatterDeleter::operator()(URelativeDateTimeFormatter* relativeDateTimeFormatter) const
@@ -83,10 +82,9 @@
     Base::visitChildren(thisObject, visitor);
 }
 
-Vector<String> IntlRelativeTimeFormat::localeData(const String& locale, size_t keyIndex)
+Vector<String> IntlRelativeTimeFormat::localeData(const String& locale, RelevantExtensionKey key)
 {
-    // The index of the extension key "nu" in relevantExtensionKeys is 0.
-    ASSERT_UNUSED(keyIndex, !keyIndex);
+    ASSERT_UNUSED(key, key == RelevantExtensionKey::Nu);
     return numberingSystemsForLocale(locale);
 }
 
@@ -107,7 +105,7 @@
         RETURN_IF_EXCEPTION(scope, void());
     }
 
-    HashMap<String, String> opt;
+    ResolveLocaleOptions localeOptions;
     LocaleMatcher localeMatcher = intlOption<LocaleMatcher>(globalObject, options, vm.propertyNames->localeMatcher, { { "lookup"_s, LocaleMatcher::Lookup }, { "best fit"_s, LocaleMatcher::BestFit } }, "localeMatcher must be either \"lookup\" or \"best fit\""_s, LocaleMatcher::BestFit);
     RETURN_IF_EXCEPTION(scope, void());
 
@@ -118,19 +116,19 @@
             throwRangeError(globalObject, scope, "numberingSystem is not a well-formed numbering system value"_s);
             return;
         }
-        opt.add("nu"_s, numberingSystem);
+        localeOptions[static_cast<unsigned>(RelevantExtensionKey::Nu)] = numberingSystem;
     }
 
     const HashSet<String>& availableLocales = intlRelativeTimeFormatAvailableLocales();
-    HashMap<String, String> resolved = resolveLocale(globalObject, availableLocales, requestedLocales, localeMatcher, opt, IntlRelativeTimeFormatInternal::relevantExtensionKeys, WTF_ARRAY_LENGTH(IntlRelativeTimeFormatInternal::relevantExtensionKeys), localeData);
-    m_locale = resolved.get(vm.propertyNames->locale.string());
+    auto resolved = resolveLocale(globalObject, availableLocales, requestedLocales, localeMatcher, localeOptions, { RelevantExtensionKey::Nu }, localeData);
+    m_locale = resolved.locale;
     if (m_locale.isEmpty()) {
         throwTypeError(globalObject, scope, "failed to initialize RelativeTimeFormat due to invalid locale"_s);
         return;
     }
 
-    m_numberingSystem = resolved.get("nu"_s);
-    CString dataLocaleWithExtensions = makeString(resolved.get("dataLocale"_s), "-u-nu-", m_numberingSystem).utf8();
+    m_numberingSystem = resolved.extensions[static_cast<unsigned>(RelevantExtensionKey::Nu)];
+    CString dataLocaleWithExtensions = makeString(resolved.dataLocale, "-u-nu-", m_numberingSystem).utf8();
 
     m_style = intlOption<Style>(globalObject, options, vm.propertyNames->style, { { "long"_s, Style::Long }, { "short"_s, Style::Short }, { "narrow"_s, Style::Narrow } }, "style must be either \"long\", \"short\", or \"narrow\""_s, Style::Long);
     RETURN_IF_EXCEPTION(scope, void());

Modified: trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormat.h (264536 => 264537)


--- trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormat.h	2020-07-17 22:01:45 UTC (rev 264536)
+++ trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormat.h	2020-07-17 22:05:30 UTC (rev 264537)
@@ -62,7 +62,7 @@
     void finishCreation(VM&);
     static void visitChildren(JSCell*, SlotVisitor&);
 
-    static Vector<String> localeData(const String&, size_t);
+    static Vector<String> localeData(const String&, RelevantExtensionKey);
 
     String formatInternal(JSGlobalObject*, double, StringView unit) const;
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to