diff options
Diffstat (limited to 'deps/v8/src/objects/js-number-format.cc')
-rw-r--r-- | deps/v8/src/objects/js-number-format.cc | 129 |
1 files changed, 90 insertions, 39 deletions
diff --git a/deps/v8/src/objects/js-number-format.cc b/deps/v8/src/objects/js-number-format.cc index 646cbed8e7..fda9a940d6 100644 --- a/deps/v8/src/objects/js-number-format.cc +++ b/deps/v8/src/objects/js-number-format.cc @@ -109,19 +109,20 @@ Handle<JSObject> JSNumberFormat::ResolvedOptions( // [[MinimumSignificantDigits]] "minimumSignificantDigits" // [[MaximumSignificantDigits]] "maximumSignificantDigits" // [[UseGrouping]] "useGrouping" - CHECK(JSReceiver::CreateDataProperty( - isolate, options, factory->locale_string(), locale, kDontThrow) + CHECK(JSReceiver::CreateDataProperty(isolate, options, + factory->locale_string(), locale, + Just(kDontThrow)) .FromJust()); if (!numbering_system.empty()) { CHECK(JSReceiver::CreateDataProperty( isolate, options, factory->numberingSystem_string(), factory->NewStringFromAsciiChecked(numbering_system.c_str()), - kDontThrow) + Just(kDontThrow)) .FromJust()); } CHECK(JSReceiver::CreateDataProperty( isolate, options, factory->style_string(), - number_format_holder->StyleAsString(), kDontThrow) + number_format_holder->StyleAsString(), Just(kDontThrow)) .FromJust()); if (number_format_holder->style() == Style::CURRENCY) { icu::UnicodeString currency(number_format->getCurrency()); @@ -133,49 +134,49 @@ Handle<JSObject> JSNumberFormat::ResolvedOptions( reinterpret_cast<const uint16_t*>(currency.getBuffer()), currency.length())) .ToHandleChecked(), - kDontThrow) + Just(kDontThrow)) .FromJust()); CHECK(JSReceiver::CreateDataProperty( isolate, options, factory->currencyDisplay_string(), - number_format_holder->CurrencyDisplayAsString(), kDontThrow) + number_format_holder->CurrencyDisplayAsString(), Just(kDontThrow)) .FromJust()); } CHECK(JSReceiver::CreateDataProperty( isolate, options, factory->minimumIntegerDigits_string(), factory->NewNumberFromInt(number_format->getMinimumIntegerDigits()), - kDontThrow) + Just(kDontThrow)) .FromJust()); CHECK( JSReceiver::CreateDataProperty( isolate, options, factory->minimumFractionDigits_string(), factory->NewNumberFromInt(number_format->getMinimumFractionDigits()), - kDontThrow) + Just(kDontThrow)) .FromJust()); CHECK( JSReceiver::CreateDataProperty( isolate, options, factory->maximumFractionDigits_string(), factory->NewNumberFromInt(number_format->getMaximumFractionDigits()), - kDontThrow) + Just(kDontThrow)) .FromJust()); if (decimal_format->areSignificantDigitsUsed()) { CHECK(JSReceiver::CreateDataProperty( isolate, options, factory->minimumSignificantDigits_string(), factory->NewNumberFromInt( decimal_format->getMinimumSignificantDigits()), - kDontThrow) + Just(kDontThrow)) .FromJust()); CHECK(JSReceiver::CreateDataProperty( isolate, options, factory->maximumSignificantDigits_string(), factory->NewNumberFromInt( decimal_format->getMaximumSignificantDigits()), - kDontThrow) + Just(kDontThrow)) .FromJust()); } CHECK(JSReceiver::CreateDataProperty( isolate, options, factory->useGrouping_string(), factory->ToBoolean((number_format->isGroupingUsed() == TRUE)), - kDontThrow) + Just(kDontThrow)) .FromJust()); return options; } @@ -461,10 +462,45 @@ Handle<String> JSNumberFormat::CurrencyDisplayAsString() const { } } -MaybeHandle<String> JSNumberFormat::FormatNumber( - Isolate* isolate, const icu::NumberFormat& number_format, double number) { +namespace { +Maybe<icu::UnicodeString> IcuFormatNumber( + Isolate* isolate, const icu::NumberFormat& number_format, + Handle<Object> numeric_obj, icu::FieldPositionIterator* fp_iter) { icu::UnicodeString result; - number_format.format(number, result); + // If it is BigInt, handle it differently. + UErrorCode status = U_ZERO_ERROR; + if (numeric_obj->IsBigInt()) { + Handle<BigInt> big_int = Handle<BigInt>::cast(numeric_obj); + Handle<String> big_int_string; + ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, big_int_string, + BigInt::ToString(isolate, big_int), + Nothing<icu::UnicodeString>()); + number_format.format( + {big_int_string->ToCString().get(), big_int_string->length()}, result, + fp_iter, status); + } else { + double number = numeric_obj->Number(); + number_format.format(number, result, fp_iter, status); + } + if (U_FAILURE(status)) { + THROW_NEW_ERROR_RETURN_VALUE(isolate, + NewTypeError(MessageTemplate::kIcuError), + Nothing<icu::UnicodeString>()); + } + return Just(result); +} + +} // namespace + +MaybeHandle<String> JSNumberFormat::FormatNumeric( + Isolate* isolate, const icu::NumberFormat& number_format, + Handle<Object> numeric_obj) { + DCHECK(numeric_obj->IsNumeric()); + + Maybe<icu::UnicodeString> maybe_format = + IcuFormatNumber(isolate, number_format, numeric_obj, nullptr); + MAYBE_RETURN(maybe_format, Handle<String>()); + icu::UnicodeString result = maybe_format.FromJust(); return isolate->factory()->NewStringFromTwoByte(Vector<const uint16_t>( reinterpret_cast<const uint16_t*>(result.getBuffer()), result.length())); @@ -490,13 +526,22 @@ bool cmp_NumberFormatSpan(const NumberFormatSpan& a, // The list comes from third_party/icu/source/i18n/unicode/unum.h. // They're mapped to NumberFormat part types mentioned throughout // https://tc39.github.io/ecma402/#sec-partitionnumberpattern . -Handle<String> IcuNumberFieldIdToNumberType(int32_t field_id, double number, +Handle<String> IcuNumberFieldIdToNumberType(int32_t field_id, + Handle<Object> numeric_obj, Isolate* isolate) { + DCHECK(numeric_obj->IsNumeric()); switch (static_cast<UNumberFormatFields>(field_id)) { case UNUM_INTEGER_FIELD: - if (std::isfinite(number)) return isolate->factory()->integer_string(); - if (std::isnan(number)) return isolate->factory()->nan_string(); - return isolate->factory()->infinity_string(); + if (numeric_obj->IsBigInt()) { + // Neither NaN nor Infinite could be stored into BigInt + // so just return integer. + return isolate->factory()->integer_string(); + } else { + double number = numeric_obj->Number(); + if (std::isfinite(number)) return isolate->factory()->integer_string(); + if (std::isnan(number)) return isolate->factory()->nan_string(); + return isolate->factory()->infinity_string(); + } case UNUM_FRACTION_FIELD: return isolate->factory()->fraction_string(); case UNUM_DECIMAL_SEPARATOR_FIELD: @@ -508,9 +553,15 @@ Handle<String> IcuNumberFieldIdToNumberType(int32_t field_id, double number, case UNUM_PERCENT_FIELD: return isolate->factory()->percentSign_string(); case UNUM_SIGN_FIELD: - return number < 0 ? isolate->factory()->minusSign_string() - : isolate->factory()->plusSign_string(); - + if (numeric_obj->IsBigInt()) { + Handle<BigInt> big_int = Handle<BigInt>::cast(numeric_obj); + return big_int->IsNegative() ? isolate->factory()->minusSign_string() + : isolate->factory()->plusSign_string(); + } else { + double number = numeric_obj->Number(); + return number < 0 ? isolate->factory()->minusSign_string() + : isolate->factory()->plusSign_string(); + } case UNUM_EXPONENT_SYMBOL_FIELD: case UNUM_EXPONENT_SIGN_FIELD: case UNUM_EXPONENT_FIELD: @@ -625,16 +676,15 @@ std::vector<NumberFormatSpan> FlattenRegionsToParts( Maybe<int> JSNumberFormat::FormatToParts(Isolate* isolate, Handle<JSArray> result, int start_index, - const icu::NumberFormat& fmt, - double number, Handle<String> unit) { - icu::UnicodeString formatted; + const icu::NumberFormat& number_format, + Handle<Object> numeric_obj, + Handle<String> unit) { + DCHECK(numeric_obj->IsNumeric()); icu::FieldPositionIterator fp_iter; - UErrorCode status = U_ZERO_ERROR; - fmt.format(number, formatted, &fp_iter, status); - if (U_FAILURE(status)) { - THROW_NEW_ERROR_RETURN_VALUE( - isolate, NewTypeError(MessageTemplate::kIcuError), Nothing<int>()); - } + Maybe<icu::UnicodeString> maybe_format = + IcuFormatNumber(isolate, number_format, numeric_obj, &fp_iter); + MAYBE_RETURN(maybe_format, Nothing<int>()); + icu::UnicodeString formatted = maybe_format.FromJust(); int32_t length = formatted.length(); int index = start_index; @@ -662,7 +712,7 @@ Maybe<int> JSNumberFormat::FormatToParts(Isolate* isolate, Handle<String> field_type_string = part.field_id == -1 ? isolate->factory()->literal_string() - : IcuNumberFieldIdToNumberType(part.field_id, number, isolate); + : IcuNumberFieldIdToNumberType(part.field_id, numeric_obj, isolate); Handle<String> substring; ASSIGN_RETURN_ON_EXCEPTION_VALUE( isolate, substring, @@ -681,7 +731,9 @@ Maybe<int> JSNumberFormat::FormatToParts(Isolate* isolate, } MaybeHandle<JSArray> JSNumberFormat::FormatToParts( - Isolate* isolate, Handle<JSNumberFormat> number_format, double number) { + Isolate* isolate, Handle<JSNumberFormat> number_format, + Handle<Object> numeric_obj) { + CHECK(numeric_obj->IsNumeric()); Factory* factory = isolate->factory(); icu::NumberFormat* fmt = number_format->icu_number_format()->raw(); CHECK_NOT_NULL(fmt); @@ -689,17 +741,16 @@ MaybeHandle<JSArray> JSNumberFormat::FormatToParts( Handle<JSArray> result = factory->NewJSArray(0); Maybe<int> maybe_format_to_parts = JSNumberFormat::FormatToParts( - isolate, result, 0, *fmt, number, Handle<String>()); + isolate, result, 0, *fmt, numeric_obj, Handle<String>()); MAYBE_RETURN(maybe_format_to_parts, Handle<JSArray>()); return result; } -std::set<std::string> JSNumberFormat::GetAvailableLocales() { - int32_t num_locales = 0; - const icu::Locale* icu_available_locales = - icu::NumberFormat::getAvailableLocales(num_locales); - return Intl::BuildLocaleSet(icu_available_locales, num_locales); +const std::set<std::string>& JSNumberFormat::GetAvailableLocales() { + static base::LazyInstance<Intl::AvailableLocales<icu::NumberFormat>>::type + available_locales = LAZY_INSTANCE_INITIALIZER; + return available_locales.Pointer()->Get(); } } // namespace internal |