1 // © 2018 and later: Unicode, Inc. and others. 
   2 // License & terms of use: http://www.unicode.org/copyright.html 
   4 #include "unicode/utypes.h" 
   6 #if !UCONFIG_NO_FORMATTING 
   8 // Allow implicit conversion from char16_t* to UnicodeString for this file: 
   9 // Helpful in toString methods and elsewhere. 
  10 #define UNISTR_FROM_STRING_EXPLICIT 
  12 #include "numrange_impl.h" 
  14 #include "number_utypes.h" 
  17 using namespace icu::number
; 
  18 using namespace icu::number::impl
; 
  21 // This function needs to be declared in this namespace so it can be friended. 
  22 // NOTE: In Java, this logic is handled in the resolve() function. 
  23 void icu::number::impl::touchRangeLocales(RangeMacroProps
& macros
) { 
  24     macros
.formatter1
.fMacros
.locale 
= macros
.locale
; 
  25     macros
.formatter2
.fMacros
.locale 
= macros
.locale
; 
  29 template<typename Derived
> 
  30 Derived NumberRangeFormatterSettings
<Derived
>::numberFormatterBoth(const UnlocalizedNumberFormatter
& formatter
) const& { 
  32     copy
.fMacros
.formatter1 
= formatter
; 
  33     copy
.fMacros
.singleFormatter 
= true; 
  34     touchRangeLocales(copy
.fMacros
); 
  38 template<typename Derived
> 
  39 Derived NumberRangeFormatterSettings
<Derived
>::numberFormatterBoth(const UnlocalizedNumberFormatter
& formatter
) && { 
  40     Derived 
move(std::move(*this)); 
  41     move
.fMacros
.formatter1 
= formatter
; 
  42     move
.fMacros
.singleFormatter 
= true; 
  43     touchRangeLocales(move
.fMacros
); 
  47 template<typename Derived
> 
  48 Derived NumberRangeFormatterSettings
<Derived
>::numberFormatterBoth(UnlocalizedNumberFormatter
&& formatter
) const& { 
  50     copy
.fMacros
.formatter1 
= std::move(formatter
); 
  51     copy
.fMacros
.singleFormatter 
= true; 
  52     touchRangeLocales(copy
.fMacros
); 
  56 template<typename Derived
> 
  57 Derived NumberRangeFormatterSettings
<Derived
>::numberFormatterBoth(UnlocalizedNumberFormatter
&& formatter
) && { 
  58     Derived 
move(std::move(*this)); 
  59     move
.fMacros
.formatter1 
= std::move(formatter
); 
  60     move
.fMacros
.singleFormatter 
= true; 
  61     touchRangeLocales(move
.fMacros
); 
  65 template<typename Derived
> 
  66 Derived NumberRangeFormatterSettings
<Derived
>::numberFormatterFirst(const UnlocalizedNumberFormatter
& formatter
) const& { 
  68     copy
.fMacros
.formatter1 
= formatter
; 
  69     copy
.fMacros
.singleFormatter 
= false; 
  70     touchRangeLocales(copy
.fMacros
); 
  74 template<typename Derived
> 
  75 Derived NumberRangeFormatterSettings
<Derived
>::numberFormatterFirst(const UnlocalizedNumberFormatter
& formatter
) && { 
  76     Derived 
move(std::move(*this)); 
  77     move
.fMacros
.formatter1 
= formatter
; 
  78     move
.fMacros
.singleFormatter 
= false; 
  79     touchRangeLocales(move
.fMacros
); 
  83 template<typename Derived
> 
  84 Derived NumberRangeFormatterSettings
<Derived
>::numberFormatterFirst(UnlocalizedNumberFormatter
&& formatter
) const& { 
  86     copy
.fMacros
.formatter1 
= std::move(formatter
); 
  87     copy
.fMacros
.singleFormatter 
= false; 
  88     touchRangeLocales(copy
.fMacros
); 
  92 template<typename Derived
> 
  93 Derived NumberRangeFormatterSettings
<Derived
>::numberFormatterFirst(UnlocalizedNumberFormatter
&& formatter
) && { 
  94     Derived 
move(std::move(*this)); 
  95     move
.fMacros
.formatter1 
= std::move(formatter
); 
  96     move
.fMacros
.singleFormatter 
= false; 
  97     touchRangeLocales(move
.fMacros
); 
 101 template<typename Derived
> 
 102 Derived NumberRangeFormatterSettings
<Derived
>::numberFormatterSecond(const UnlocalizedNumberFormatter
& formatter
) const& { 
 104     copy
.fMacros
.formatter2 
= formatter
; 
 105     copy
.fMacros
.singleFormatter 
= false; 
 106     touchRangeLocales(copy
.fMacros
); 
 110 template<typename Derived
> 
 111 Derived NumberRangeFormatterSettings
<Derived
>::numberFormatterSecond(const UnlocalizedNumberFormatter
& formatter
) && { 
 112     Derived 
move(std::move(*this)); 
 113     move
.fMacros
.formatter2 
= formatter
; 
 114     move
.fMacros
.singleFormatter 
= false; 
 115     touchRangeLocales(move
.fMacros
); 
 119 template<typename Derived
> 
 120 Derived NumberRangeFormatterSettings
<Derived
>::numberFormatterSecond(UnlocalizedNumberFormatter
&& formatter
) const& { 
 122     copy
.fMacros
.formatter2 
= std::move(formatter
); 
 123     copy
.fMacros
.singleFormatter 
= false; 
 124     touchRangeLocales(copy
.fMacros
); 
 128 template<typename Derived
> 
 129 Derived NumberRangeFormatterSettings
<Derived
>::numberFormatterSecond(UnlocalizedNumberFormatter
&& formatter
) && { 
 130     Derived 
move(std::move(*this)); 
 131     move
.fMacros
.formatter2 
= std::move(formatter
); 
 132     move
.fMacros
.singleFormatter 
= false; 
 133     touchRangeLocales(move
.fMacros
); 
 137 template<typename Derived
> 
 138 Derived NumberRangeFormatterSettings
<Derived
>::collapse(UNumberRangeCollapse collapse
) const& { 
 140     copy
.fMacros
.collapse 
= collapse
; 
 144 template<typename Derived
> 
 145 Derived NumberRangeFormatterSettings
<Derived
>::collapse(UNumberRangeCollapse collapse
) && { 
 146     Derived 
move(std::move(*this)); 
 147     move
.fMacros
.collapse 
= collapse
; 
 151 template<typename Derived
> 
 152 Derived NumberRangeFormatterSettings
<Derived
>::identityFallback(UNumberRangeIdentityFallback identityFallback
) const& { 
 154     copy
.fMacros
.identityFallback 
= identityFallback
; 
 158 template<typename Derived
> 
 159 Derived NumberRangeFormatterSettings
<Derived
>::identityFallback(UNumberRangeIdentityFallback identityFallback
) && { 
 160     Derived 
move(std::move(*this)); 
 161     move
.fMacros
.identityFallback 
= identityFallback
; 
 165 template<typename Derived
> 
 166 LocalPointer
<Derived
> NumberRangeFormatterSettings
<Derived
>::clone() const & { 
 167     return LocalPointer
<Derived
>(new Derived(*this)); 
 170 template<typename Derived
> 
 171 LocalPointer
<Derived
> NumberRangeFormatterSettings
<Derived
>::clone() && { 
 172     return LocalPointer
<Derived
>(new Derived(std::move(*this))); 
 175 // Declare all classes that implement NumberRangeFormatterSettings 
 176 // See https://stackoverflow.com/a/495056/1407170 
 178 class icu::number::NumberRangeFormatterSettings
<icu::number::UnlocalizedNumberRangeFormatter
>; 
 180 class icu::number::NumberRangeFormatterSettings
<icu::number::LocalizedNumberRangeFormatter
>; 
 183 UnlocalizedNumberRangeFormatter 
NumberRangeFormatter::with() { 
 184     UnlocalizedNumberRangeFormatter result
; 
 188 LocalizedNumberRangeFormatter 
NumberRangeFormatter::withLocale(const Locale
& locale
) { 
 189     return with().locale(locale
); 
 193 template<typename T
> using NFS 
= NumberRangeFormatterSettings
<T
>; 
 194 using LNF 
= LocalizedNumberRangeFormatter
; 
 195 using UNF 
= UnlocalizedNumberRangeFormatter
; 
 197 UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(const UNF
& other
) 
 198         : UNF(static_cast<const NFS
<UNF
>&>(other
)) {} 
 200 UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(const NFS
<UNF
>& other
) 
 202     // No additional fields to assign 
 205 // Make default copy constructor call the NumberRangeFormatterSettings copy constructor. 
 206 UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(UNF
&& src
) U_NOEXCEPT
 
 207         : UNF(static_cast<NFS
<UNF
>&&>(src
)) {} 
 209 UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(NFS
<UNF
>&& src
) U_NOEXCEPT
 
 210         : NFS
<UNF
>(std::move(src
)) { 
 211     // No additional fields to assign 
 214 UnlocalizedNumberRangeFormatter
& UnlocalizedNumberRangeFormatter::operator=(const UNF
& other
) { 
 215     NFS
<UNF
>::operator=(static_cast<const NFS
<UNF
>&>(other
)); 
 216     // No additional fields to assign 
 220 UnlocalizedNumberRangeFormatter
& UnlocalizedNumberRangeFormatter::operator=(UNF
&& src
) U_NOEXCEPT 
{ 
 221     NFS
<UNF
>::operator=(static_cast<NFS
<UNF
>&&>(src
)); 
 222     // No additional fields to assign 
 226 // Make default copy constructor call the NumberRangeFormatterSettings copy constructor. 
 227 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const LNF
& other
) 
 228         : LNF(static_cast<const NFS
<LNF
>&>(other
)) {} 
 230 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const NFS
<LNF
>& other
) 
 232     // No additional fields to assign 
 235 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(LocalizedNumberRangeFormatter
&& src
) U_NOEXCEPT
 
 236         : LNF(static_cast<NFS
<LNF
>&&>(src
)) {} 
 238 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(NFS
<LNF
>&& src
) U_NOEXCEPT
 
 239         : NFS
<LNF
>(std::move(src
)) { 
 240     // Steal the compiled formatter 
 241     LNF
&& _src 
= static_cast<LNF
&&>(src
); 
 242     auto* stolen 
= _src
.fAtomicFormatter
.exchange(nullptr); 
 243     delete fAtomicFormatter
.exchange(stolen
); 
 246 LocalizedNumberRangeFormatter
& LocalizedNumberRangeFormatter::operator=(const LNF
& other
) { 
 247     NFS
<LNF
>::operator=(static_cast<const NFS
<LNF
>&>(other
)); 
 248     // Do not steal; just clear 
 249     delete fAtomicFormatter
.exchange(nullptr); 
 253 LocalizedNumberRangeFormatter
& LocalizedNumberRangeFormatter::operator=(LNF
&& src
) U_NOEXCEPT 
{ 
 254     NFS
<LNF
>::operator=(static_cast<NFS
<LNF
>&&>(src
)); 
 255     // Steal the compiled formatter 
 256     auto* stolen 
= src
.fAtomicFormatter
.exchange(nullptr); 
 257     delete fAtomicFormatter
.exchange(stolen
); 
 262 LocalizedNumberRangeFormatter::~LocalizedNumberRangeFormatter() { 
 263     delete fAtomicFormatter
.exchange(nullptr); 
 266 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const RangeMacroProps
& macros
, const Locale
& locale
) { 
 268     fMacros
.locale 
= locale
; 
 269     touchRangeLocales(fMacros
); 
 272 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(RangeMacroProps
&& macros
, const Locale
& locale
) { 
 273     fMacros 
= std::move(macros
); 
 274     fMacros
.locale 
= locale
; 
 275     touchRangeLocales(fMacros
); 
 278 LocalizedNumberRangeFormatter 
UnlocalizedNumberRangeFormatter::locale(const Locale
& locale
) const& { 
 279     return LocalizedNumberRangeFormatter(fMacros
, locale
); 
 282 LocalizedNumberRangeFormatter 
UnlocalizedNumberRangeFormatter::locale(const Locale
& locale
)&& { 
 283     return LocalizedNumberRangeFormatter(std::move(fMacros
), locale
); 
 287 FormattedNumberRange 
LocalizedNumberRangeFormatter::formatFormattableRange( 
 288         const Formattable
& first
, const Formattable
& second
, UErrorCode
& status
) const { 
 289     if (U_FAILURE(status
)) { 
 290         return FormattedNumberRange(U_ILLEGAL_ARGUMENT_ERROR
); 
 293     auto results 
= new UFormattedNumberRangeData(); 
 294     if (results 
== nullptr) { 
 295         status 
= U_MEMORY_ALLOCATION_ERROR
; 
 296         return FormattedNumberRange(status
); 
 299     first
.populateDecimalQuantity(results
->quantity1
, status
); 
 300     if (U_FAILURE(status
)) { 
 301         return FormattedNumberRange(status
); 
 304     second
.populateDecimalQuantity(results
->quantity2
, status
); 
 305     if (U_FAILURE(status
)) { 
 306         return FormattedNumberRange(status
); 
 309     formatImpl(*results
, first 
== second
, status
); 
 311     // Do not save the results object if we encountered a failure. 
 312     if (U_SUCCESS(status
)) { 
 313         return FormattedNumberRange(results
); 
 316         return FormattedNumberRange(status
); 
 320 void LocalizedNumberRangeFormatter::formatImpl( 
 321         UFormattedNumberRangeData
& results
, bool equalBeforeRounding
, UErrorCode
& status
) const { 
 322     auto* impl 
= getFormatter(status
); 
 323     if (U_FAILURE(status
)) { 
 326     if (impl 
== nullptr) { 
 327         status 
= U_INTERNAL_PROGRAM_ERROR
; 
 330     impl
->format(results
, equalBeforeRounding
, status
); 
 331     if (U_FAILURE(status
)) { 
 334     results
.getStringRef().writeTerminator(status
); 
 337 const impl::NumberRangeFormatterImpl
* 
 338 LocalizedNumberRangeFormatter::getFormatter(UErrorCode
& status
) const { 
 339     // TODO: Move this into umutex.h? (similar logic also in decimfmt.cpp) 
 342     if (U_FAILURE(status
)) { 
 346     // First try to get the pre-computed formatter 
 347     auto* ptr 
= fAtomicFormatter
.load(); 
 348     if (ptr 
!= nullptr) { 
 352     // Try computing the formatter on our own 
 353     auto* temp 
= new NumberRangeFormatterImpl(fMacros
, status
); 
 354     if (U_FAILURE(status
)) { 
 357     if (temp 
== nullptr) { 
 358         status 
= U_MEMORY_ALLOCATION_ERROR
; 
 362     // Note: ptr starts as nullptr; during compare_exchange, 
 363     // it is set to what is actually stored in the atomic 
 364     // if another thread beat us to computing the formatter object. 
 365     auto* nonConstThis 
= const_cast<LocalizedNumberRangeFormatter
*>(this); 
 366     if (!nonConstThis
->fAtomicFormatter
.compare_exchange_strong(ptr
, temp
)) { 
 367         // Another thread beat us to computing the formatter 
 371         // Our copy of the formatter got stored in the atomic 
 378 UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(FormattedNumberRange
) 
 382 UBool 
FormattedNumberRange::nextFieldPosition(FieldPosition
& fieldPosition
, UErrorCode
& status
) const { 
 383     UPRV_FORMATTED_VALUE_METHOD_GUARD(FALSE
) 
 384     // NOTE: MSVC sometimes complains when implicitly converting between bool and UBool 
 385     return fData
->getStringRef().nextFieldPosition(fieldPosition
, status
) ? TRUE 
: FALSE
; 
 388 void FormattedNumberRange::getAllFieldPositions(FieldPositionIterator
& iterator
, UErrorCode
& status
) const { 
 389     FieldPositionIteratorHandler 
fpih(&iterator
, status
); 
 390     getAllFieldPositionsImpl(fpih
, status
); 
 393 void FormattedNumberRange::getAllFieldPositionsImpl( 
 394         FieldPositionIteratorHandler
& fpih
, UErrorCode
& status
) const { 
 395     UPRV_FORMATTED_VALUE_METHOD_GUARD(UPRV_NOARG
) 
 396     fData
->getStringRef().getAllFieldPositions(fpih
, status
); 
 399 UnicodeString 
FormattedNumberRange::getFirstDecimal(UErrorCode
& status
) const { 
 400     UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString()) 
 401     return fData
->quantity1
.toScientificString(); 
 404 UnicodeString 
FormattedNumberRange::getSecondDecimal(UErrorCode
& status
) const { 
 405     UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString()) 
 406     return fData
->quantity2
.toScientificString(); 
 409 UNumberRangeIdentityResult 
FormattedNumberRange::getIdentityResult(UErrorCode
& status
) const { 
 410     UPRV_FORMATTED_VALUE_METHOD_GUARD(UNUM_IDENTITY_RESULT_NOT_EQUAL
) 
 411     return fData
->identityResult
; 
 415 UFormattedNumberRangeData::~UFormattedNumberRangeData() = default; 
 419 #endif /* #if !UCONFIG_NO_FORMATTING */