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