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 "fphdlimp.h"
13 #include "number_utypes.h"
14 #include "numparse_types.h"
15 #include "formattedval_impl.h"
16 #include "numrange_impl.h"
17 #include "number_decnum.h"
18 #include "unicode/numberrangeformatter.h"
19 #include "unicode/unumberrangeformatter.h"
20
21 using namespace icu;
22 using namespace icu::number;
23 using namespace icu::number::impl;
24
25
26 U_NAMESPACE_BEGIN
27 namespace number {
28 namespace impl {
29
30 /**
31 * Implementation class for UNumberRangeFormatter. Wraps a LocalizedRangeNumberFormatter.
32 */
33 struct UNumberRangeFormatterData : public UMemory,
34 // Magic number as ASCII == "NRF" (NumberRangeFormatter)
35 public IcuCApiHelper<UNumberRangeFormatter, UNumberRangeFormatterData, 0x4E524600> {
36 LocalizedNumberRangeFormatter fFormatter;
37 };
38
39 struct UFormattedNumberRangeImpl;
40
41 // Magic number as ASCII == "FDN" (FormatteDNumber)
42 typedef IcuCApiHelper<UFormattedNumberRange, UFormattedNumberRangeImpl, 0x46444E00> UFormattedNumberRangeApiHelper;
43
44 struct UFormattedNumberRangeImpl : public UFormattedValueImpl, public UFormattedNumberRangeApiHelper {
45 UFormattedNumberRangeImpl();
46 ~UFormattedNumberRangeImpl();
47
48 FormattedNumberRange fImpl;
49 UFormattedNumberRangeData fData;
50 };
51
UFormattedNumberRangeImpl()52 UFormattedNumberRangeImpl::UFormattedNumberRangeImpl()
53 : fImpl(&fData) {
54 fFormattedValue = &fImpl;
55 }
56
~UFormattedNumberRangeImpl()57 UFormattedNumberRangeImpl::~UFormattedNumberRangeImpl() {
58 // Disown the data from fImpl so it doesn't get deleted twice
59 fImpl.fData = nullptr;
60 }
61
62 } // namespace impl
63 } // namespace number
64 U_NAMESPACE_END
65
66
UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(UFormattedNumberRange,UFormattedNumberRangeImpl,UFormattedNumberRangeApiHelper,unumrf) const67 UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(
68 UFormattedNumberRange,
69 UFormattedNumberRangeImpl,
70 UFormattedNumberRangeApiHelper,
71 unumrf)
72
73
74 const UFormattedNumberRangeData* number::impl::validateUFormattedNumberRange(
75 const UFormattedNumberRange* uresult, UErrorCode& status) {
76 auto* result = UFormattedNumberRangeApiHelper::validate(uresult, status);
77 if (U_FAILURE(status)) {
78 return nullptr;
79 }
80 return &result->fData;
81 }
82
83
84 U_CAPI UNumberRangeFormatter* U_EXPORT2
unumrf_openForSkeletonWithCollapseAndIdentityFallback(const UChar * skeleton,int32_t skeletonLen,UNumberRangeCollapse collapse,UNumberRangeIdentityFallback identityFallback,const char * locale,UParseError * perror,UErrorCode * ec)85 unumrf_openForSkeletonWithCollapseAndIdentityFallback(
86 const UChar* skeleton,
87 int32_t skeletonLen,
88 UNumberRangeCollapse collapse,
89 UNumberRangeIdentityFallback identityFallback,
90 const char* locale,
91 UParseError* perror,
92 UErrorCode* ec) {
93 auto* impl = new UNumberRangeFormatterData();
94 if (impl == nullptr) {
95 *ec = U_MEMORY_ALLOCATION_ERROR;
96 return nullptr;
97 }
98 // Readonly-alias constructor (first argument is whether we are NUL-terminated)
99 UnicodeString skeletonString(skeletonLen == -1, skeleton, skeletonLen);
100 impl->fFormatter = NumberRangeFormatter::withLocale(locale)
101 .numberFormatterBoth(NumberFormatter::forSkeleton(skeletonString, *perror, *ec))
102 .collapse(collapse)
103 .identityFallback(identityFallback);
104 return impl->exportForC();
105 }
106
107 U_CAPI void U_EXPORT2
unumrf_formatDoubleRange(const UNumberRangeFormatter * uformatter,double first,double second,UFormattedNumberRange * uresult,UErrorCode * ec)108 unumrf_formatDoubleRange(
109 const UNumberRangeFormatter* uformatter,
110 double first,
111 double second,
112 UFormattedNumberRange* uresult,
113 UErrorCode* ec) {
114 const UNumberRangeFormatterData* formatter = UNumberRangeFormatterData::validate(uformatter, *ec);
115 auto* result = UFormattedNumberRangeApiHelper::validate(uresult, *ec);
116 if (U_FAILURE(*ec)) { return; }
117
118 result->fData.getStringRef().clear();
119 result->fData.quantity1.setToDouble(first);
120 result->fData.quantity2.setToDouble(second);
121 formatter->fFormatter.formatImpl(result->fData, first == second, *ec);
122 }
123
124 U_CAPI void U_EXPORT2
unumrf_formatDecimalRange(const UNumberRangeFormatter * uformatter,const char * first,int32_t firstLen,const char * second,int32_t secondLen,UFormattedNumberRange * uresult,UErrorCode * ec)125 unumrf_formatDecimalRange(
126 const UNumberRangeFormatter* uformatter,
127 const char* first, int32_t firstLen,
128 const char* second, int32_t secondLen,
129 UFormattedNumberRange* uresult,
130 UErrorCode* ec) {
131 const UNumberRangeFormatterData* formatter = UNumberRangeFormatterData::validate(uformatter, *ec);
132 auto* result = UFormattedNumberRangeApiHelper::validate(uresult, *ec);
133 if (U_FAILURE(*ec)) { return; }
134
135 result->fData.getStringRef().clear();
136 result->fData.quantity1.setToDecNumber({first, firstLen}, *ec);
137 result->fData.quantity2.setToDecNumber({second, secondLen}, *ec);
138 formatter->fFormatter.formatImpl(result->fData, first == second, *ec);
139 }
140
141 U_CAPI UNumberRangeIdentityResult U_EXPORT2
unumrf_resultGetIdentityResult(const UFormattedNumberRange * uresult,UErrorCode * ec)142 unumrf_resultGetIdentityResult(
143 const UFormattedNumberRange* uresult,
144 UErrorCode* ec) {
145 auto* result = UFormattedNumberRangeApiHelper::validate(uresult, *ec);
146 if (U_FAILURE(*ec)) {
147 return UNUM_IDENTITY_RESULT_COUNT;
148 }
149 return result->fData.identityResult;
150 }
151
152 U_CAPI int32_t U_EXPORT2
unumrf_resultGetFirstDecimalNumber(const UFormattedNumberRange * uresult,char * dest,int32_t destCapacity,UErrorCode * ec)153 unumrf_resultGetFirstDecimalNumber(
154 const UFormattedNumberRange* uresult,
155 char* dest,
156 int32_t destCapacity,
157 UErrorCode* ec) {
158 const auto* result = UFormattedNumberRangeApiHelper::validate(uresult, *ec);
159 if (U_FAILURE(*ec)) {
160 return 0;
161 }
162 DecNum decnum;
163 return result->fData.quantity1.toDecNum(decnum, *ec)
164 .toCharString(*ec)
165 .extract(dest, destCapacity, *ec);
166 }
167
168 U_CAPI int32_t U_EXPORT2
unumrf_resultGetSecondDecimalNumber(const UFormattedNumberRange * uresult,char * dest,int32_t destCapacity,UErrorCode * ec)169 unumrf_resultGetSecondDecimalNumber(
170 const UFormattedNumberRange* uresult,
171 char* dest,
172 int32_t destCapacity,
173 UErrorCode* ec) {
174 const auto* result = UFormattedNumberRangeApiHelper::validate(uresult, *ec);
175 if (U_FAILURE(*ec)) {
176 return 0;
177 }
178 DecNum decnum;
179 return result->fData.quantity2
180 .toDecNum(decnum, *ec)
181 .toCharString(*ec)
182 .extract(dest, destCapacity, *ec);
183 }
184
185 U_CAPI void U_EXPORT2
unumrf_close(UNumberRangeFormatter * f)186 unumrf_close(UNumberRangeFormatter* f) {
187 UErrorCode localStatus = U_ZERO_ERROR;
188 const UNumberRangeFormatterData* impl = UNumberRangeFormatterData::validate(f, localStatus);
189 delete impl;
190 }
191
192
193 #endif /* #if !UCONFIG_NO_FORMATTING */
194