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