• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // Declare all classes that implement NumberRangeFormatterSettings
166 // See https://stackoverflow.com/a/495056/1407170
167 template
168 class icu::number::NumberRangeFormatterSettings<icu::number::UnlocalizedNumberRangeFormatter>;
169 template
170 class icu::number::NumberRangeFormatterSettings<icu::number::LocalizedNumberRangeFormatter>;
171 
172 
with()173 UnlocalizedNumberRangeFormatter NumberRangeFormatter::with() {
174     UnlocalizedNumberRangeFormatter result;
175     return result;
176 }
177 
withLocale(const Locale & locale)178 LocalizedNumberRangeFormatter NumberRangeFormatter::withLocale(const Locale& locale) {
179     return with().locale(locale);
180 }
181 
182 
183 template<typename T> using NFS = NumberRangeFormatterSettings<T>;
184 using LNF = LocalizedNumberRangeFormatter;
185 using UNF = UnlocalizedNumberRangeFormatter;
186 
UnlocalizedNumberRangeFormatter(const UNF & other)187 UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(const UNF& other)
188         : UNF(static_cast<const NFS<UNF>&>(other)) {}
189 
UnlocalizedNumberRangeFormatter(const NFS<UNF> & other)190 UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(const NFS<UNF>& other)
191         : NFS<UNF>(other) {
192     // No additional fields to assign
193 }
194 
195 // Make default copy constructor call the NumberRangeFormatterSettings copy constructor.
UnlocalizedNumberRangeFormatter(UNF && src)196 UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(UNF&& src) U_NOEXCEPT
197         : UNF(static_cast<NFS<UNF>&&>(src)) {}
198 
UnlocalizedNumberRangeFormatter(NFS<UNF> && src)199 UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(NFS<UNF>&& src) U_NOEXCEPT
200         : NFS<UNF>(std::move(src)) {
201     // No additional fields to assign
202 }
203 
operator =(const UNF & other)204 UnlocalizedNumberRangeFormatter& UnlocalizedNumberRangeFormatter::operator=(const UNF& other) {
205     NFS<UNF>::operator=(static_cast<const NFS<UNF>&>(other));
206     // No additional fields to assign
207     return *this;
208 }
209 
operator =(UNF && src)210 UnlocalizedNumberRangeFormatter& UnlocalizedNumberRangeFormatter::operator=(UNF&& src) U_NOEXCEPT {
211     NFS<UNF>::operator=(static_cast<NFS<UNF>&&>(src));
212     // No additional fields to assign
213     return *this;
214 }
215 
216 // Make default copy constructor call the NumberRangeFormatterSettings copy constructor.
LocalizedNumberRangeFormatter(const LNF & other)217 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const LNF& other)
218         : LNF(static_cast<const NFS<LNF>&>(other)) {}
219 
LocalizedNumberRangeFormatter(const NFS<LNF> & other)220 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const NFS<LNF>& other)
221         : NFS<LNF>(other) {
222     // No additional fields to assign
223 }
224 
LocalizedNumberRangeFormatter(LocalizedNumberRangeFormatter && src)225 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(LocalizedNumberRangeFormatter&& src) U_NOEXCEPT
226         : LNF(static_cast<NFS<LNF>&&>(src)) {}
227 
LocalizedNumberRangeFormatter(NFS<LNF> && src)228 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(NFS<LNF>&& src) U_NOEXCEPT
229         : NFS<LNF>(std::move(src)) {
230     // Steal the compiled formatter
231     LNF&& _src = static_cast<LNF&&>(src);
232     auto* stolen = _src.fAtomicFormatter.exchange(nullptr);
233     delete fAtomicFormatter.exchange(stolen);
234 }
235 
operator =(const LNF & other)236 LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(const LNF& other) {
237     NFS<LNF>::operator=(static_cast<const NFS<LNF>&>(other));
238     // Do not steal; just clear
239     delete fAtomicFormatter.exchange(nullptr);
240     return *this;
241 }
242 
operator =(LNF && src)243 LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(LNF&& src) U_NOEXCEPT {
244     NFS<LNF>::operator=(static_cast<NFS<LNF>&&>(src));
245     // Steal the compiled formatter
246     auto* stolen = src.fAtomicFormatter.exchange(nullptr);
247     delete fAtomicFormatter.exchange(stolen);
248     return *this;
249 }
250 
251 
~LocalizedNumberRangeFormatter()252 LocalizedNumberRangeFormatter::~LocalizedNumberRangeFormatter() {
253     delete fAtomicFormatter.exchange(nullptr);
254 }
255 
LocalizedNumberRangeFormatter(const RangeMacroProps & macros,const Locale & locale)256 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const RangeMacroProps& macros, const Locale& locale) {
257     fMacros = macros;
258     fMacros.locale = locale;
259     touchRangeLocales(fMacros);
260 }
261 
LocalizedNumberRangeFormatter(RangeMacroProps && macros,const Locale & locale)262 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(RangeMacroProps&& macros, const Locale& locale) {
263     fMacros = std::move(macros);
264     fMacros.locale = locale;
265     touchRangeLocales(fMacros);
266 }
267 
locale(const Locale & locale) const268 LocalizedNumberRangeFormatter UnlocalizedNumberRangeFormatter::locale(const Locale& locale) const& {
269     return LocalizedNumberRangeFormatter(fMacros, locale);
270 }
271 
locale(const Locale & locale)272 LocalizedNumberRangeFormatter UnlocalizedNumberRangeFormatter::locale(const Locale& locale)&& {
273     return LocalizedNumberRangeFormatter(std::move(fMacros), locale);
274 }
275 
276 
formatFormattableRange(const Formattable & first,const Formattable & second,UErrorCode & status) const277 FormattedNumberRange LocalizedNumberRangeFormatter::formatFormattableRange(
278         const Formattable& first, const Formattable& second, UErrorCode& status) const {
279     if (U_FAILURE(status)) {
280         return FormattedNumberRange(U_ILLEGAL_ARGUMENT_ERROR);
281     }
282 
283     auto results = new UFormattedNumberRangeData();
284     if (results == nullptr) {
285         status = U_MEMORY_ALLOCATION_ERROR;
286         return FormattedNumberRange(status);
287     }
288 
289     first.populateDecimalQuantity(results->quantity1, status);
290     if (U_FAILURE(status)) {
291         return FormattedNumberRange(status);
292     }
293 
294     second.populateDecimalQuantity(results->quantity2, status);
295     if (U_FAILURE(status)) {
296         return FormattedNumberRange(status);
297     }
298 
299     formatImpl(*results, first == second, status);
300 
301     // Do not save the results object if we encountered a failure.
302     if (U_SUCCESS(status)) {
303         return FormattedNumberRange(results);
304     } else {
305         delete results;
306         return FormattedNumberRange(status);
307     }
308 }
309 
formatImpl(UFormattedNumberRangeData & results,bool equalBeforeRounding,UErrorCode & status) const310 void LocalizedNumberRangeFormatter::formatImpl(
311         UFormattedNumberRangeData& results, bool equalBeforeRounding, UErrorCode& status) const {
312     auto* impl = getFormatter(status);
313     if (U_FAILURE(status)) {
314         return;
315     }
316     if (impl == nullptr) {
317         status = U_INTERNAL_PROGRAM_ERROR;
318         return;
319     }
320     impl->format(results, equalBeforeRounding, status);
321 }
322 
323 const impl::NumberRangeFormatterImpl*
getFormatter(UErrorCode & status) const324 LocalizedNumberRangeFormatter::getFormatter(UErrorCode& status) const {
325     // TODO: Move this into umutex.h? (similar logic also in decimfmt.cpp)
326     // See ICU-20146
327 
328     if (U_FAILURE(status)) {
329         return nullptr;
330     }
331 
332     // First try to get the pre-computed formatter
333     auto* ptr = fAtomicFormatter.load();
334     if (ptr != nullptr) {
335         return ptr;
336     }
337 
338     // Try computing the formatter on our own
339     auto* temp = new NumberRangeFormatterImpl(fMacros, status);
340     if (U_FAILURE(status)) {
341         return nullptr;
342     }
343     if (temp == nullptr) {
344         status = U_MEMORY_ALLOCATION_ERROR;
345         return nullptr;
346     }
347 
348     // Note: ptr starts as nullptr; during compare_exchange,
349     // it is set to what is actually stored in the atomic
350     // if another thread beat us to computing the formatter object.
351     auto* nonConstThis = const_cast<LocalizedNumberRangeFormatter*>(this);
352     if (!nonConstThis->fAtomicFormatter.compare_exchange_strong(ptr, temp)) {
353         // Another thread beat us to computing the formatter
354         delete temp;
355         return ptr;
356     } else {
357         // Our copy of the formatter got stored in the atomic
358         return temp;
359     }
360 
361 }
362 
363 
FormattedNumberRange(FormattedNumberRange && src)364 FormattedNumberRange::FormattedNumberRange(FormattedNumberRange&& src) U_NOEXCEPT
365         : fResults(src.fResults), fErrorCode(src.fErrorCode) {
366     // Disown src.fResults to prevent double-deletion
367     src.fResults = nullptr;
368     src.fErrorCode = U_INVALID_STATE_ERROR;
369 }
370 
operator =(FormattedNumberRange && src)371 FormattedNumberRange& FormattedNumberRange::operator=(FormattedNumberRange&& src) U_NOEXCEPT {
372     delete fResults;
373     fResults = src.fResults;
374     fErrorCode = src.fErrorCode;
375     // Disown src.fResults to prevent double-deletion
376     src.fResults = nullptr;
377     src.fErrorCode = U_INVALID_STATE_ERROR;
378     return *this;
379 }
380 
toString(UErrorCode & status) const381 UnicodeString FormattedNumberRange::toString(UErrorCode& status) const {
382     if (U_FAILURE(status)) {
383         return ICU_Utility::makeBogusString();
384     }
385     if (fResults == nullptr) {
386         status = fErrorCode;
387         return ICU_Utility::makeBogusString();
388     }
389     return fResults->string.toUnicodeString();
390 }
391 
appendTo(Appendable & appendable,UErrorCode & status) const392 Appendable& FormattedNumberRange::appendTo(Appendable& appendable, UErrorCode& status) const {
393     if (U_FAILURE(status)) {
394         return appendable;
395     }
396     if (fResults == nullptr) {
397         status = fErrorCode;
398         return appendable;
399     }
400     appendable.appendString(fResults->string.chars(), fResults->string.length());
401     return appendable;
402 }
403 
nextFieldPosition(FieldPosition & fieldPosition,UErrorCode & status) const404 UBool FormattedNumberRange::nextFieldPosition(FieldPosition& fieldPosition, UErrorCode& status) const {
405     if (U_FAILURE(status)) {
406         return FALSE;
407     }
408     if (fResults == nullptr) {
409         status = fErrorCode;
410         return FALSE;
411     }
412     // NOTE: MSVC sometimes complains when implicitly converting between bool and UBool
413     return fResults->string.nextFieldPosition(fieldPosition, status) ? TRUE : FALSE;
414 }
415 
getAllFieldPositions(FieldPositionIterator & iterator,UErrorCode & status) const416 void FormattedNumberRange::getAllFieldPositions(FieldPositionIterator& iterator, UErrorCode& status) const {
417     FieldPositionIteratorHandler fpih(&iterator, status);
418     getAllFieldPositionsImpl(fpih, status);
419 }
420 
getAllFieldPositionsImpl(FieldPositionIteratorHandler & fpih,UErrorCode & status) const421 void FormattedNumberRange::getAllFieldPositionsImpl(
422         FieldPositionIteratorHandler& fpih, UErrorCode& status) const {
423     if (U_FAILURE(status)) {
424         return;
425     }
426     if (fResults == nullptr) {
427         status = fErrorCode;
428         return;
429     }
430     fResults->string.getAllFieldPositions(fpih, status);
431 }
432 
getFirstDecimal(UErrorCode & status) const433 UnicodeString FormattedNumberRange::getFirstDecimal(UErrorCode& status) const {
434     if (U_FAILURE(status)) {
435         return ICU_Utility::makeBogusString();
436     }
437     if (fResults == nullptr) {
438         status = fErrorCode;
439         return ICU_Utility::makeBogusString();
440     }
441     return fResults->quantity1.toScientificString();
442 }
443 
getSecondDecimal(UErrorCode & status) const444 UnicodeString FormattedNumberRange::getSecondDecimal(UErrorCode& status) const {
445     if (U_FAILURE(status)) {
446         return ICU_Utility::makeBogusString();
447     }
448     if (fResults == nullptr) {
449         status = fErrorCode;
450         return ICU_Utility::makeBogusString();
451     }
452     return fResults->quantity2.toScientificString();
453 }
454 
getIdentityResult(UErrorCode & status) const455 UNumberRangeIdentityResult FormattedNumberRange::getIdentityResult(UErrorCode& status) const {
456     if (U_FAILURE(status)) {
457         return UNUM_IDENTITY_RESULT_NOT_EQUAL;
458     }
459     if (fResults == nullptr) {
460         status = fErrorCode;
461         return UNUM_IDENTITY_RESULT_NOT_EQUAL;
462     }
463     return fResults->identityResult;
464 }
465 
~FormattedNumberRange()466 FormattedNumberRange::~FormattedNumberRange() {
467     delete fResults;
468 }
469 
470 
471 
472 #endif /* #if !UCONFIG_NO_FORMATTING */
473