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.resetString();
119 result->fData.quantity1.clear();
120 result->fData.quantity2.clear();
121 result->fData.quantity1.setToDouble(first);
122 result->fData.quantity2.setToDouble(second);
123 formatter->fFormatter.formatImpl(result->fData, first == second, *ec);
124 }
125
126 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)127 unumrf_formatDecimalRange(
128 const UNumberRangeFormatter* uformatter,
129 const char* first, int32_t firstLen,
130 const char* second, int32_t secondLen,
131 UFormattedNumberRange* uresult,
132 UErrorCode* ec) {
133 const UNumberRangeFormatterData* formatter = UNumberRangeFormatterData::validate(uformatter, *ec);
134 auto* result = UFormattedNumberRangeApiHelper::validate(uresult, *ec);
135 if (U_FAILURE(*ec)) { return; }
136
137 result->fData.resetString();
138 result->fData.quantity1.clear();
139 result->fData.quantity2.clear();
140 result->fData.quantity1.setToDecNumber({first, firstLen}, *ec);
141 result->fData.quantity2.setToDecNumber({second, secondLen}, *ec);
142 formatter->fFormatter.formatImpl(result->fData, first == second, *ec);
143 }
144
145 U_CAPI UNumberRangeIdentityResult U_EXPORT2
unumrf_resultGetIdentityResult(const UFormattedNumberRange * uresult,UErrorCode * ec)146 unumrf_resultGetIdentityResult(
147 const UFormattedNumberRange* uresult,
148 UErrorCode* ec) {
149 auto* result = UFormattedNumberRangeApiHelper::validate(uresult, *ec);
150 if (U_FAILURE(*ec)) {
151 return UNUM_IDENTITY_RESULT_COUNT;
152 }
153 return result->fData.identityResult;
154 }
155
156 U_CAPI int32_t U_EXPORT2
unumrf_resultGetFirstDecimalNumber(const UFormattedNumberRange * uresult,char * dest,int32_t destCapacity,UErrorCode * ec)157 unumrf_resultGetFirstDecimalNumber(
158 const UFormattedNumberRange* uresult,
159 char* dest,
160 int32_t destCapacity,
161 UErrorCode* ec) {
162 const auto* result = UFormattedNumberRangeApiHelper::validate(uresult, *ec);
163 if (U_FAILURE(*ec)) {
164 return 0;
165 }
166 DecNum decnum;
167 return result->fData.quantity1.toDecNum(decnum, *ec)
168 .toCharString(*ec)
169 .extract(dest, destCapacity, *ec);
170 }
171
172 U_CAPI int32_t U_EXPORT2
unumrf_resultGetSecondDecimalNumber(const UFormattedNumberRange * uresult,char * dest,int32_t destCapacity,UErrorCode * ec)173 unumrf_resultGetSecondDecimalNumber(
174 const UFormattedNumberRange* uresult,
175 char* dest,
176 int32_t destCapacity,
177 UErrorCode* ec) {
178 const auto* result = UFormattedNumberRangeApiHelper::validate(uresult, *ec);
179 if (U_FAILURE(*ec)) {
180 return 0;
181 }
182 DecNum decnum;
183 return result->fData.quantity2
184 .toDecNum(decnum, *ec)
185 .toCharString(*ec)
186 .extract(dest, destCapacity, *ec);
187 }
188
189 U_CAPI void U_EXPORT2
unumrf_close(UNumberRangeFormatter * f)190 unumrf_close(UNumberRangeFormatter* f) {
191 UErrorCode localStatus = U_ZERO_ERROR;
192 const UNumberRangeFormatterData* impl = UNumberRangeFormatterData::validate(f, localStatus);
193 delete impl;
194 }
195
196
197 #endif /* #if !UCONFIG_NO_FORMATTING */
198