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
->nextFieldPosition(fieldPosition
, status
);
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
->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 */