1 // © 2018 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 
4 #include "unicode/utypes.h"
5 
6 #if !UCONFIG_NO_FORMATTING
7 
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
11 
12 #include "numrange_impl.h"
13 #include "util.h"
14 #include "number_utypes.h"
15 
16 using namespace icu;
17 using namespace icu::number;
18 using namespace icu::number::impl;
19 
20 
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.
touchRangeLocales(RangeMacroProps & macros)23 void icu::number::impl::touchRangeLocales(RangeMacroProps& macros) {
24     macros.formatter1.fMacros.locale = macros.locale;
25     macros.formatter2.fMacros.locale = macros.locale;
26 }
27 
28 
29 template<typename Derived>
numberFormatterBoth(const UnlocalizedNumberFormatter & formatter) const30 Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(const UnlocalizedNumberFormatter& formatter) const& {
31     Derived copy(*this);
32     copy.fMacros.formatter1 = formatter;
33     copy.fMacros.singleFormatter = true;
34     touchRangeLocales(copy.fMacros);
35     return copy;
36 }
37 
38 template<typename Derived>
numberFormatterBoth(const UnlocalizedNumberFormatter & formatter)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);
44     return move;
45 }
46 
47 template<typename Derived>
numberFormatterBoth(UnlocalizedNumberFormatter && formatter) const48 Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(UnlocalizedNumberFormatter&& formatter) const& {
49     Derived copy(*this);
50     copy.fMacros.formatter1 = std::move(formatter);
51     copy.fMacros.singleFormatter = true;
52     touchRangeLocales(copy.fMacros);
53     return copy;
54 }
55 
56 template<typename Derived>
numberFormatterBoth(UnlocalizedNumberFormatter && formatter)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);
62     return move;
63 }
64 
65 template<typename Derived>
numberFormatterFirst(const UnlocalizedNumberFormatter & formatter) const66 Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(const UnlocalizedNumberFormatter& formatter) const& {
67     Derived copy(*this);
68     copy.fMacros.formatter1 = formatter;
69     copy.fMacros.singleFormatter = false;
70     touchRangeLocales(copy.fMacros);
71     return copy;
72 }
73 
74 template<typename Derived>
numberFormatterFirst(const UnlocalizedNumberFormatter & formatter)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);
80     return move;
81 }
82 
83 template<typename Derived>
numberFormatterFirst(UnlocalizedNumberFormatter && formatter) const84 Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(UnlocalizedNumberFormatter&& formatter) const& {
85     Derived copy(*this);
86     copy.fMacros.formatter1 = std::move(formatter);
87     copy.fMacros.singleFormatter = false;
88     touchRangeLocales(copy.fMacros);
89     return copy;
90 }
91 
92 template<typename Derived>
numberFormatterFirst(UnlocalizedNumberFormatter && formatter)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);
98     return move;
99 }
100 
101 template<typename Derived>
numberFormatterSecond(const UnlocalizedNumberFormatter & formatter) const102 Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(const UnlocalizedNumberFormatter& formatter) const& {
103     Derived copy(*this);
104     copy.fMacros.formatter2 = formatter;
105     copy.fMacros.singleFormatter = false;
106     touchRangeLocales(copy.fMacros);
107     return copy;
108 }
109 
110 template<typename Derived>
numberFormatterSecond(const UnlocalizedNumberFormatter & formatter)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);
116     return move;
117 }
118 
119 template<typename Derived>
numberFormatterSecond(UnlocalizedNumberFormatter && formatter) const120 Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(UnlocalizedNumberFormatter&& formatter) const& {
121     Derived copy(*this);
122     copy.fMacros.formatter2 = std::move(formatter);
123     copy.fMacros.singleFormatter = false;
124     touchRangeLocales(copy.fMacros);
125     return copy;
126 }
127 
128 template<typename Derived>
numberFormatterSecond(UnlocalizedNumberFormatter && formatter)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);
134     return move;
135 }
136 
137 template<typename Derived>
collapse(UNumberRangeCollapse collapse) const138 Derived NumberRangeFormatterSettings<Derived>::collapse(UNumberRangeCollapse collapse) const& {
139     Derived copy(*this);
140     copy.fMacros.collapse = collapse;
141     return copy;
142 }
143 
144 template<typename Derived>
collapse(UNumberRangeCollapse collapse)145 Derived NumberRangeFormatterSettings<Derived>::collapse(UNumberRangeCollapse collapse) && {
146     Derived move(std::move(*this));
147     move.fMacros.collapse = collapse;
148     return move;
149 }
150 
151 template<typename Derived>
identityFallback(UNumberRangeIdentityFallback identityFallback) const152 Derived NumberRangeFormatterSettings<Derived>::identityFallback(UNumberRangeIdentityFallback identityFallback) const& {
153     Derived copy(*this);
154     copy.fMacros.identityFallback = identityFallback;
155     return copy;
156 }
157 
158 template<typename Derived>
identityFallback(UNumberRangeIdentityFallback identityFallback)159 Derived NumberRangeFormatterSettings<Derived>::identityFallback(UNumberRangeIdentityFallback identityFallback) && {
160     Derived move(std::move(*this));
161     move.fMacros.identityFallback = identityFallback;
162     return move;
163 }
164 
165 template<typename Derived>
clone() const166 LocalPointer<Derived> NumberRangeFormatterSettings<Derived>::clone() const & {
167     return LocalPointer<Derived>(new Derived(*this));
168 }
169 
170 template<typename Derived>
clone()171 LocalPointer<Derived> NumberRangeFormatterSettings<Derived>::clone() && {
172     return LocalPointer<Derived>(new Derived(std::move(*this)));
173 }
174 
175 // Declare all classes that implement NumberRangeFormatterSettings
176 // See https://stackoverflow.com/a/495056/1407170
177 template
178 class icu::number::NumberRangeFormatterSettings<icu::number::UnlocalizedNumberRangeFormatter>;
179 template
180 class icu::number::NumberRangeFormatterSettings<icu::number::LocalizedNumberRangeFormatter>;
181 
182 
with()183 UnlocalizedNumberRangeFormatter NumberRangeFormatter::with() {
184     UnlocalizedNumberRangeFormatter result;
185     return result;
186 }
187 
withLocale(const Locale & locale)188 LocalizedNumberRangeFormatter NumberRangeFormatter::withLocale(const Locale& locale) {
189     return with().locale(locale);
190 }
191 
192 
193 template<typename T> using NFS = NumberRangeFormatterSettings<T>;
194 using LNF = LocalizedNumberRangeFormatter;
195 using UNF = UnlocalizedNumberRangeFormatter;
196 
UnlocalizedNumberRangeFormatter(const UNF & other)197 UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(const UNF& other)
198         : UNF(static_cast<const NFS<UNF>&>(other)) {}
199 
UnlocalizedNumberRangeFormatter(const NFS<UNF> & other)200 UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(const NFS<UNF>& other)
201         : NFS<UNF>(other) {
202     // No additional fields to assign
203 }
204 
205 // Make default copy constructor call the NumberRangeFormatterSettings copy constructor.
UnlocalizedNumberRangeFormatter(UNF && src)206 UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(UNF&& src) U_NOEXCEPT
207         : UNF(static_cast<NFS<UNF>&&>(src)) {}
208 
UnlocalizedNumberRangeFormatter(NFS<UNF> && src)209 UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(NFS<UNF>&& src) U_NOEXCEPT
210         : NFS<UNF>(std::move(src)) {
211     // No additional fields to assign
212 }
213 
operator =(const UNF & other)214 UnlocalizedNumberRangeFormatter& UnlocalizedNumberRangeFormatter::operator=(const UNF& other) {
215     NFS<UNF>::operator=(static_cast<const NFS<UNF>&>(other));
216     // No additional fields to assign
217     return *this;
218 }
219 
operator =(UNF && src)220 UnlocalizedNumberRangeFormatter& UnlocalizedNumberRangeFormatter::operator=(UNF&& src) U_NOEXCEPT {
221     NFS<UNF>::operator=(static_cast<NFS<UNF>&&>(src));
222     // No additional fields to assign
223     return *this;
224 }
225 
226 // Make default copy constructor call the NumberRangeFormatterSettings copy constructor.
LocalizedNumberRangeFormatter(const LNF & other)227 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const LNF& other)
228         : LNF(static_cast<const NFS<LNF>&>(other)) {}
229 
LocalizedNumberRangeFormatter(const NFS<LNF> & other)230 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const NFS<LNF>& other)
231         : NFS<LNF>(other) {
232     // No additional fields to assign
233 }
234 
LocalizedNumberRangeFormatter(LocalizedNumberRangeFormatter && src)235 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(LocalizedNumberRangeFormatter&& src) U_NOEXCEPT
236         : LNF(static_cast<NFS<LNF>&&>(src)) {}
237 
LocalizedNumberRangeFormatter(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);
244 }
245 
operator =(const LNF & other)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);
250     return *this;
251 }
252 
operator =(LNF && src)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);
258     return *this;
259 }
260 
261 
~LocalizedNumberRangeFormatter()262 LocalizedNumberRangeFormatter::~LocalizedNumberRangeFormatter() {
263     delete fAtomicFormatter.exchange(nullptr);
264 }
265 
LocalizedNumberRangeFormatter(const RangeMacroProps & macros,const Locale & locale)266 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const RangeMacroProps& macros, const Locale& locale) {
267     fMacros = macros;
268     fMacros.locale = locale;
269     touchRangeLocales(fMacros);
270 }
271 
LocalizedNumberRangeFormatter(RangeMacroProps && macros,const Locale & locale)272 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(RangeMacroProps&& macros, const Locale& locale) {
273     fMacros = std::move(macros);
274     fMacros.locale = locale;
275     touchRangeLocales(fMacros);
276 }
277 
locale(const Locale & locale) const278 LocalizedNumberRangeFormatter UnlocalizedNumberRangeFormatter::locale(const Locale& locale) const& {
279     return LocalizedNumberRangeFormatter(fMacros, locale);
280 }
281 
locale(const Locale & locale)282 LocalizedNumberRangeFormatter UnlocalizedNumberRangeFormatter::locale(const Locale& locale)&& {
283     return LocalizedNumberRangeFormatter(std::move(fMacros), locale);
284 }
285 
286 
formatFormattableRange(const Formattable & first,const Formattable & second,UErrorCode & status) const287 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);
291     }
292 
293     auto results = new UFormattedNumberRangeData();
294     if (results == nullptr) {
295         status = U_MEMORY_ALLOCATION_ERROR;
296         return FormattedNumberRange(status);
297     }
298 
299     first.populateDecimalQuantity(results->quantity1, status);
300     if (U_FAILURE(status)) {
301         return FormattedNumberRange(status);
302     }
303 
304     second.populateDecimalQuantity(results->quantity2, status);
305     if (U_FAILURE(status)) {
306         return FormattedNumberRange(status);
307     }
308 
309     formatImpl(*results, first == second, status);
310 
311     // Do not save the results object if we encountered a failure.
312     if (U_SUCCESS(status)) {
313         return FormattedNumberRange(results);
314     } else {
315         delete results;
316         return FormattedNumberRange(status);
317     }
318 }
319 
formatImpl(UFormattedNumberRangeData & results,bool equalBeforeRounding,UErrorCode & status) const320 void LocalizedNumberRangeFormatter::formatImpl(
321         UFormattedNumberRangeData& results, bool equalBeforeRounding, UErrorCode& status) const {
322     auto* impl = getFormatter(status);
323     if (U_FAILURE(status)) {
324         return;
325     }
326     if (impl == nullptr) {
327         status = U_INTERNAL_PROGRAM_ERROR;
328         return;
329     }
330     impl->format(results, equalBeforeRounding, status);
331     if (U_FAILURE(status)) {
332         return;
333     }
334     results.getStringRef().writeTerminator(status);
335 }
336 
337 const impl::NumberRangeFormatterImpl*
getFormatter(UErrorCode & status) const338 LocalizedNumberRangeFormatter::getFormatter(UErrorCode& status) const {
339     // TODO: Move this into umutex.h? (similar logic also in decimfmt.cpp)
340     // See ICU-20146
341 
342     if (U_FAILURE(status)) {
343         return nullptr;
344     }
345 
346     // First try to get the pre-computed formatter
347     auto* ptr = fAtomicFormatter.load();
348     if (ptr != nullptr) {
349         return ptr;
350     }
351 
352     // Try computing the formatter on our own
353     auto* temp = new NumberRangeFormatterImpl(fMacros, status);
354     if (U_FAILURE(status)) {
355         return nullptr;
356     }
357     if (temp == nullptr) {
358         status = U_MEMORY_ALLOCATION_ERROR;
359         return nullptr;
360     }
361 
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
368         delete temp;
369         return ptr;
370     } else {
371         // Our copy of the formatter got stored in the atomic
372         return temp;
373     }
374 
375 }
376 
377 
UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(FormattedNumberRange)378 UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(FormattedNumberRange)
379 
380 #define UPRV_NOARG
381 
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->nextFieldPosition(fieldPosition, status);
386 }
387 
getAllFieldPositions(FieldPositionIterator & iterator,UErrorCode & status) const388 void FormattedNumberRange::getAllFieldPositions(FieldPositionIterator& iterator, UErrorCode& status) const {
389     FieldPositionIteratorHandler fpih(&iterator, status);
390     getAllFieldPositionsImpl(fpih, status);
391 }
392 
getAllFieldPositionsImpl(FieldPositionIteratorHandler & fpih,UErrorCode & status) const393 void FormattedNumberRange::getAllFieldPositionsImpl(
394         FieldPositionIteratorHandler& fpih, UErrorCode& status) const {
395     UPRV_FORMATTED_VALUE_METHOD_GUARD(UPRV_NOARG)
396     fData->getAllFieldPositions(fpih, status);
397 }
398 
getFirstDecimal(UErrorCode & status) const399 UnicodeString FormattedNumberRange::getFirstDecimal(UErrorCode& status) const {
400     UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString())
401     return fData->quantity1.toScientificString();
402 }
403 
getSecondDecimal(UErrorCode & status) const404 UnicodeString FormattedNumberRange::getSecondDecimal(UErrorCode& status) const {
405     UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString())
406     return fData->quantity2.toScientificString();
407 }
408 
getIdentityResult(UErrorCode & status) const409 UNumberRangeIdentityResult FormattedNumberRange::getIdentityResult(UErrorCode& status) const {
410     UPRV_FORMATTED_VALUE_METHOD_GUARD(UNUM_IDENTITY_RESULT_NOT_EQUAL)
411     return fData->identityResult;
412 }
413 
414 
415 UFormattedNumberRangeData::~UFormattedNumberRangeData() = default;
416 
417 
418 
419 #endif /* #if !UCONFIG_NO_FORMATTING */
420