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