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 "unicode/numberformatter.h"
17#include "unicode/unumberformatter.h"
18
19using namespace icu;
20using namespace icu::number;
21using namespace icu::number::impl;
22
23
24U_NAMESPACE_BEGIN
25namespace number {
26namespace impl {
27
28/**
29 * Implementation class for UNumberFormatter. Wraps a LocalizedNumberFormatter.
30 */
31struct UNumberFormatterData : public UMemory,
32 // Magic number as ASCII == "NFR" (NumberFormatteR)
33 public IcuCApiHelper<UNumberFormatter, UNumberFormatterData, 0x4E465200> {
34 LocalizedNumberFormatter fFormatter;
35};
36
37struct UFormattedNumberImpl;
38
39// Magic number as ASCII == "FDN" (FormatteDNumber)
40typedef IcuCApiHelper<UFormattedNumber, UFormattedNumberImpl, 0x46444E00> UFormattedNumberApiHelper;
41
42struct UFormattedNumberImpl : public UFormattedValueImpl, public UFormattedNumberApiHelper {
43 UFormattedNumberImpl();
44 ~UFormattedNumberImpl();
45
46 FormattedNumber fImpl;
47 UFormattedNumberData fData;
48};
49
50UFormattedNumberImpl::UFormattedNumberImpl()
51 : fImpl(&fData) {
52 fFormattedValue = &fImpl;
53}
54
55UFormattedNumberImpl::~UFormattedNumberImpl() {
56 // Disown the data from fImpl so it doesn't get deleted twice
57 fImpl.fData = nullptr;
58}
59
60}
61}
62U_NAMESPACE_END
63
64
65UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(
66 UFormattedNumber,
67 UFormattedNumberImpl,
68 UFormattedNumberApiHelper,
69 unumf)
70
71
72const DecimalQuantity* icu::number::impl::validateUFormattedNumberToDecimalQuantity(
73 const UFormattedNumber* uresult, UErrorCode& status) {
74 auto* result = UFormattedNumberApiHelper::validate(uresult, status);
75 if (U_FAILURE(status)) {
76 return nullptr;
77 }
78 return &result->fData.quantity;
79}
80
81
82
83U_CAPI UNumberFormatter* U_EXPORT2
84unumf_openForSkeletonAndLocale(const UChar* skeleton, int32_t skeletonLen, const char* locale,
85 UErrorCode* ec) {
86 auto* impl = new UNumberFormatterData();
87 if (impl == nullptr) {
88 *ec = U_MEMORY_ALLOCATION_ERROR;
89 return nullptr;
90 }
91 // Readonly-alias constructor (first argument is whether we are NUL-terminated)
92 UnicodeString skeletonString(skeletonLen == -1, skeleton, skeletonLen);
93 impl->fFormatter = NumberFormatter::forSkeleton(skeletonString, *ec).locale(locale);
94 return impl->exportForC();
95}
96
97U_CAPI UNumberFormatter* U_EXPORT2
98unumf_openForSkeletonAndLocaleWithError(const UChar* skeleton, int32_t skeletonLen, const char* locale,
99 UParseError* perror, UErrorCode* ec) {
100 auto* impl = new UNumberFormatterData();
101 if (impl == nullptr) {
102 *ec = U_MEMORY_ALLOCATION_ERROR;
103 return nullptr;
104 }
105 // Readonly-alias constructor (first argument is whether we are NUL-terminated)
106 UnicodeString skeletonString(skeletonLen == -1, skeleton, skeletonLen);
107 impl->fFormatter = NumberFormatter::forSkeleton(skeletonString, *perror, *ec).locale(locale);
108 return impl->exportForC();
109}
110
111U_CAPI void U_EXPORT2
112unumf_formatInt(const UNumberFormatter* uformatter, int64_t value, UFormattedNumber* uresult,
113 UErrorCode* ec) {
114 const UNumberFormatterData* formatter = UNumberFormatterData::validate(uformatter, *ec);
115 auto* result = UFormattedNumberApiHelper::validate(uresult, *ec);
116 if (U_FAILURE(*ec)) { return; }
117
118 result->fData.getStringRef().clear();
119 result->fData.quantity.setToLong(value);
120 formatter->fFormatter.formatImpl(&result->fData, *ec);
121}
122
123U_CAPI void U_EXPORT2
124unumf_formatDouble(const UNumberFormatter* uformatter, double value, UFormattedNumber* uresult,
125 UErrorCode* ec) {
126 const UNumberFormatterData* formatter = UNumberFormatterData::validate(uformatter, *ec);
127 auto* result = UFormattedNumberApiHelper::validate(uresult, *ec);
128 if (U_FAILURE(*ec)) { return; }
129
130 result->fData.getStringRef().clear();
131 result->fData.quantity.setToDouble(value);
132 formatter->fFormatter.formatImpl(&result->fData, *ec);
133}
134
135U_CAPI void U_EXPORT2
136unumf_formatDecimal(const UNumberFormatter* uformatter, const char* value, int32_t valueLen,
137 UFormattedNumber* uresult, UErrorCode* ec) {
138 const UNumberFormatterData* formatter = UNumberFormatterData::validate(uformatter, *ec);
139 auto* result = UFormattedNumberApiHelper::validate(uresult, *ec);
140 if (U_FAILURE(*ec)) { return; }
141
142 result->fData.getStringRef().clear();
143 result->fData.quantity.setToDecNumber({value, valueLen}, *ec);
144 if (U_FAILURE(*ec)) { return; }
145 formatter->fFormatter.formatImpl(&result->fData, *ec);
146}
147
148U_CAPI int32_t U_EXPORT2
149unumf_resultToString(const UFormattedNumber* uresult, UChar* buffer, int32_t bufferCapacity,
150 UErrorCode* ec) {
151 const auto* result = UFormattedNumberApiHelper::validate(uresult, *ec);
152 if (U_FAILURE(*ec)) { return 0; }
153
154 if (buffer == nullptr ? bufferCapacity != 0 : bufferCapacity < 0) {
155 *ec = U_ILLEGAL_ARGUMENT_ERROR;
156 return 0;
157 }
158
159 return result->fImpl.toTempString(*ec).extract(buffer, bufferCapacity, *ec);
160}
161
162U_CAPI UBool U_EXPORT2
163unumf_resultNextFieldPosition(const UFormattedNumber* uresult, UFieldPosition* ufpos, UErrorCode* ec) {
164 const auto* result = UFormattedNumberApiHelper::validate(uresult, *ec);
165 if (U_FAILURE(*ec)) { return FALSE; }
166
167 if (ufpos == nullptr) {
168 *ec = U_ILLEGAL_ARGUMENT_ERROR;
169 return FALSE;
170 }
171
172 FieldPosition fp;
173 fp.setField(ufpos->field);
174 fp.setBeginIndex(ufpos->beginIndex);
175 fp.setEndIndex(ufpos->endIndex);
176 bool retval = result->fImpl.nextFieldPosition(fp, *ec);
177 ufpos->beginIndex = fp.getBeginIndex();
178 ufpos->endIndex = fp.getEndIndex();
179 // NOTE: MSVC sometimes complains when implicitly converting between bool and UBool
180 return retval ? TRUE : FALSE;
181}
182
183U_CAPI void U_EXPORT2
184unumf_resultGetAllFieldPositions(const UFormattedNumber* uresult, UFieldPositionIterator* ufpositer,
185 UErrorCode* ec) {
186 const auto* result = UFormattedNumberApiHelper::validate(uresult, *ec);
187 if (U_FAILURE(*ec)) { return; }
188
189 if (ufpositer == nullptr) {
190 *ec = U_ILLEGAL_ARGUMENT_ERROR;
191 return;
192 }
193
194 auto* fpi = reinterpret_cast<FieldPositionIterator*>(ufpositer);
195 result->fImpl.getAllFieldPositions(*fpi, *ec);
196}
197
198U_CAPI void U_EXPORT2
199unumf_close(UNumberFormatter* f) {
200 UErrorCode localStatus = U_ZERO_ERROR;
201 const UNumberFormatterData* impl = UNumberFormatterData::validate(f, localStatus);
202 delete impl;
203}
204
205
206#endif /* #if !UCONFIG_NO_FORMATTING */
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234