• 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 #include "number_decnum.h"
16 
17 using namespace icu;
18 using namespace icu::number;
19 using namespace icu::number::impl;
20 
21 
22 // This function needs to be declared in this namespace so it can be friended.
23 // NOTE: In Java, this logic is handled in the resolve() function.
touchRangeLocales(RangeMacroProps & macros)24 void icu::number::impl::touchRangeLocales(RangeMacroProps& macros) {
25     macros.formatter1.fMacros.locale = macros.locale;
26     macros.formatter2.fMacros.locale = macros.locale;
27 }
28 
29 
30 template<typename Derived>
numberFormatterBoth(const UnlocalizedNumberFormatter & formatter) const31 Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(const UnlocalizedNumberFormatter& formatter) const& {
32     Derived copy(*this);
33     copy.fMacros.formatter1 = formatter;
34     copy.fMacros.singleFormatter = true;
35     touchRangeLocales(copy.fMacros);
36     return copy;
37 }
38 
39 template<typename Derived>
numberFormatterBoth(const UnlocalizedNumberFormatter & formatter)40 Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(const UnlocalizedNumberFormatter& formatter) && {
41     Derived move(std::move(*this));
42     move.fMacros.formatter1 = formatter;
43     move.fMacros.singleFormatter = true;
44     touchRangeLocales(move.fMacros);
45     return move;
46 }
47 
48 template<typename Derived>
numberFormatterBoth(UnlocalizedNumberFormatter && formatter) const49 Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(UnlocalizedNumberFormatter&& formatter) const& {
50     Derived copy(*this);
51     copy.fMacros.formatter1 = std::move(formatter);
52     copy.fMacros.singleFormatter = true;
53     touchRangeLocales(copy.fMacros);
54     return copy;
55 }
56 
57 template<typename Derived>
numberFormatterBoth(UnlocalizedNumberFormatter && formatter)58 Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(UnlocalizedNumberFormatter&& formatter) && {
59     Derived move(std::move(*this));
60     move.fMacros.formatter1 = std::move(formatter);
61     move.fMacros.singleFormatter = true;
62     touchRangeLocales(move.fMacros);
63     return move;
64 }
65 
66 template<typename Derived>
numberFormatterFirst(const UnlocalizedNumberFormatter & formatter) const67 Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(const UnlocalizedNumberFormatter& formatter) const& {
68     Derived copy(*this);
69     copy.fMacros.formatter1 = formatter;
70     copy.fMacros.singleFormatter = false;
71     touchRangeLocales(copy.fMacros);
72     return copy;
73 }
74 
75 template<typename Derived>
numberFormatterFirst(const UnlocalizedNumberFormatter & formatter)76 Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(const UnlocalizedNumberFormatter& formatter) && {
77     Derived move(std::move(*this));
78     move.fMacros.formatter1 = formatter;
79     move.fMacros.singleFormatter = false;
80     touchRangeLocales(move.fMacros);
81     return move;
82 }
83 
84 template<typename Derived>
numberFormatterFirst(UnlocalizedNumberFormatter && formatter) const85 Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(UnlocalizedNumberFormatter&& formatter) const& {
86     Derived copy(*this);
87     copy.fMacros.formatter1 = std::move(formatter);
88     copy.fMacros.singleFormatter = false;
89     touchRangeLocales(copy.fMacros);
90     return copy;
91 }
92 
93 template<typename Derived>
numberFormatterFirst(UnlocalizedNumberFormatter && formatter)94 Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(UnlocalizedNumberFormatter&& formatter) && {
95     Derived move(std::move(*this));
96     move.fMacros.formatter1 = std::move(formatter);
97     move.fMacros.singleFormatter = false;
98     touchRangeLocales(move.fMacros);
99     return move;
100 }
101 
102 template<typename Derived>
numberFormatterSecond(const UnlocalizedNumberFormatter & formatter) const103 Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(const UnlocalizedNumberFormatter& formatter) const& {
104     Derived copy(*this);
105     copy.fMacros.formatter2 = formatter;
106     copy.fMacros.singleFormatter = false;
107     touchRangeLocales(copy.fMacros);
108     return copy;
109 }
110 
111 template<typename Derived>
numberFormatterSecond(const UnlocalizedNumberFormatter & formatter)112 Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(const UnlocalizedNumberFormatter& formatter) && {
113     Derived move(std::move(*this));
114     move.fMacros.formatter2 = formatter;
115     move.fMacros.singleFormatter = false;
116     touchRangeLocales(move.fMacros);
117     return move;
118 }
119 
120 template<typename Derived>
numberFormatterSecond(UnlocalizedNumberFormatter && formatter) const121 Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(UnlocalizedNumberFormatter&& formatter) const& {
122     Derived copy(*this);
123     copy.fMacros.formatter2 = std::move(formatter);
124     copy.fMacros.singleFormatter = false;
125     touchRangeLocales(copy.fMacros);
126     return copy;
127 }
128 
129 template<typename Derived>
numberFormatterSecond(UnlocalizedNumberFormatter && formatter)130 Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(UnlocalizedNumberFormatter&& formatter) && {
131     Derived move(std::move(*this));
132     move.fMacros.formatter2 = std::move(formatter);
133     move.fMacros.singleFormatter = false;
134     touchRangeLocales(move.fMacros);
135     return move;
136 }
137 
138 template<typename Derived>
collapse(UNumberRangeCollapse collapse) const139 Derived NumberRangeFormatterSettings<Derived>::collapse(UNumberRangeCollapse collapse) const& {
140     Derived copy(*this);
141     copy.fMacros.collapse = collapse;
142     return copy;
143 }
144 
145 template<typename Derived>
collapse(UNumberRangeCollapse collapse)146 Derived NumberRangeFormatterSettings<Derived>::collapse(UNumberRangeCollapse collapse) && {
147     Derived move(std::move(*this));
148     move.fMacros.collapse = collapse;
149     return move;
150 }
151 
152 template<typename Derived>
identityFallback(UNumberRangeIdentityFallback identityFallback) const153 Derived NumberRangeFormatterSettings<Derived>::identityFallback(UNumberRangeIdentityFallback identityFallback) const& {
154     Derived copy(*this);
155     copy.fMacros.identityFallback = identityFallback;
156     return copy;
157 }
158 
159 template<typename Derived>
identityFallback(UNumberRangeIdentityFallback identityFallback)160 Derived NumberRangeFormatterSettings<Derived>::identityFallback(UNumberRangeIdentityFallback identityFallback) && {
161     Derived move(std::move(*this));
162     move.fMacros.identityFallback = identityFallback;
163     return move;
164 }
165 
166 template<typename Derived>
clone() const167 LocalPointer<Derived> NumberRangeFormatterSettings<Derived>::clone() const & {
168     return LocalPointer<Derived>(new Derived(*this));
169 }
170 
171 template<typename Derived>
clone()172 LocalPointer<Derived> NumberRangeFormatterSettings<Derived>::clone() && {
173     return LocalPointer<Derived>(new Derived(std::move(*this)));
174 }
175 
176 // Declare all classes that implement NumberRangeFormatterSettings
177 // See https://stackoverflow.com/a/495056/1407170
178 template
179 class icu::number::NumberRangeFormatterSettings<icu::number::UnlocalizedNumberRangeFormatter>;
180 template
181 class icu::number::NumberRangeFormatterSettings<icu::number::LocalizedNumberRangeFormatter>;
182 
183 
with()184 UnlocalizedNumberRangeFormatter NumberRangeFormatter::with() {
185     UnlocalizedNumberRangeFormatter result;
186     return result;
187 }
188 
withLocale(const Locale & locale)189 LocalizedNumberRangeFormatter NumberRangeFormatter::withLocale(const Locale& locale) {
190     return with().locale(locale);
191 }
192 
193 
194 template<typename T> using NFS = NumberRangeFormatterSettings<T>;
195 using LNF = LocalizedNumberRangeFormatter;
196 using UNF = UnlocalizedNumberRangeFormatter;
197 
UnlocalizedNumberRangeFormatter(const UNF & other)198 UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(const UNF& other)
199         : UNF(static_cast<const NFS<UNF>&>(other)) {}
200 
UnlocalizedNumberRangeFormatter(const NFS<UNF> & other)201 UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(const NFS<UNF>& other)
202         : NFS<UNF>(other) {
203     // No additional fields to assign
204 }
205 
206 // Make default copy constructor call the NumberRangeFormatterSettings copy constructor.
UnlocalizedNumberRangeFormatter(UNF && src)207 UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(UNF&& src) noexcept
208         : UNF(static_cast<NFS<UNF>&&>(src)) {}
209 
UnlocalizedNumberRangeFormatter(NFS<UNF> && src)210 UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(NFS<UNF>&& src) noexcept
211         : NFS<UNF>(std::move(src)) {
212     // No additional fields to assign
213 }
214 
UnlocalizedNumberRangeFormatter(const impl::RangeMacroProps & macros)215 UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(const impl::RangeMacroProps &macros) {
216     fMacros = macros;
217 }
218 
UnlocalizedNumberRangeFormatter(impl::RangeMacroProps && macros)219 UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(impl::RangeMacroProps &&macros) {
220     fMacros = macros;
221 }
222 
operator =(const UNF & other)223 UnlocalizedNumberRangeFormatter& UnlocalizedNumberRangeFormatter::operator=(const UNF& other) {
224     NFS<UNF>::operator=(static_cast<const NFS<UNF>&>(other));
225     // No additional fields to assign
226     return *this;
227 }
228 
operator =(UNF && src)229 UnlocalizedNumberRangeFormatter& UnlocalizedNumberRangeFormatter::operator=(UNF&& src) noexcept {
230     NFS<UNF>::operator=(static_cast<NFS<UNF>&&>(src));
231     // No additional fields to assign
232     return *this;
233 }
234 
235 // Make default copy constructor call the NumberRangeFormatterSettings copy constructor.
LocalizedNumberRangeFormatter(const LNF & other)236 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const LNF& other)
237         : LNF(static_cast<const NFS<LNF>&>(other)) {}
238 
LocalizedNumberRangeFormatter(const NFS<LNF> & other)239 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const NFS<LNF>& other)
240         : NFS<LNF>(other) {
241     // No additional fields to assign
242 }
243 
LocalizedNumberRangeFormatter(LocalizedNumberRangeFormatter && src)244 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(LocalizedNumberRangeFormatter&& src) noexcept
245         : LNF(static_cast<NFS<LNF>&&>(src)) {}
246 
LocalizedNumberRangeFormatter(NFS<LNF> && src)247 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(NFS<LNF>&& src) noexcept
248         : NFS<LNF>(std::move(src)) {
249     // Steal the compiled formatter
250     LNF&& _src = static_cast<LNF&&>(src);
251     auto* stolen = _src.fAtomicFormatter.exchange(nullptr);
252     delete fAtomicFormatter.exchange(stolen);
253 }
254 
operator =(const LNF & other)255 LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(const LNF& other) {
256     if (this == &other) { return *this; }  // self-assignment: no-op
257     NFS<LNF>::operator=(static_cast<const NFS<LNF>&>(other));
258     // Do not steal; just clear
259     delete fAtomicFormatter.exchange(nullptr);
260     return *this;
261 }
262 
operator =(LNF && src)263 LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(LNF&& src) noexcept {
264     NFS<LNF>::operator=(static_cast<NFS<LNF>&&>(src));
265     // Steal the compiled formatter
266     auto* stolen = src.fAtomicFormatter.exchange(nullptr);
267     delete fAtomicFormatter.exchange(stolen);
268     return *this;
269 }
270 
271 
~LocalizedNumberRangeFormatter()272 LocalizedNumberRangeFormatter::~LocalizedNumberRangeFormatter() {
273     delete fAtomicFormatter.exchange(nullptr);
274 }
275 
LocalizedNumberRangeFormatter(const RangeMacroProps & macros,const Locale & locale)276 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const RangeMacroProps& macros, const Locale& locale) {
277     fMacros = macros;
278     fMacros.locale = locale;
279     touchRangeLocales(fMacros);
280 }
281 
LocalizedNumberRangeFormatter(RangeMacroProps && macros,const Locale & locale)282 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(RangeMacroProps&& macros, const Locale& locale) {
283     fMacros = std::move(macros);
284     fMacros.locale = locale;
285     touchRangeLocales(fMacros);
286 }
287 
locale(const Locale & locale) const288 LocalizedNumberRangeFormatter UnlocalizedNumberRangeFormatter::locale(const Locale& locale) const& {
289     return LocalizedNumberRangeFormatter(fMacros, locale);
290 }
291 
locale(const Locale & locale)292 LocalizedNumberRangeFormatter UnlocalizedNumberRangeFormatter::locale(const Locale& locale)&& {
293     return LocalizedNumberRangeFormatter(std::move(fMacros), locale);
294 }
295 
296 
withoutLocale() const297 UnlocalizedNumberRangeFormatter LocalizedNumberRangeFormatter::withoutLocale() const & {
298     RangeMacroProps macros(fMacros);
299     macros.locale = Locale();
300     return UnlocalizedNumberRangeFormatter(macros);
301 }
302 
withoutLocale()303 UnlocalizedNumberRangeFormatter LocalizedNumberRangeFormatter::withoutLocale() && {
304     RangeMacroProps macros(std::move(fMacros));
305     macros.locale = Locale();
306     return UnlocalizedNumberRangeFormatter(std::move(macros));
307 }
308 
309 
formatFormattableRange(const Formattable & first,const Formattable & second,UErrorCode & status) const310 FormattedNumberRange LocalizedNumberRangeFormatter::formatFormattableRange(
311         const Formattable& first, const Formattable& second, UErrorCode& status) const {
312     if (U_FAILURE(status)) {
313         return FormattedNumberRange(U_ILLEGAL_ARGUMENT_ERROR);
314     }
315 
316     auto* results = new UFormattedNumberRangeData();
317     if (results == nullptr) {
318         status = U_MEMORY_ALLOCATION_ERROR;
319         return FormattedNumberRange(status);
320     }
321 
322     first.populateDecimalQuantity(results->quantity1, status);
323     if (U_FAILURE(status)) {
324         return FormattedNumberRange(status);
325     }
326 
327     second.populateDecimalQuantity(results->quantity2, status);
328     if (U_FAILURE(status)) {
329         return FormattedNumberRange(status);
330     }
331 
332     formatImpl(*results, first == second, status);
333 
334     // Do not save the results object if we encountered a failure.
335     if (U_SUCCESS(status)) {
336         return FormattedNumberRange(results);
337     } else {
338         delete results;
339         return FormattedNumberRange(status);
340     }
341 }
342 
formatImpl(UFormattedNumberRangeData & results,bool equalBeforeRounding,UErrorCode & status) const343 void LocalizedNumberRangeFormatter::formatImpl(
344         UFormattedNumberRangeData& results, bool equalBeforeRounding, UErrorCode& status) const {
345     const auto* impl = getFormatter(status);
346     if (U_FAILURE(status)) {
347         return;
348     }
349     if (impl == nullptr) {
350         status = U_INTERNAL_PROGRAM_ERROR;
351         return;
352     }
353     impl->format(results, equalBeforeRounding, status);
354     if (U_FAILURE(status)) {
355         return;
356     }
357     results.getStringRef().writeTerminator(status);
358 }
359 
360 const impl::NumberRangeFormatterImpl*
getFormatter(UErrorCode & status) const361 LocalizedNumberRangeFormatter::getFormatter(UErrorCode& status) const {
362     // TODO: Move this into umutex.h? (similar logic also in decimfmt.cpp)
363     // See ICU-20146
364 
365     if (U_FAILURE(status)) {
366         return nullptr;
367     }
368 
369     // First try to get the pre-computed formatter
370     auto* ptr = fAtomicFormatter.load();
371     if (ptr != nullptr) {
372         return ptr;
373     }
374 
375     // Try computing the formatter on our own
376     auto* temp = new NumberRangeFormatterImpl(fMacros, status);
377     if (U_FAILURE(status)) {
378         delete temp;
379         return nullptr;
380     }
381     if (temp == nullptr) {
382         status = U_MEMORY_ALLOCATION_ERROR;
383         return nullptr;
384     }
385 
386     // Note: ptr starts as nullptr; during compare_exchange,
387     // it is set to what is actually stored in the atomic
388     // if another thread beat us to computing the formatter object.
389     auto* nonConstThis = const_cast<LocalizedNumberRangeFormatter*>(this);
390     if (!nonConstThis->fAtomicFormatter.compare_exchange_strong(ptr, temp)) {
391         // Another thread beat us to computing the formatter
392         delete temp;
393         return ptr;
394     } else {
395         // Our copy of the formatter got stored in the atomic
396         return temp;
397     }
398 
399 }
400 
401 
402 #endif /* #if !UCONFIG_NO_FORMATTING */
403