• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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