diff --git a/icu4c/source/i18n/number_fluent.cpp b/icu4c/source/i18n/number_fluent.cpp index cc2431cf72c..198c7caee0f 100644 --- a/icu4c/source/i18n/number_fluent.cpp +++ b/icu4c/source/i18n/number_fluent.cpp @@ -706,7 +706,11 @@ bool LocalizedNumberFormatter::computeCompiled(UErrorCode& status) const { if (currentCount == fMacros.threshold && fMacros.threshold > 0) { // Build the data structure and then use it (slow to fast path). - const NumberFormatterImpl* compiled = NumberFormatterImpl::fromMacros(fMacros, status); + const NumberFormatterImpl* compiled = new NumberFormatterImpl(fMacros, status); + if (compiled == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + return false; + } U_ASSERT(fCompiled == nullptr); const_cast(this)->fCompiled = compiled; umtx_storeRelease(*callCount, INT32_MIN); diff --git a/icu4c/source/i18n/number_formatimpl.cpp b/icu4c/source/i18n/number_formatimpl.cpp index 183fe214ecf..d84ba2cfead 100644 --- a/icu4c/source/i18n/number_formatimpl.cpp +++ b/icu4c/source/i18n/number_formatimpl.cpp @@ -67,8 +67,8 @@ getCurrencyFormatInfo(const Locale& locale, const char* isoCode, UErrorCode& sta MicroPropsGenerator::~MicroPropsGenerator() = default; -NumberFormatterImpl* NumberFormatterImpl::fromMacros(const MacroProps& macros, UErrorCode& status) { - return new NumberFormatterImpl(macros, true, status); +NumberFormatterImpl::NumberFormatterImpl(const MacroProps& macros, UErrorCode& status) + : NumberFormatterImpl(macros, true, status) { } void NumberFormatterImpl::formatStatic(const MacroProps& macros, DecimalQuantity& inValue, diff --git a/icu4c/source/i18n/number_formatimpl.h b/icu4c/source/i18n/number_formatimpl.h index e8f0fc3f747..9b89e5b88e6 100644 --- a/icu4c/source/i18n/number_formatimpl.h +++ b/icu4c/source/i18n/number_formatimpl.h @@ -29,7 +29,7 @@ class NumberFormatterImpl : public UMemory { * Builds a "safe" MicroPropsGenerator, which is thread-safe and can be used repeatedly. * The caller owns the returned NumberFormatterImpl. */ - static NumberFormatterImpl *fromMacros(const MacroProps ¯os, UErrorCode &status); + NumberFormatterImpl(const MacroProps ¯os, UErrorCode &status); /** * Builds and evaluates an "unsafe" MicroPropsGenerator, which is cheaper but can be used only once. diff --git a/icu4c/source/i18n/numrange_fluent.cpp b/icu4c/source/i18n/numrange_fluent.cpp index 6a2704e5fdf..0deb352055e 100644 --- a/icu4c/source/i18n/numrange_fluent.cpp +++ b/icu4c/source/i18n/numrange_fluent.cpp @@ -228,7 +228,7 @@ FormattedNumberRange LocalizedNumberRangeFormatter::formatFormattableRange( return FormattedNumberRange(status); } - formatImpl(results, status); + formatImpl(*results, first == second, status); // Do not save the results object if we encountered a failure. if (U_SUCCESS(status)) { @@ -240,35 +240,20 @@ FormattedNumberRange LocalizedNumberRangeFormatter::formatFormattableRange( } void LocalizedNumberRangeFormatter::formatImpl( - UFormattedNumberRangeData* results, UErrorCode& status) const { - - MicroProps microsFirst; - MicroProps microsSecond; - - UFormattedNumberData r1; - r1.quantity = results->quantity1; - fMacros.formatter1.locale(fMacros.locale).formatImpl(&r1, status); - if (U_FAILURE(status)) { - return; + UFormattedNumberRangeData& results, bool equalBeforeRounding, UErrorCode& status) const { + if (fImpl == nullptr) { + // TODO: Fix this once the atomic is ready! + auto* nonConstThis = const_cast(this); + nonConstThis->fImpl = new NumberRangeFormatterImpl(fMacros, status); + if (U_FAILURE(status)) { + return; + } + if (fImpl == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + return; + } } - results->quantity1 = r1.quantity; - - UFormattedNumberData r2; - r2.quantity = results->quantity2; - fMacros.formatter2.locale(fMacros.locale).formatImpl(&r2, status); - if (U_FAILURE(status)) { - return; - } - results->quantity2 = r2.quantity; - - results->string.append(r1.string, status); - results->string.append(u" --- ", UNUM_FIELD_COUNT, status); - results->string.append(r2.string, status); - if (U_FAILURE(status)) { - return; - } - - results->identityResult = UNUM_IDENTITY_RESULT_NOT_EQUAL; + fImpl->format(results, equalBeforeRounding, status); } diff --git a/icu4c/source/i18n/numrange_impl.cpp b/icu4c/source/i18n/numrange_impl.cpp index 42476bed993..f2da9b70438 100644 --- a/icu4c/source/i18n/numrange_impl.cpp +++ b/icu4c/source/i18n/numrange_impl.cpp @@ -9,6 +9,7 @@ // Helpful in toString methods and elsewhere. #define UNISTR_FROM_STRING_EXPLICIT +#include "unicode/numberrangeformatter.h" #include "numrange_impl.h" using namespace icu; @@ -24,6 +25,15 @@ constexpr int8_t identity2d(UNumberIdentityFallback a, UNumberRangeIdentityResul } // namespace + +NumberRangeFormatterImpl::NumberRangeFormatterImpl(const RangeMacroProps& macros, UErrorCode& status) + : formatterImpl1(macros.formatter1.fMacros, status), + formatterImpl2(macros.formatter2.fMacros, status), + fSameFormatters(true), // FIXME + fCollapse(macros.collapse), + fIdentityFallback(macros.identityFallback) { +} + void NumberRangeFormatterImpl::format(UFormattedNumberRangeData& data, bool equalBeforeRounding, UErrorCode& status) const { if (U_FAILURE(status)) { return; @@ -199,7 +209,7 @@ void NumberRangeFormatterImpl::formatRange(UFormattedNumberRangeData& data, // TODO: Use localized pattern lengthShared += string.insert(UPRV_INDEX_0, u" --- ", UNUM_FIELD_COUNT, status); length1 += NumberFormatterImpl::writeNumber(micros1, data.quantity1, string, UPRV_INDEX_0, status); - length2 += NumberFormatterImpl::writeNumber(micros2, data.quantity2, string, UPRV_INDEX_0, status); + length2 += NumberFormatterImpl::writeNumber(micros2, data.quantity2, string, UPRV_INDEX_2, status); // TODO: Support padding? diff --git a/icu4c/source/i18n/numrange_impl.h b/icu4c/source/i18n/numrange_impl.h index d05ea850037..8a478abe29a 100644 --- a/icu4c/source/i18n/numrange_impl.h +++ b/icu4c/source/i18n/numrange_impl.h @@ -45,6 +45,8 @@ struct UFormattedNumberRangeData : public UMemory { class NumberRangeFormatterImpl : public UMemory { public: + NumberRangeFormatterImpl(const RangeMacroProps& macros, UErrorCode& status); + void format(UFormattedNumberRangeData& data, bool equalBeforeRounding, UErrorCode& status) const; private: diff --git a/icu4c/source/i18n/unicode/numberformatter.h b/icu4c/source/i18n/unicode/numberformatter.h index 57bc1f30345..2a9743e6bd5 100644 --- a/icu4c/source/i18n/unicode/numberformatter.h +++ b/icu4c/source/i18n/unicode/numberformatter.h @@ -2110,6 +2110,9 @@ class U_I18N_API NumberFormatterSettings { friend class LocalizedNumberFormatter; friend class UnlocalizedNumberFormatter; + + // Give NumberRangeFormatter access to the MacroProps + friend class impl::NumberRangeFormatterImpl; }; /** @@ -2189,9 +2192,6 @@ class U_I18N_API UnlocalizedNumberFormatter // To give NumberFormatter::with() access to this class's constructor: friend class NumberFormatter; - - // Give NumberRangeFormatter access to the MacroProps - friend class NumberRangeFormatterImpl; }; /** diff --git a/icu4c/source/i18n/unicode/numberrangeformatter.h b/icu4c/source/i18n/unicode/numberrangeformatter.h index 208e533e22c..7f4000f4423 100644 --- a/icu4c/source/i18n/unicode/numberrangeformatter.h +++ b/icu4c/source/i18n/unicode/numberrangeformatter.h @@ -175,6 +175,7 @@ namespace impl { struct RangeMacroProps; class DecimalQuantity; struct UFormattedNumberRangeData; +class NumberRangeFormatterImpl; } // namespace impl @@ -598,7 +599,8 @@ class U_I18N_API LocalizedNumberRangeFormatter * Set if an error occurs while formatting. * @internal */ - void formatImpl(impl::UFormattedNumberRangeData* results, UErrorCode& status) const; + void formatImpl(impl::UFormattedNumberRangeData& results, bool equalBeforeRounding, + UErrorCode& status) const; #endif @@ -609,6 +611,8 @@ class U_I18N_API LocalizedNumberRangeFormatter ~LocalizedNumberRangeFormatter(); private: + // TODO: This is not thread-safe! Do NOT check this in without an atomic here. + impl::NumberRangeFormatterImpl* fImpl = nullptr; explicit LocalizedNumberRangeFormatter( const NumberRangeFormatterSettings& other); diff --git a/icu4c/source/test/intltest/numbertest_range.cpp b/icu4c/source/test/intltest/numbertest_range.cpp index 3370edc5301..9e47bab6e98 100644 --- a/icu4c/source/test/intltest/numbertest_range.cpp +++ b/icu4c/source/test/intltest/numbertest_range.cpp @@ -38,14 +38,14 @@ void NumberRangeFormatterTest::testBasic() { NumberRangeFormatter::with(), Locale("en-us"), u"1 --- 5", - u"5 --- 5", - u"5 --- 5", + u"~5", + u"~5", u"0 --- 3", - u"0 --- 0", + u"~0", u"3 --- 3,000", u"3,000 --- 5,000", u"4,999 --- 5,001", - u"5,000 --- 5,000", + u"~5,000", u"5,000 --- 5,000,000"); }