From eee13d26532623b69d434b4ca1038bb6bc13c3b3 Mon Sep 17 00:00:00 2001 From: Martok Date: Mon, 13 Feb 2023 00:23:46 +0100 Subject: [PATCH] Issue #2046 - Create helper method to call ICU string conversion methods Based-on: m-c 1333844 --- js/src/builtin/Intl.cpp | 211 +++++--------------------- js/src/builtin/intl/CommonFunctions.h | 40 +++++ 2 files changed, 78 insertions(+), 173 deletions(-) diff --git a/js/src/builtin/Intl.cpp b/js/src/builtin/Intl.cpp index 28533129ed..688b7698a8 100644 --- a/js/src/builtin/Intl.cpp +++ b/js/src/builtin/Intl.cpp @@ -57,6 +57,7 @@ using mozilla::IsNaN; using mozilla::IsNegativeZero; using mozilla::PodCopy; +using js::intl::CallICU; using js::intl::GetAvailableLocales; using js::intl::IcuLocale; using js::intl::INITIAL_CHAR_BUFFER_SIZE; @@ -1050,33 +1051,9 @@ PartitionNumberPattern(JSContext* cx, UNumberFormat* nf, double* x, if (IsNegativeZero(*x)) *x = 0.0; - MOZ_ASSERT(formattedChars.length() == 0, - "formattedChars must initially be empty"); - MOZ_ALWAYS_TRUE(formattedChars.resize(INITIAL_CHAR_BUFFER_SIZE)); - UErrorCode status = U_ZERO_ERROR; - - int32_t resultSize; - resultSize = - unum_formatDoubleForFields(nf, *x, - Char16ToUChar(formattedChars.begin()), INITIAL_CHAR_BUFFER_SIZE, - fpositer, &status); - if (status == U_BUFFER_OVERFLOW_ERROR) { - if (!formattedChars.resize(size_t(resultSize))) - return false; - status = U_ZERO_ERROR; -#ifdef DEBUG - int32_t size = -#endif - unum_formatDoubleForFields(nf, *x, Char16ToUChar(formattedChars.begin()), resultSize, - fpositer, &status); - MOZ_ASSERT(size == resultSize); - } - if (U_FAILURE(status)) { - intl::ReportInternalError(cx); - return false; - } - - return formattedChars.resize(size_t(resultSize)); + return CallICU(cx, formattedChars, [nf, x, fpositer](UChar* chars, int32_t size, UErrorCode* status) { + return unum_formatDoubleForFields(nf, *x, chars, size, fpositer, status); + }) >= 0; } static bool @@ -2182,30 +2159,10 @@ js::intl_canonicalizeTimeZone(JSContext* cx, unsigned argc, Value* vp) mozilla::Range tzchars = stableChars.twoByteRange(); - Vector chars(cx); - if (!chars.resize(INITIAL_CHAR_BUFFER_SIZE)) - return false; - - UBool* isSystemID = nullptr; - UErrorCode status = U_ZERO_ERROR; - int32_t size = ucal_getCanonicalTimeZoneID(Char16ToUChar(tzchars.begin().get()), - tzchars.length(), Char16ToUChar(chars.begin()), - INITIAL_CHAR_BUFFER_SIZE, isSystemID, &status); - if (status == U_BUFFER_OVERFLOW_ERROR) { - MOZ_ASSERT(size >= 0); - if (!chars.resize(size_t(size))) - return false; - status = U_ZERO_ERROR; - ucal_getCanonicalTimeZoneID(Char16ToUChar(tzchars.begin().get()), tzchars.length(), - Char16ToUChar(chars.begin()), size, isSystemID, &status); - } - if (U_FAILURE(status)) { - intl::ReportInternalError(cx); - return false; - } - - MOZ_ASSERT(size >= 0); - JSString* str = NewStringCopyN(cx, chars.begin(), size_t(size)); + JSString* str = CallICU(cx, [&tzchars](UChar* chars, uint32_t size, UErrorCode* status) { + return ucal_getCanonicalTimeZoneID(tzchars.begin().get(), tzchars.length(), + chars, size, nullptr, status); + }); if (!str) return false; args.rval().setString(str); @@ -2223,27 +2180,7 @@ js::intl_defaultTimeZone(JSContext* cx, unsigned argc, Value* vp) // needed. js::ResyncICUDefaultTimeZone(); - Vector chars(cx); - if (!chars.resize(INITIAL_CHAR_BUFFER_SIZE)) - return false; - - UErrorCode status = U_ZERO_ERROR; - int32_t size = ucal_getDefaultTimeZone(Char16ToUChar(chars.begin()), INITIAL_CHAR_BUFFER_SIZE, - &status); - if (status == U_BUFFER_OVERFLOW_ERROR) { - MOZ_ASSERT(size >= 0); - if (!chars.resize(size_t(size))) - return false; - status = U_ZERO_ERROR; - ucal_getDefaultTimeZone(Char16ToUChar(chars.begin()), size, &status); - } - if (U_FAILURE(status)) { - intl::ReportInternalError(cx); - return false; - } - - MOZ_ASSERT(size >= 0); - JSString* str = NewStringCopyN(cx, chars.begin(), size_t(size)); + JSString* str = CallICU(cx, ucal_getDefaultTimeZone); if (!str) return false; args.rval().setString(str); @@ -2307,25 +2244,11 @@ js::intl_patternForSkeleton(JSContext* cx, unsigned argc, Value* vp) } ScopedICUObject toClose(gen); - int32_t size = udatpg_getBestPattern(gen, Char16ToUChar(skeletonChars.begin().get()), - skeletonLen, nullptr, 0, &status); - if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR) { - intl::ReportInternalError(cx); - return false; - } - ScopedJSFreePtr pattern(cx->pod_malloc(size + 1)); - if (!pattern) - return false; - pattern[size] = '\0'; - status = U_ZERO_ERROR; - udatpg_getBestPattern(gen, Char16ToUChar(skeletonChars.begin().get()), - skeletonLen, pattern, size, &status); - if (U_FAILURE(status)) { - intl::ReportInternalError(cx); - return false; - } - - RootedString str(cx, JS_NewUCStringCopyZ(cx, reinterpret_cast(pattern.get()))); + JSString* str = + CallICU(cx, [gen, &skeletonChars, skeletonLen](UChar* chars, uint32_t size, UErrorCode* status) { + return udatpg_getBestPattern(gen, skeletonChars.begin().get(), skeletonLen, + chars, size, status); + }); if (!str) return false; args.rval().setString(str); @@ -2404,29 +2327,13 @@ intl_FormatDateTime(JSContext* cx, UDateFormat* df, double x, MutableHandleValue return false; } - Vector chars(cx); - if (!chars.resize(INITIAL_CHAR_BUFFER_SIZE)) - return false; - UErrorCode status = U_ZERO_ERROR; - int size = udat_format(df, x, Char16ToUChar(chars.begin()), INITIAL_CHAR_BUFFER_SIZE, - nullptr, &status); - if (status == U_BUFFER_OVERFLOW_ERROR) { - if (!chars.resize(size)) - return false; - status = U_ZERO_ERROR; - udat_format(df, x, Char16ToUChar(chars.begin()), size, nullptr, &status); - } - if (U_FAILURE(status)) { - intl::ReportInternalError(cx); - return false; - } - - JSString* str = NewStringCopyN(cx, chars.begin(), size); + JSString* str = CallICU(cx, [df, x](UChar* chars, int32_t size, UErrorCode* status) { + return udat_format(df, x, chars, size, nullptr, status); + }); if (!str) return false; result.setString(str); - return true; } @@ -2536,33 +2443,22 @@ intl_FormatToPartsDateTime(JSContext* cx, UDateFormat* df, double x, MutableHand } ScopedICUObject toClose(fpositer); - int resultSize = - udat_formatForFields(df, x, Char16ToUChar(chars.begin()), INITIAL_CHAR_BUFFER_SIZE, - fpositer, &status); - if (status == U_BUFFER_OVERFLOW_ERROR) { - if (!chars.resize(resultSize)) - return false; - status = U_ZERO_ERROR; - udat_formatForFields(df, x, Char16ToUChar(chars.begin()), resultSize, fpositer, &status); - } - if (U_FAILURE(status)) { - intl::ReportInternalError(cx); + RootedString overallResult(cx); + overallResult = CallICU(cx, [df, x, fpositer](UChar* chars, int32_t size, UErrorCode* status) { + return udat_formatForFields(df, x, chars, size, fpositer, status); + }); + if (!overallResult) return false; - } RootedArrayObject partsArray(cx, NewDenseEmptyArray(cx)); if (!partsArray) return false; - if (resultSize == 0) { + if (overallResult->length() == 0) { // An empty string contains no parts, so avoid extra work below. result.setObject(*partsArray); return true; } - RootedString overallResult(cx, NewStringCopyN(cx, chars.begin(), resultSize)); - if (!overallResult) - return false; - size_t lastEndIndex = 0; uint32_t partIndex = 0; @@ -2950,23 +2846,9 @@ js::intl_SelectPluralRule(JSContext* cx, unsigned argc, Value* vp) ScopedICUObject closePluralRules(pr); - Vector chars(cx); - if (!chars.resize(INITIAL_CHAR_BUFFER_SIZE)) - return false; - - int size = uplrules_select(pr, y, Char16ToUChar(chars.begin()), INITIAL_CHAR_BUFFER_SIZE, &status); - if (status == U_BUFFER_OVERFLOW_ERROR) { - if (!chars.resize(size)) - return false; - status = U_ZERO_ERROR; - uplrules_select(pr, y, Char16ToUChar(chars.begin()), size, &status); - } - if (U_FAILURE(status)) { - intl::ReportInternalError(cx); - return false; - } - - JSString* str = NewStringCopyN(cx, chars.begin(), size); + JSString* str = CallICU(cx, [pr, y](UChar* chars, int32_t size, UErrorCode* status) { + return uplrules_select(pr, y, chars, size, status); + }); if (!str) return false; @@ -3333,21 +3215,17 @@ js::intl_FormatRelativeTime(JSContext* cx, unsigned argc, Value* vp) intl::ReportInternalError(cx); return false; } - - int32_t size; - - if (relDateTimeNumeric == RelativeTimeNumeric::Auto) { - size = ureldatefmt_format(rtf, t, relDateTimeUnit, Char16ToUChar(chars.begin()), - INITIAL_CHAR_BUFFER_SIZE, &status); - } else { - MOZ_ASSERT(relDateTimeNumeric == RelativeTimeNumeric::Always); - size = ureldatefmt_formatNumeric(rtf, t, relDateTimeUnit, Char16ToUChar(chars.begin()), - INITIAL_CHAR_BUFFER_SIZE, &status); - } - ScopedICUObject closeRelativeTimeFormat(rtf); - JSString* str = NewStringCopyN(cx, chars.begin(), size); + JSString* str = + CallICU(cx, [rtf, t, relDateTimeUnit, relDateTimeNumeric](UChar* chars, int32_t size, + UErrorCode* status) + { + auto fmt = relDateTimeNumeric == RelativeTimeNumeric::Auto + ? ureldatefmt_format + : ureldatefmt_formatNumeric; + return fmt(rtf, t, relDateTimeUnit, chars, size, status); + }); if (!str) return false; @@ -3699,22 +3577,9 @@ js::intl_ComputeDisplayNames(JSContext* cx, unsigned argc, Value* vp) return false; } - int32_t resultSize = - udat_getSymbols(fmt, symbolType, index, Char16ToUChar(chars.begin()), - INITIAL_CHAR_BUFFER_SIZE, &status); - if (status == U_BUFFER_OVERFLOW_ERROR) { - if (!chars.resize(resultSize)) - return false; - status = U_ZERO_ERROR; - udat_getSymbols(fmt, symbolType, index, Char16ToUChar(chars.begin()), - resultSize, &status); - } - if (U_FAILURE(status)) { - intl::ReportInternalError(cx); - return false; - } - - JSString* word = NewStringCopyN(cx, chars.begin(), resultSize); + JSString* word = CallICU(cx, [fmt, symbolType, index](UChar* chars, int32_t size, UErrorCode* status) { + return udat_getSymbols(fmt, symbolType, index, chars, size, status); + }); if (!word) return false; diff --git a/js/src/builtin/intl/CommonFunctions.h b/js/src/builtin/intl/CommonFunctions.h index e8bbb69077..90d3a5636b 100644 --- a/js/src/builtin/intl/CommonFunctions.h +++ b/js/src/builtin/intl/CommonFunctions.h @@ -79,6 +79,46 @@ static_assert(mozilla::IsSame::value, // buffer's entire inline capacity before growing it and heap-allocating. static const size_t INITIAL_CHAR_BUFFER_SIZE = 32; +template +static int32_t +CallICU(JSContext* cx, Vector& chars, const ICUStringFunction& strFn) +{ + MOZ_ASSERT(chars.length() == 0); + MOZ_ALWAYS_TRUE(chars.resize(InlineCapacity)); + + UErrorCode status = U_ZERO_ERROR; + int32_t size = strFn(chars.begin(), InlineCapacity, &status); + if (status == U_BUFFER_OVERFLOW_ERROR) { + MOZ_ASSERT(size >= 0); + if (!chars.resize(size_t(size))) + return -1; + status = U_ZERO_ERROR; + strFn(chars.begin(), size, &status); + } + if (U_FAILURE(status)) { + ReportInternalError(cx); + return -1; + } + + MOZ_ASSERT(size >= 0); + if (!chars.resize(size_t(size))) + return -1; + return size; +} + +template +static JSString* +CallICU(JSContext* cx, const ICUStringFunction& strFn) +{ + Vector chars(cx); + + int32_t size = CallICU(cx, chars, strFn); + if (size < 0) + return nullptr; + + return NewStringCopyN(cx, chars.begin(), size_t(size)); +} + // CountAvailable and GetAvailable describe the signatures used for ICU API // to determine available locales for various functionality. using CountAvailable = int32_t (*)();