1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 **********************************************************************
5 * Copyright (c) 2014, International Business Machines
6 * Corporation and others. All Rights Reserved.
7 **********************************************************************
8 */
9 #include "unicode/utypes.h"
10
11 #if !UCONFIG_NO_FORMATTING
12
13 #include "unicode/scientificnumberformatter.h"
14 #include "unicode/dcfmtsym.h"
15 #include "unicode/fpositer.h"
16 #include "unicode/utf16.h"
17 #include "unicode/uniset.h"
18 #include "decfmtst.h"
19 #include "unicode/decimfmt.h"
20
21 U_NAMESPACE_BEGIN
22
23 static const UChar kSuperscriptDigits[] = {
24 0x2070,
25 0xB9,
26 0xB2,
27 0xB3,
28 0x2074,
29 0x2075,
30 0x2076,
31 0x2077,
32 0x2078,
33 0x2079};
34
35 static const UChar kSuperscriptPlusSign = 0x207A;
36 static const UChar kSuperscriptMinusSign = 0x207B;
37
copyAsSuperscript(const UnicodeString & s,int32_t beginIndex,int32_t endIndex,UnicodeString & result,UErrorCode & status)38 static UBool copyAsSuperscript(
39 const UnicodeString &s,
40 int32_t beginIndex,
41 int32_t endIndex,
42 UnicodeString &result,
43 UErrorCode &status) {
44 if (U_FAILURE(status)) {
45 return FALSE;
46 }
47 for (int32_t i = beginIndex; i < endIndex;) {
48 UChar32 c = s.char32At(i);
49 int32_t digit = u_charDigitValue(c);
50 if (digit < 0) {
51 status = U_INVALID_CHAR_FOUND;
52 return FALSE;
53 }
54 result.append(kSuperscriptDigits[digit]);
55 i += U16_LENGTH(c);
56 }
57 return TRUE;
58 }
59
createSuperscriptInstance(DecimalFormat * fmtToAdopt,UErrorCode & status)60 ScientificNumberFormatter *ScientificNumberFormatter::createSuperscriptInstance(
61 DecimalFormat *fmtToAdopt, UErrorCode &status) {
62 return createInstance(fmtToAdopt, new SuperscriptStyle(), status);
63 }
64
createSuperscriptInstance(const Locale & locale,UErrorCode & status)65 ScientificNumberFormatter *ScientificNumberFormatter::createSuperscriptInstance(
66 const Locale &locale, UErrorCode &status) {
67 return createInstance(
68 static_cast<DecimalFormat *>(
69 DecimalFormat::createScientificInstance(locale, status)),
70 new SuperscriptStyle(),
71 status);
72 }
73
createMarkupInstance(DecimalFormat * fmtToAdopt,const UnicodeString & beginMarkup,const UnicodeString & endMarkup,UErrorCode & status)74 ScientificNumberFormatter *ScientificNumberFormatter::createMarkupInstance(
75 DecimalFormat *fmtToAdopt,
76 const UnicodeString &beginMarkup,
77 const UnicodeString &endMarkup,
78 UErrorCode &status) {
79 return createInstance(
80 fmtToAdopt,
81 new MarkupStyle(beginMarkup, endMarkup),
82 status);
83 }
84
createMarkupInstance(const Locale & locale,const UnicodeString & beginMarkup,const UnicodeString & endMarkup,UErrorCode & status)85 ScientificNumberFormatter *ScientificNumberFormatter::createMarkupInstance(
86 const Locale &locale,
87 const UnicodeString &beginMarkup,
88 const UnicodeString &endMarkup,
89 UErrorCode &status) {
90 return createInstance(
91 static_cast<DecimalFormat *>(
92 DecimalFormat::createScientificInstance(locale, status)),
93 new MarkupStyle(beginMarkup, endMarkup),
94 status);
95 }
96
createInstance(DecimalFormat * fmtToAdopt,Style * styleToAdopt,UErrorCode & status)97 ScientificNumberFormatter *ScientificNumberFormatter::createInstance(
98 DecimalFormat *fmtToAdopt,
99 Style *styleToAdopt,
100 UErrorCode &status) {
101 LocalPointer<DecimalFormat> fmt(fmtToAdopt);
102 LocalPointer<Style> style(styleToAdopt);
103 if (U_FAILURE(status)) {
104 return NULL;
105 }
106 ScientificNumberFormatter *result =
107 new ScientificNumberFormatter(
108 fmt.getAlias(),
109 style.getAlias(),
110 status);
111 if (result == NULL) {
112 status = U_MEMORY_ALLOCATION_ERROR;
113 return NULL;
114 }
115 fmt.orphan();
116 style.orphan();
117 if (U_FAILURE(status)) {
118 delete result;
119 return NULL;
120 }
121 return result;
122 }
123
clone() const124 ScientificNumberFormatter::Style *ScientificNumberFormatter::SuperscriptStyle::clone() const {
125 return new ScientificNumberFormatter::SuperscriptStyle(*this);
126 }
127
format(const UnicodeString & original,FieldPositionIterator & fpi,const UnicodeString & preExponent,const DecimalFormatStaticSets & staticSets,UnicodeString & appendTo,UErrorCode & status) const128 UnicodeString &ScientificNumberFormatter::SuperscriptStyle::format(
129 const UnicodeString &original,
130 FieldPositionIterator &fpi,
131 const UnicodeString &preExponent,
132 const DecimalFormatStaticSets &staticSets,
133 UnicodeString &appendTo,
134 UErrorCode &status) const {
135 if (U_FAILURE(status)) {
136 return appendTo;
137 }
138 FieldPosition fp;
139 int32_t copyFromOffset = 0;
140 while (fpi.next(fp)) {
141 switch (fp.getField()) {
142 case UNUM_EXPONENT_SYMBOL_FIELD:
143 appendTo.append(
144 original,
145 copyFromOffset,
146 fp.getBeginIndex() - copyFromOffset);
147 copyFromOffset = fp.getEndIndex();
148 appendTo.append(preExponent);
149 break;
150 case UNUM_EXPONENT_SIGN_FIELD:
151 {
152 int32_t beginIndex = fp.getBeginIndex();
153 int32_t endIndex = fp.getEndIndex();
154 UChar32 aChar = original.char32At(beginIndex);
155 if (staticSets.fMinusSigns->contains(aChar)) {
156 appendTo.append(
157 original,
158 copyFromOffset,
159 beginIndex - copyFromOffset);
160 appendTo.append(kSuperscriptMinusSign);
161 } else if (staticSets.fPlusSigns->contains(aChar)) {
162 appendTo.append(
163 original,
164 copyFromOffset,
165 beginIndex - copyFromOffset);
166 appendTo.append(kSuperscriptPlusSign);
167 } else {
168 status = U_INVALID_CHAR_FOUND;
169 return appendTo;
170 }
171 copyFromOffset = endIndex;
172 }
173 break;
174 case UNUM_EXPONENT_FIELD:
175 appendTo.append(
176 original,
177 copyFromOffset,
178 fp.getBeginIndex() - copyFromOffset);
179 if (!copyAsSuperscript(
180 original,
181 fp.getBeginIndex(),
182 fp.getEndIndex(),
183 appendTo,
184 status)) {
185 return appendTo;
186 }
187 copyFromOffset = fp.getEndIndex();
188 break;
189 default:
190 break;
191 }
192 }
193 appendTo.append(
194 original, copyFromOffset, original.length() - copyFromOffset);
195 return appendTo;
196 }
197
clone() const198 ScientificNumberFormatter::Style *ScientificNumberFormatter::MarkupStyle::clone() const {
199 return new ScientificNumberFormatter::MarkupStyle(*this);
200 }
201
format(const UnicodeString & original,FieldPositionIterator & fpi,const UnicodeString & preExponent,const DecimalFormatStaticSets &,UnicodeString & appendTo,UErrorCode & status) const202 UnicodeString &ScientificNumberFormatter::MarkupStyle::format(
203 const UnicodeString &original,
204 FieldPositionIterator &fpi,
205 const UnicodeString &preExponent,
206 const DecimalFormatStaticSets & /*unusedDecimalFormatSets*/,
207 UnicodeString &appendTo,
208 UErrorCode &status) const {
209 if (U_FAILURE(status)) {
210 return appendTo;
211 }
212 FieldPosition fp;
213 int32_t copyFromOffset = 0;
214 while (fpi.next(fp)) {
215 switch (fp.getField()) {
216 case UNUM_EXPONENT_SYMBOL_FIELD:
217 appendTo.append(
218 original,
219 copyFromOffset,
220 fp.getBeginIndex() - copyFromOffset);
221 copyFromOffset = fp.getEndIndex();
222 appendTo.append(preExponent);
223 appendTo.append(fBeginMarkup);
224 break;
225 case UNUM_EXPONENT_FIELD:
226 appendTo.append(
227 original,
228 copyFromOffset,
229 fp.getEndIndex() - copyFromOffset);
230 copyFromOffset = fp.getEndIndex();
231 appendTo.append(fEndMarkup);
232 break;
233 default:
234 break;
235 }
236 }
237 appendTo.append(
238 original, copyFromOffset, original.length() - copyFromOffset);
239 return appendTo;
240 }
241
ScientificNumberFormatter(DecimalFormat * fmtToAdopt,Style * styleToAdopt,UErrorCode & status)242 ScientificNumberFormatter::ScientificNumberFormatter(
243 DecimalFormat *fmtToAdopt, Style *styleToAdopt, UErrorCode &status)
244 : fPreExponent(),
245 fDecimalFormat(fmtToAdopt),
246 fStyle(styleToAdopt),
247 fStaticSets(NULL) {
248 if (U_FAILURE(status)) {
249 return;
250 }
251 if (fDecimalFormat == NULL || fStyle == NULL) {
252 status = U_ILLEGAL_ARGUMENT_ERROR;
253 return;
254 }
255 const DecimalFormatSymbols *sym = fDecimalFormat->getDecimalFormatSymbols();
256 if (sym == NULL) {
257 status = U_ILLEGAL_ARGUMENT_ERROR;
258 return;
259 }
260 getPreExponent(*sym, fPreExponent);
261 fStaticSets = DecimalFormatStaticSets::getStaticSets(status);
262 }
263
ScientificNumberFormatter(const ScientificNumberFormatter & other)264 ScientificNumberFormatter::ScientificNumberFormatter(
265 const ScientificNumberFormatter &other)
266 : UObject(other),
267 fPreExponent(other.fPreExponent),
268 fDecimalFormat(NULL),
269 fStyle(NULL),
270 fStaticSets(other.fStaticSets) {
271 fDecimalFormat = static_cast<DecimalFormat *>(
272 other.fDecimalFormat->clone());
273 fStyle = other.fStyle->clone();
274 }
275
~ScientificNumberFormatter()276 ScientificNumberFormatter::~ScientificNumberFormatter() {
277 delete fDecimalFormat;
278 delete fStyle;
279 }
280
format(const Formattable & number,UnicodeString & appendTo,UErrorCode & status) const281 UnicodeString &ScientificNumberFormatter::format(
282 const Formattable &number,
283 UnicodeString &appendTo,
284 UErrorCode &status) const {
285 if (U_FAILURE(status)) {
286 return appendTo;
287 }
288 UnicodeString original;
289 FieldPositionIterator fpi;
290 fDecimalFormat->format(number, original, &fpi, status);
291 return fStyle->format(
292 original,
293 fpi,
294 fPreExponent,
295 *fStaticSets,
296 appendTo,
297 status);
298 }
299
getPreExponent(const DecimalFormatSymbols & dfs,UnicodeString & preExponent)300 void ScientificNumberFormatter::getPreExponent(
301 const DecimalFormatSymbols &dfs, UnicodeString &preExponent) {
302 preExponent.append(dfs.getConstSymbol(
303 DecimalFormatSymbols::kExponentMultiplicationSymbol));
304 preExponent.append(dfs.getConstSymbol(DecimalFormatSymbols::kOneDigitSymbol));
305 preExponent.append(dfs.getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol));
306 }
307
308 U_NAMESPACE_END
309
310 #endif /* !UCONFIG_NO_FORMATTING */
311