1 | // © 2017 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 | #include "uassert.h" |
9 | #include "unicode/numberformatter.h" |
10 | #include "number_decimalquantity.h" |
11 | #include "number_formatimpl.h" |
12 | #include "umutex.h" |
13 | #include "number_asformat.h" |
14 | #include "number_skeletons.h" |
15 | #include "number_utils.h" |
16 | #include "number_utypes.h" |
17 | #include "util.h" |
18 | #include "fphdlimp.h" |
19 | |
20 | using namespace icu; |
21 | using namespace icu::number; |
22 | using namespace icu::number::impl; |
23 | |
24 | template<typename Derived> |
25 | Derived NumberFormatterSettings<Derived>::notation(const Notation& notation) const& { |
26 | Derived copy(*this); |
27 | // NOTE: Slicing is OK. |
28 | copy.fMacros.notation = notation; |
29 | return copy; |
30 | } |
31 | |
32 | template<typename Derived> |
33 | Derived NumberFormatterSettings<Derived>::notation(const Notation& notation)&& { |
34 | Derived move(std::move(*this)); |
35 | // NOTE: Slicing is OK. |
36 | move.fMacros.notation = notation; |
37 | return move; |
38 | } |
39 | |
40 | template<typename Derived> |
41 | Derived NumberFormatterSettings<Derived>::unit(const icu::MeasureUnit& unit) const& { |
42 | Derived copy(*this); |
43 | // NOTE: Slicing occurs here. However, CurrencyUnit can be restored from MeasureUnit. |
44 | // TimeUnit may be affected, but TimeUnit is not as relevant to number formatting. |
45 | copy.fMacros.unit = unit; |
46 | return copy; |
47 | } |
48 | |
49 | template<typename Derived> |
50 | Derived NumberFormatterSettings<Derived>::unit(const icu::MeasureUnit& unit)&& { |
51 | Derived move(std::move(*this)); |
52 | // See comments above about slicing. |
53 | move.fMacros.unit = unit; |
54 | return move; |
55 | } |
56 | |
57 | template<typename Derived> |
58 | Derived NumberFormatterSettings<Derived>::adoptUnit(icu::MeasureUnit* unit) const& { |
59 | Derived copy(*this); |
60 | // Just move the unit into the MacroProps by value, and delete it since we have ownership. |
61 | // NOTE: Slicing occurs here. However, CurrencyUnit can be restored from MeasureUnit. |
62 | // TimeUnit may be affected, but TimeUnit is not as relevant to number formatting. |
63 | if (unit != nullptr) { |
64 | // TODO: On nullptr, reset to default value? |
65 | copy.fMacros.unit = std::move(*unit); |
66 | delete unit; |
67 | } |
68 | return copy; |
69 | } |
70 | |
71 | template<typename Derived> |
72 | Derived NumberFormatterSettings<Derived>::adoptUnit(icu::MeasureUnit* unit)&& { |
73 | Derived move(std::move(*this)); |
74 | // See comments above about slicing and ownership. |
75 | if (unit != nullptr) { |
76 | // TODO: On nullptr, reset to default value? |
77 | move.fMacros.unit = std::move(*unit); |
78 | delete unit; |
79 | } |
80 | return move; |
81 | } |
82 | |
83 | template<typename Derived> |
84 | Derived NumberFormatterSettings<Derived>::perUnit(const icu::MeasureUnit& perUnit) const& { |
85 | Derived copy(*this); |
86 | // See comments above about slicing. |
87 | copy.fMacros.perUnit = perUnit; |
88 | return copy; |
89 | } |
90 | |
91 | template<typename Derived> |
92 | Derived NumberFormatterSettings<Derived>::perUnit(const icu::MeasureUnit& perUnit)&& { |
93 | Derived move(std::move(*this)); |
94 | // See comments above about slicing. |
95 | move.fMacros.perUnit = perUnit; |
96 | return move; |
97 | } |
98 | |
99 | template<typename Derived> |
100 | Derived NumberFormatterSettings<Derived>::adoptPerUnit(icu::MeasureUnit* perUnit) const& { |
101 | Derived copy(*this); |
102 | // See comments above about slicing and ownership. |
103 | if (perUnit != nullptr) { |
104 | // TODO: On nullptr, reset to default value? |
105 | copy.fMacros.perUnit = std::move(*perUnit); |
106 | delete perUnit; |
107 | } |
108 | return copy; |
109 | } |
110 | |
111 | template<typename Derived> |
112 | Derived NumberFormatterSettings<Derived>::adoptPerUnit(icu::MeasureUnit* perUnit)&& { |
113 | Derived move(std::move(*this)); |
114 | // See comments above about slicing and ownership. |
115 | if (perUnit != nullptr) { |
116 | // TODO: On nullptr, reset to default value? |
117 | move.fMacros.perUnit = std::move(*perUnit); |
118 | delete perUnit; |
119 | } |
120 | return move; |
121 | } |
122 | |
123 | template<typename Derived> |
124 | Derived NumberFormatterSettings<Derived>::precision(const Precision& precision) const& { |
125 | Derived copy(*this); |
126 | // NOTE: Slicing is OK. |
127 | copy.fMacros.precision = precision; |
128 | return copy; |
129 | } |
130 | |
131 | template<typename Derived> |
132 | Derived NumberFormatterSettings<Derived>::precision(const Precision& precision)&& { |
133 | Derived move(std::move(*this)); |
134 | // NOTE: Slicing is OK. |
135 | move.fMacros.precision = precision; |
136 | return move; |
137 | } |
138 | |
139 | template<typename Derived> |
140 | Derived NumberFormatterSettings<Derived>::roundingMode(UNumberFormatRoundingMode roundingMode) const& { |
141 | Derived copy(*this); |
142 | copy.fMacros.roundingMode = roundingMode; |
143 | return copy; |
144 | } |
145 | |
146 | template<typename Derived> |
147 | Derived NumberFormatterSettings<Derived>::roundingMode(UNumberFormatRoundingMode roundingMode)&& { |
148 | Derived move(std::move(*this)); |
149 | move.fMacros.roundingMode = roundingMode; |
150 | return move; |
151 | } |
152 | |
153 | template<typename Derived> |
154 | Derived NumberFormatterSettings<Derived>::grouping(UNumberGroupingStrategy strategy) const& { |
155 | Derived copy(*this); |
156 | // NOTE: This is slightly different than how the setting is stored in Java |
157 | // because we want to put it on the stack. |
158 | copy.fMacros.grouper = Grouper::forStrategy(strategy); |
159 | return copy; |
160 | } |
161 | |
162 | template<typename Derived> |
163 | Derived NumberFormatterSettings<Derived>::grouping(UNumberGroupingStrategy strategy)&& { |
164 | Derived move(std::move(*this)); |
165 | move.fMacros.grouper = Grouper::forStrategy(strategy); |
166 | return move; |
167 | } |
168 | |
169 | template<typename Derived> |
170 | Derived NumberFormatterSettings<Derived>::integerWidth(const IntegerWidth& style) const& { |
171 | Derived copy(*this); |
172 | copy.fMacros.integerWidth = style; |
173 | return copy; |
174 | } |
175 | |
176 | template<typename Derived> |
177 | Derived NumberFormatterSettings<Derived>::integerWidth(const IntegerWidth& style)&& { |
178 | Derived move(std::move(*this)); |
179 | move.fMacros.integerWidth = style; |
180 | return move; |
181 | } |
182 | |
183 | template<typename Derived> |
184 | Derived NumberFormatterSettings<Derived>::symbols(const DecimalFormatSymbols& symbols) const& { |
185 | Derived copy(*this); |
186 | copy.fMacros.symbols.setTo(symbols); |
187 | return copy; |
188 | } |
189 | |
190 | template<typename Derived> |
191 | Derived NumberFormatterSettings<Derived>::symbols(const DecimalFormatSymbols& symbols)&& { |
192 | Derived move(std::move(*this)); |
193 | move.fMacros.symbols.setTo(symbols); |
194 | return move; |
195 | } |
196 | |
197 | template<typename Derived> |
198 | Derived NumberFormatterSettings<Derived>::adoptSymbols(NumberingSystem* ns) const& { |
199 | Derived copy(*this); |
200 | copy.fMacros.symbols.setTo(ns); |
201 | return copy; |
202 | } |
203 | |
204 | template<typename Derived> |
205 | Derived NumberFormatterSettings<Derived>::adoptSymbols(NumberingSystem* ns)&& { |
206 | Derived move(std::move(*this)); |
207 | move.fMacros.symbols.setTo(ns); |
208 | return move; |
209 | } |
210 | |
211 | template<typename Derived> |
212 | Derived NumberFormatterSettings<Derived>::unitWidth(UNumberUnitWidth width) const& { |
213 | Derived copy(*this); |
214 | copy.fMacros.unitWidth = width; |
215 | return copy; |
216 | } |
217 | |
218 | template<typename Derived> |
219 | Derived NumberFormatterSettings<Derived>::unitWidth(UNumberUnitWidth width)&& { |
220 | Derived move(std::move(*this)); |
221 | move.fMacros.unitWidth = width; |
222 | return move; |
223 | } |
224 | |
225 | template<typename Derived> |
226 | Derived NumberFormatterSettings<Derived>::sign(UNumberSignDisplay style) const& { |
227 | Derived copy(*this); |
228 | copy.fMacros.sign = style; |
229 | return copy; |
230 | } |
231 | |
232 | template<typename Derived> |
233 | Derived NumberFormatterSettings<Derived>::sign(UNumberSignDisplay style)&& { |
234 | Derived move(std::move(*this)); |
235 | move.fMacros.sign = style; |
236 | return move; |
237 | } |
238 | |
239 | template<typename Derived> |
240 | Derived NumberFormatterSettings<Derived>::decimal(UNumberDecimalSeparatorDisplay style) const& { |
241 | Derived copy(*this); |
242 | copy.fMacros.decimal = style; |
243 | return copy; |
244 | } |
245 | |
246 | template<typename Derived> |
247 | Derived NumberFormatterSettings<Derived>::decimal(UNumberDecimalSeparatorDisplay style)&& { |
248 | Derived move(std::move(*this)); |
249 | move.fMacros.decimal = style; |
250 | return move; |
251 | } |
252 | |
253 | template<typename Derived> |
254 | Derived NumberFormatterSettings<Derived>::scale(const Scale& scale) const& { |
255 | Derived copy(*this); |
256 | copy.fMacros.scale = scale; |
257 | return copy; |
258 | } |
259 | |
260 | template<typename Derived> |
261 | Derived NumberFormatterSettings<Derived>::scale(const Scale& scale)&& { |
262 | Derived move(std::move(*this)); |
263 | move.fMacros.scale = scale; |
264 | return move; |
265 | } |
266 | |
267 | template<typename Derived> |
268 | Derived NumberFormatterSettings<Derived>::padding(const Padder& padder) const& { |
269 | Derived copy(*this); |
270 | copy.fMacros.padder = padder; |
271 | return copy; |
272 | } |
273 | |
274 | template<typename Derived> |
275 | Derived NumberFormatterSettings<Derived>::padding(const Padder& padder)&& { |
276 | Derived move(std::move(*this)); |
277 | move.fMacros.padder = padder; |
278 | return move; |
279 | } |
280 | |
281 | template<typename Derived> |
282 | Derived NumberFormatterSettings<Derived>::threshold(int32_t threshold) const& { |
283 | Derived copy(*this); |
284 | copy.fMacros.threshold = threshold; |
285 | return copy; |
286 | } |
287 | |
288 | template<typename Derived> |
289 | Derived NumberFormatterSettings<Derived>::threshold(int32_t threshold)&& { |
290 | Derived move(std::move(*this)); |
291 | move.fMacros.threshold = threshold; |
292 | return move; |
293 | } |
294 | |
295 | template<typename Derived> |
296 | Derived NumberFormatterSettings<Derived>::macros(const impl::MacroProps& macros) const& { |
297 | Derived copy(*this); |
298 | copy.fMacros = macros; |
299 | return copy; |
300 | } |
301 | |
302 | template<typename Derived> |
303 | Derived NumberFormatterSettings<Derived>::macros(const impl::MacroProps& macros)&& { |
304 | Derived move(std::move(*this)); |
305 | move.fMacros = macros; |
306 | return move; |
307 | } |
308 | |
309 | template<typename Derived> |
310 | Derived NumberFormatterSettings<Derived>::macros(impl::MacroProps&& macros) const& { |
311 | Derived copy(*this); |
312 | copy.fMacros = std::move(macros); |
313 | return copy; |
314 | } |
315 | |
316 | template<typename Derived> |
317 | Derived NumberFormatterSettings<Derived>::macros(impl::MacroProps&& macros)&& { |
318 | Derived move(std::move(*this)); |
319 | move.fMacros = std::move(macros); |
320 | return move; |
321 | } |
322 | |
323 | template<typename Derived> |
324 | UnicodeString NumberFormatterSettings<Derived>::toSkeleton(UErrorCode& status) const { |
325 | if (U_FAILURE(status)) { |
326 | return ICU_Utility::makeBogusString(); |
327 | } |
328 | if (fMacros.copyErrorTo(status)) { |
329 | return ICU_Utility::makeBogusString(); |
330 | } |
331 | return skeleton::generate(fMacros, status); |
332 | } |
333 | |
334 | template<typename Derived> |
335 | LocalPointer<Derived> NumberFormatterSettings<Derived>::clone() const & { |
336 | return LocalPointer<Derived>(new Derived(*this)); |
337 | } |
338 | |
339 | template<typename Derived> |
340 | LocalPointer<Derived> NumberFormatterSettings<Derived>::clone() && { |
341 | return LocalPointer<Derived>(new Derived(std::move(*this))); |
342 | } |
343 | |
344 | // Declare all classes that implement NumberFormatterSettings |
345 | // See https://stackoverflow.com/a/495056/1407170 |
346 | template |
347 | class icu::number::NumberFormatterSettings<icu::number::UnlocalizedNumberFormatter>; |
348 | template |
349 | class icu::number::NumberFormatterSettings<icu::number::LocalizedNumberFormatter>; |
350 | |
351 | |
352 | UnlocalizedNumberFormatter NumberFormatter::with() { |
353 | UnlocalizedNumberFormatter result; |
354 | return result; |
355 | } |
356 | |
357 | LocalizedNumberFormatter NumberFormatter::withLocale(const Locale& locale) { |
358 | return with().locale(locale); |
359 | } |
360 | |
361 | UnlocalizedNumberFormatter |
362 | NumberFormatter::forSkeleton(const UnicodeString& skeleton, UErrorCode& status) { |
363 | return skeleton::create(skeleton, nullptr, status); |
364 | } |
365 | |
366 | UnlocalizedNumberFormatter |
367 | NumberFormatter::forSkeleton(const UnicodeString& skeleton, UParseError& perror, UErrorCode& status) { |
368 | return skeleton::create(skeleton, &perror, status); |
369 | } |
370 | |
371 | |
372 | template<typename T> using NFS = NumberFormatterSettings<T>; |
373 | using LNF = LocalizedNumberFormatter; |
374 | using UNF = UnlocalizedNumberFormatter; |
375 | |
376 | UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(const UNF& other) |
377 | : UNF(static_cast<const NFS<UNF>&>(other)) {} |
378 | |
379 | UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(const NFS<UNF>& other) |
380 | : NFS<UNF>(other) { |
381 | // No additional fields to assign |
382 | } |
383 | |
384 | // Make default copy constructor call the NumberFormatterSettings copy constructor. |
385 | UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(UNF&& src) U_NOEXCEPT |
386 | : UNF(static_cast<NFS<UNF>&&>(src)) {} |
387 | |
388 | UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(NFS<UNF>&& src) U_NOEXCEPT |
389 | : NFS<UNF>(std::move(src)) { |
390 | // No additional fields to assign |
391 | } |
392 | |
393 | UnlocalizedNumberFormatter& UnlocalizedNumberFormatter::operator=(const UNF& other) { |
394 | NFS<UNF>::operator=(static_cast<const NFS<UNF>&>(other)); |
395 | // No additional fields to assign |
396 | return *this; |
397 | } |
398 | |
399 | UnlocalizedNumberFormatter& UnlocalizedNumberFormatter::operator=(UNF&& src) U_NOEXCEPT { |
400 | NFS<UNF>::operator=(static_cast<NFS<UNF>&&>(src)); |
401 | // No additional fields to assign |
402 | return *this; |
403 | } |
404 | |
405 | // Make default copy constructor call the NumberFormatterSettings copy constructor. |
406 | LocalizedNumberFormatter::LocalizedNumberFormatter(const LNF& other) |
407 | : LNF(static_cast<const NFS<LNF>&>(other)) {} |
408 | |
409 | LocalizedNumberFormatter::LocalizedNumberFormatter(const NFS<LNF>& other) |
410 | : NFS<LNF>(other) { |
411 | // No additional fields to assign (let call count and compiled formatter reset to defaults) |
412 | } |
413 | |
414 | LocalizedNumberFormatter::LocalizedNumberFormatter(LocalizedNumberFormatter&& src) U_NOEXCEPT |
415 | : LNF(static_cast<NFS<LNF>&&>(src)) {} |
416 | |
417 | LocalizedNumberFormatter::LocalizedNumberFormatter(NFS<LNF>&& src) U_NOEXCEPT |
418 | : NFS<LNF>(std::move(src)) { |
419 | // For the move operators, copy over the compiled formatter. |
420 | // Note: if the formatter is not compiled, call count information is lost. |
421 | if (static_cast<LNF&&>(src).fCompiled != nullptr) { |
422 | lnfMoveHelper(static_cast<LNF&&>(src)); |
423 | } |
424 | } |
425 | |
426 | LocalizedNumberFormatter& LocalizedNumberFormatter::operator=(const LNF& other) { |
427 | NFS<LNF>::operator=(static_cast<const NFS<LNF>&>(other)); |
428 | // Reset to default values. |
429 | clear(); |
430 | return *this; |
431 | } |
432 | |
433 | LocalizedNumberFormatter& LocalizedNumberFormatter::operator=(LNF&& src) U_NOEXCEPT { |
434 | NFS<LNF>::operator=(static_cast<NFS<LNF>&&>(src)); |
435 | // For the move operators, copy over the compiled formatter. |
436 | // Note: if the formatter is not compiled, call count information is lost. |
437 | if (static_cast<LNF&&>(src).fCompiled != nullptr) { |
438 | // Formatter is compiled |
439 | lnfMoveHelper(static_cast<LNF&&>(src)); |
440 | } else { |
441 | clear(); |
442 | } |
443 | return *this; |
444 | } |
445 | |
446 | void LocalizedNumberFormatter::clear() { |
447 | // Reset to default values. |
448 | auto* callCount = reinterpret_cast<u_atomic_int32_t*>(fUnsafeCallCount); |
449 | umtx_storeRelease(*callCount, 0); |
450 | delete fCompiled; |
451 | fCompiled = nullptr; |
452 | } |
453 | |
454 | void LocalizedNumberFormatter::lnfMoveHelper(LNF&& src) { |
455 | // Copy over the compiled formatter and set call count to INT32_MIN as in computeCompiled(). |
456 | // Don't copy the call count directly because doing so requires a loadAcquire/storeRelease. |
457 | // The bits themselves appear to be platform-dependent, so copying them might not be safe. |
458 | auto* callCount = reinterpret_cast<u_atomic_int32_t*>(fUnsafeCallCount); |
459 | umtx_storeRelease(*callCount, INT32_MIN); |
460 | delete fCompiled; |
461 | fCompiled = src.fCompiled; |
462 | // Reset the source object to leave it in a safe state. |
463 | auto* srcCallCount = reinterpret_cast<u_atomic_int32_t*>(src.fUnsafeCallCount); |
464 | umtx_storeRelease(*srcCallCount, 0); |
465 | src.fCompiled = nullptr; |
466 | } |
467 | |
468 | |
469 | LocalizedNumberFormatter::~LocalizedNumberFormatter() { |
470 | delete fCompiled; |
471 | } |
472 | |
473 | LocalizedNumberFormatter::LocalizedNumberFormatter(const MacroProps& macros, const Locale& locale) { |
474 | fMacros = macros; |
475 | fMacros.locale = locale; |
476 | } |
477 | |
478 | LocalizedNumberFormatter::LocalizedNumberFormatter(MacroProps&& macros, const Locale& locale) { |
479 | fMacros = std::move(macros); |
480 | fMacros.locale = locale; |
481 | } |
482 | |
483 | LocalizedNumberFormatter UnlocalizedNumberFormatter::locale(const Locale& locale) const& { |
484 | return LocalizedNumberFormatter(fMacros, locale); |
485 | } |
486 | |
487 | LocalizedNumberFormatter UnlocalizedNumberFormatter::locale(const Locale& locale)&& { |
488 | return LocalizedNumberFormatter(std::move(fMacros), locale); |
489 | } |
490 | |
491 | SymbolsWrapper::SymbolsWrapper(const SymbolsWrapper& other) { |
492 | doCopyFrom(other); |
493 | } |
494 | |
495 | SymbolsWrapper::SymbolsWrapper(SymbolsWrapper&& src) U_NOEXCEPT { |
496 | doMoveFrom(std::move(src)); |
497 | } |
498 | |
499 | SymbolsWrapper& SymbolsWrapper::operator=(const SymbolsWrapper& other) { |
500 | if (this == &other) { |
501 | return *this; |
502 | } |
503 | doCleanup(); |
504 | doCopyFrom(other); |
505 | return *this; |
506 | } |
507 | |
508 | SymbolsWrapper& SymbolsWrapper::operator=(SymbolsWrapper&& src) U_NOEXCEPT { |
509 | if (this == &src) { |
510 | return *this; |
511 | } |
512 | doCleanup(); |
513 | doMoveFrom(std::move(src)); |
514 | return *this; |
515 | } |
516 | |
517 | SymbolsWrapper::~SymbolsWrapper() { |
518 | doCleanup(); |
519 | } |
520 | |
521 | void SymbolsWrapper::setTo(const DecimalFormatSymbols& dfs) { |
522 | doCleanup(); |
523 | fType = SYMPTR_DFS; |
524 | fPtr.dfs = new DecimalFormatSymbols(dfs); |
525 | } |
526 | |
527 | void SymbolsWrapper::setTo(const NumberingSystem* ns) { |
528 | doCleanup(); |
529 | fType = SYMPTR_NS; |
530 | fPtr.ns = ns; |
531 | } |
532 | |
533 | void SymbolsWrapper::doCopyFrom(const SymbolsWrapper& other) { |
534 | fType = other.fType; |
535 | switch (fType) { |
536 | case SYMPTR_NONE: |
537 | // No action necessary |
538 | break; |
539 | case SYMPTR_DFS: |
540 | // Memory allocation failures are exposed in copyErrorTo() |
541 | if (other.fPtr.dfs != nullptr) { |
542 | fPtr.dfs = new DecimalFormatSymbols(*other.fPtr.dfs); |
543 | } else { |
544 | fPtr.dfs = nullptr; |
545 | } |
546 | break; |
547 | case SYMPTR_NS: |
548 | // Memory allocation failures are exposed in copyErrorTo() |
549 | if (other.fPtr.ns != nullptr) { |
550 | fPtr.ns = new NumberingSystem(*other.fPtr.ns); |
551 | } else { |
552 | fPtr.ns = nullptr; |
553 | } |
554 | break; |
555 | } |
556 | } |
557 | |
558 | void SymbolsWrapper::doMoveFrom(SymbolsWrapper&& src) { |
559 | fType = src.fType; |
560 | switch (fType) { |
561 | case SYMPTR_NONE: |
562 | // No action necessary |
563 | break; |
564 | case SYMPTR_DFS: |
565 | fPtr.dfs = src.fPtr.dfs; |
566 | src.fPtr.dfs = nullptr; |
567 | break; |
568 | case SYMPTR_NS: |
569 | fPtr.ns = src.fPtr.ns; |
570 | src.fPtr.ns = nullptr; |
571 | break; |
572 | } |
573 | } |
574 | |
575 | void SymbolsWrapper::doCleanup() { |
576 | switch (fType) { |
577 | case SYMPTR_NONE: |
578 | // No action necessary |
579 | break; |
580 | case SYMPTR_DFS: |
581 | delete fPtr.dfs; |
582 | break; |
583 | case SYMPTR_NS: |
584 | delete fPtr.ns; |
585 | break; |
586 | } |
587 | } |
588 | |
589 | bool SymbolsWrapper::isDecimalFormatSymbols() const { |
590 | return fType == SYMPTR_DFS; |
591 | } |
592 | |
593 | bool SymbolsWrapper::isNumberingSystem() const { |
594 | return fType == SYMPTR_NS; |
595 | } |
596 | |
597 | const DecimalFormatSymbols* SymbolsWrapper::getDecimalFormatSymbols() const { |
598 | U_ASSERT(fType == SYMPTR_DFS); |
599 | return fPtr.dfs; |
600 | } |
601 | |
602 | const NumberingSystem* SymbolsWrapper::getNumberingSystem() const { |
603 | U_ASSERT(fType == SYMPTR_NS); |
604 | return fPtr.ns; |
605 | } |
606 | |
607 | |
608 | FormattedNumber LocalizedNumberFormatter::formatInt(int64_t value, UErrorCode& status) const { |
609 | if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); } |
610 | auto results = new UFormattedNumberData(); |
611 | if (results == nullptr) { |
612 | status = U_MEMORY_ALLOCATION_ERROR; |
613 | return FormattedNumber(status); |
614 | } |
615 | results->quantity.setToLong(value); |
616 | formatImpl(results, status); |
617 | |
618 | // Do not save the results object if we encountered a failure. |
619 | if (U_SUCCESS(status)) { |
620 | return FormattedNumber(results); |
621 | } else { |
622 | delete results; |
623 | return FormattedNumber(status); |
624 | } |
625 | } |
626 | |
627 | FormattedNumber LocalizedNumberFormatter::formatDouble(double value, UErrorCode& status) const { |
628 | if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); } |
629 | auto results = new UFormattedNumberData(); |
630 | if (results == nullptr) { |
631 | status = U_MEMORY_ALLOCATION_ERROR; |
632 | return FormattedNumber(status); |
633 | } |
634 | results->quantity.setToDouble(value); |
635 | formatImpl(results, status); |
636 | |
637 | // Do not save the results object if we encountered a failure. |
638 | if (U_SUCCESS(status)) { |
639 | return FormattedNumber(results); |
640 | } else { |
641 | delete results; |
642 | return FormattedNumber(status); |
643 | } |
644 | } |
645 | |
646 | FormattedNumber LocalizedNumberFormatter::formatDecimal(StringPiece value, UErrorCode& status) const { |
647 | if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); } |
648 | auto results = new UFormattedNumberData(); |
649 | if (results == nullptr) { |
650 | status = U_MEMORY_ALLOCATION_ERROR; |
651 | return FormattedNumber(status); |
652 | } |
653 | results->quantity.setToDecNumber(value, status); |
654 | formatImpl(results, status); |
655 | |
656 | // Do not save the results object if we encountered a failure. |
657 | if (U_SUCCESS(status)) { |
658 | return FormattedNumber(results); |
659 | } else { |
660 | delete results; |
661 | return FormattedNumber(status); |
662 | } |
663 | } |
664 | |
665 | FormattedNumber |
666 | LocalizedNumberFormatter::formatDecimalQuantity(const DecimalQuantity& dq, UErrorCode& status) const { |
667 | if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); } |
668 | auto results = new UFormattedNumberData(); |
669 | if (results == nullptr) { |
670 | status = U_MEMORY_ALLOCATION_ERROR; |
671 | return FormattedNumber(status); |
672 | } |
673 | results->quantity = dq; |
674 | formatImpl(results, status); |
675 | |
676 | // Do not save the results object if we encountered a failure. |
677 | if (U_SUCCESS(status)) { |
678 | return FormattedNumber(results); |
679 | } else { |
680 | delete results; |
681 | return FormattedNumber(status); |
682 | } |
683 | } |
684 | |
685 | void LocalizedNumberFormatter::formatImpl(impl::UFormattedNumberData* results, UErrorCode& status) const { |
686 | if (computeCompiled(status)) { |
687 | fCompiled->format(results->quantity, results->getStringRef(), status); |
688 | } else { |
689 | NumberFormatterImpl::formatStatic(fMacros, results->quantity, results->getStringRef(), status); |
690 | } |
691 | if (U_FAILURE(status)) { |
692 | return; |
693 | } |
694 | results->getStringRef().writeTerminator(status); |
695 | } |
696 | |
697 | void LocalizedNumberFormatter::getAffixImpl(bool isPrefix, bool isNegative, UnicodeString& result, |
698 | UErrorCode& status) const { |
699 | FormattedStringBuilder string; |
700 | auto signum = static_cast<Signum>(isNegative ? SIGNUM_NEG : SIGNUM_POS); |
701 | // Always return affixes for plural form OTHER. |
702 | static const StandardPlural::Form plural = StandardPlural::OTHER; |
703 | int32_t prefixLength; |
704 | if (computeCompiled(status)) { |
705 | prefixLength = fCompiled->getPrefixSuffix(signum, plural, string, status); |
706 | } else { |
707 | prefixLength = NumberFormatterImpl::getPrefixSuffixStatic(fMacros, signum, plural, string, status); |
708 | } |
709 | result.remove(); |
710 | if (isPrefix) { |
711 | result.append(string.toTempUnicodeString().tempSubStringBetween(0, prefixLength)); |
712 | } else { |
713 | result.append(string.toTempUnicodeString().tempSubStringBetween(prefixLength, string.length())); |
714 | } |
715 | } |
716 | |
717 | bool LocalizedNumberFormatter::computeCompiled(UErrorCode& status) const { |
718 | // fUnsafeCallCount contains memory to be interpreted as an atomic int, most commonly |
719 | // std::atomic<int32_t>. Since the type of atomic int is platform-dependent, we cast the |
720 | // bytes in fUnsafeCallCount to u_atomic_int32_t, a typedef for the platform-dependent |
721 | // atomic int type defined in umutex.h. |
722 | static_assert( |
723 | sizeof(u_atomic_int32_t) <= sizeof(fUnsafeCallCount), |
724 | "Atomic integer size on this platform exceeds the size allocated by fUnsafeCallCount" ); |
725 | auto* callCount = reinterpret_cast<u_atomic_int32_t*>( |
726 | const_cast<LocalizedNumberFormatter*>(this)->fUnsafeCallCount); |
727 | |
728 | // A positive value in the atomic int indicates that the data structure is not yet ready; |
729 | // a negative value indicates that it is ready. If, after the increment, the atomic int |
730 | // is exactly threshold, then it is the current thread's job to build the data structure. |
731 | // Note: We set the callCount to INT32_MIN so that if another thread proceeds to increment |
732 | // the atomic int, the value remains below zero. |
733 | int32_t currentCount = umtx_loadAcquire(*callCount); |
734 | if (0 <= currentCount && currentCount <= fMacros.threshold && fMacros.threshold > 0) { |
735 | currentCount = umtx_atomic_inc(callCount); |
736 | } |
737 | |
738 | if (currentCount == fMacros.threshold && fMacros.threshold > 0) { |
739 | // Build the data structure and then use it (slow to fast path). |
740 | const NumberFormatterImpl* compiled = new NumberFormatterImpl(fMacros, status); |
741 | if (compiled == nullptr) { |
742 | status = U_MEMORY_ALLOCATION_ERROR; |
743 | return false; |
744 | } |
745 | U_ASSERT(fCompiled == nullptr); |
746 | const_cast<LocalizedNumberFormatter*>(this)->fCompiled = compiled; |
747 | umtx_storeRelease(*callCount, INT32_MIN); |
748 | return true; |
749 | } else if (currentCount < 0) { |
750 | // The data structure is already built; use it (fast path). |
751 | U_ASSERT(fCompiled != nullptr); |
752 | return true; |
753 | } else { |
754 | // Format the number without building the data structure (slow path). |
755 | return false; |
756 | } |
757 | } |
758 | |
759 | const impl::NumberFormatterImpl* LocalizedNumberFormatter::getCompiled() const { |
760 | return fCompiled; |
761 | } |
762 | |
763 | int32_t LocalizedNumberFormatter::getCallCount() const { |
764 | auto* callCount = reinterpret_cast<u_atomic_int32_t*>( |
765 | const_cast<LocalizedNumberFormatter*>(this)->fUnsafeCallCount); |
766 | return umtx_loadAcquire(*callCount); |
767 | } |
768 | |
769 | Format* LocalizedNumberFormatter::toFormat(UErrorCode& status) const { |
770 | if (U_FAILURE(status)) { |
771 | return nullptr; |
772 | } |
773 | LocalPointer<LocalizedNumberFormatterAsFormat> retval( |
774 | new LocalizedNumberFormatterAsFormat(*this, fMacros.locale), status); |
775 | return retval.orphan(); |
776 | } |
777 | |
778 | |
779 | #endif /* #if !UCONFIG_NO_FORMATTING */ |
780 | |