• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 ********************************************************************************
3 *   Copyright (C) 2015, International Business Machines
4 *   Corporation and others.  All Rights Reserved.
5 ********************************************************************************
6 *
7 * File decimfmtimpl.h
8 ********************************************************************************
9 */
10 
11 #ifndef DECIMFMTIMPL_H
12 #define DECIMFMTIMPL_H
13 
14 #include "unicode/utypes.h"
15 
16 #if !UCONFIG_NO_FORMATTING
17 
18 #include "unicode/decimfmt.h"
19 #include "unicode/uobject.h"
20 #include "affixpatternparser.h"
21 #include "digitaffixesandpadding.h"
22 #include "digitformatter.h"
23 #include "digitgrouping.h"
24 #include "precision.h"
25 
26 U_NAMESPACE_BEGIN
27 
28 class UnicodeString;
29 class FieldPosition;
30 class ValueFormatter;
31 class FieldPositionHandler;
32 class FixedDecimal;
33 
34 /**
35  * DecimalFormatImpl is the glue code between the legacy DecimalFormat class
36  * and the new decimal formatting classes. DecimalFormat still handles
37  * parsing directly. However, DecimalFormat uses attributes of this class
38  * for parsing when possible.
39  *
40  * The public API of this class closely mirrors the legacy API of the
41  * legacy DecimalFormat deviating only when the legacy API does not make
42  * sense. For example, although DecimalFormat has a
43  * getPadCharacterString() method, DecimalFormatImpl has a getPadCharacter()
44  * method because formatting uses only a single pad character for padding.
45  *
46  * Each legacy DecimalFormat instance heap allocates its own instance of
47  * this class. Most DecimalFormat methods that deal with formatting simply
48  * delegate to the DecimalFormat's DecimalFormatImpl method.
49  *
50  * Because DecimalFormat extends NumberFormat, Each instance of this class
51  * "borrows" a pointer to the NumberFormat part of its enclosing DecimalFormat
52  * instance. This way each DecimalFormatImpl instance can read or even modify
53  * the NumberFormat portion of its enclosing DecimalFormat instance.
54  *
55  * Directed acyclic graph (DAG):
56  *
57  * This class can be represented as a directed acyclic graph (DAG) where each
58  * vertex is an attribute, and each directed edge indicates that the value
59  * of the destination attribute is calculated from the value of the source
60  * attribute. Attributes with setter methods reside at the bottom of the
61  * DAG. That is, no edges point to them. We call these independent attributes
62  * because their values can be set independently of one another. The rest of
63  * the attributes are derived attributes because their values depend on the
64  * independent attributes. DecimalFormatImpl often uses the derived
65  * attributes, not the independent attributes, when formatting numbers.
66  *
67  * The independent attributes at the bottom of the DAG correspond to the legacy
68  * attributes of DecimalFormat while the attributes at the top of the DAG
69  * correspond to the attributes of the new code. The edges of the DAG
70  * correspond to the code that handles the complex interaction among all the
71  * legacy attributes of the DecimalFormat API.
72  *
73  * We use a DAG for three reasons.
74  *
75  * First, the DAG preserves backward compatibility. Clients of the legacy
76  * DecimalFormat expect existing getters and setters of each attribute to be
77  * consistent. That means if a client sets a particular attribute to a new
78  * value, the attribute should retain that value until the client sets it to
79  * a new value. The DAG allows these attributes to remain consistent even
80  * though the new code may not use them when formatting.
81  *
82  * Second, the DAG obviates the need to recalculate derived attributes with
83  * each format. Instead, the DAG "remembers" the values of all derived
84  * attributes. Only setting an independent attribute requires a recalculation.
85  * Moreover, setting an independent attribute recalculates only the affected
86  * dependent attributes rather than all dependent attributes.
87  *
88  * Third, the DAG abstracts away the complex interaction among the legacy
89  * attributes of the DecimalFormat API.
90  *
91  * Only the independent attributes of the DAG have setters and getters.
92  * Derived attributes have no setters (and often no getters either).
93  *
94  * Copy and assign:
95  *
96  * For copy and assign, DecimalFormatImpl copies and assigns every attribute
97  * regardless of whether or not it is independent. We do this for simplicity.
98  *
99  * Implementation of the DAG:
100  *
101  * The DAG consists of three smaller DAGs:
102  * 1. Grouping attributes
103  * 2. Precision attributes
104  * 3. Formatting attributes.
105  *
106  * The first two DAGs are simple in that setting any independent attribute
107  * in the DAG recalculates all the dependent attributes in that DAG.
108  * The updateGrouping() and updatePrecision() perform the respective
109  * recalculations.
110  *
111  * Because some of the derived formatting attributes are expensive to
112  * calculate, the formatting attributes DAG is more complex. The
113  * updateFormatting() method is composed of many updateFormattingXXX()
114  * methods, each of which recalculates a single derived attribute. The
115  * updateFormatting() method accepts a bitfield of recently changed
116  * attributes and passes this bitfield by reference to each of the
117  * updateFormattingXXX() methods. Each updateFormattingXXX() method checks
118  * the bitfield to see if any of the attributes it uses to compute the XXX
119  * attribute changed. If none of them changed, it exists immediately. However,
120  * if at least one of them changed, it recalculates the XXX attribute and
121  * sets the corresponding bit in the bitfield. In this way, each
122  * updateFormattingXXX() method encodes the directed edges in the formatting
123  * DAG that point to the attribute its calculating.
124  *
125  * Maintenance of the updateFormatting() method.
126  *
127  * Use care when changing the updateFormatting() method.
128  * The updateFormatting() method must call each updateFormattingXXX() in the
129  * same partial order that the formatting DAG prescribes. That is, the
130  * attributes near the bottom of the DAG must be calculated before attributes
131  * further up. As we mentioned in the prvious paragraph, the directed edges of
132  * the formatting DAG are encoded within each updateFormattingXXX() method.
133  * Finally, adding new attributes may involve adding to the bitmap that the
134  * updateFormatting() method uses. The top most attributes in the DAG,
135  * those that do not point to any attributes but only have attributes
136  * pointing to it, need not have a slot in the bitmap.
137  *
138  * Keep in mind that most of the code that makes the legacy DecimalFormat API
139  * work the way it always has before can be found in these various updateXXX()
140  * methods. For example the updatePrecisionForScientific() method
141  * handles the complex interactions amoung the various precision attributes
142  * when formatting in scientific notation. Changing the way attributes
143  * interract, often means changing one of these updateXXX() methods.
144  *
145  * Conclusion:
146  *
147  * The DecimFmtImpl class is the glue code between the legacy and new
148  * number formatting code. It uses a direct acyclic graph (DAG) to
149  * maintain backward compatibility, to make the code efficient, and to
150  * abstract away the complex interraction among legacy attributs.
151  */
152 
153 
154 class DecimalFormatImpl : public UObject {
155 public:
156 
157 DecimalFormatImpl(
158         NumberFormat *super,
159         const Locale &locale,
160         const UnicodeString &pattern,
161         UErrorCode &status);
162 DecimalFormatImpl(
163         NumberFormat *super,
164         const UnicodeString &pattern,
165         DecimalFormatSymbols *symbolsToAdopt,
166         UParseError &parseError,
167         UErrorCode &status);
168 DecimalFormatImpl(
169         NumberFormat *super,
170         const DecimalFormatImpl &other,
171         UErrorCode &status);
172 DecimalFormatImpl &assign(
173         const DecimalFormatImpl &other, UErrorCode &status);
174 virtual ~DecimalFormatImpl();
175 void adoptDecimalFormatSymbols(DecimalFormatSymbols *symbolsToAdopt);
getDecimalFormatSymbols()176 const DecimalFormatSymbols &getDecimalFormatSymbols() const {
177     return *fSymbols;
178 }
179 UnicodeString &format(
180         int32_t number,
181         UnicodeString &appendTo,
182         FieldPosition &pos,
183         UErrorCode &status) const;
184 UnicodeString &format(
185         int32_t number,
186         UnicodeString &appendTo,
187         FieldPositionIterator *posIter,
188         UErrorCode &status) const;
189 UnicodeString &format(
190         int64_t number,
191         UnicodeString &appendTo,
192         FieldPosition &pos,
193         UErrorCode &status) const;
194 UnicodeString &format(
195         double number,
196         UnicodeString &appendTo,
197         FieldPosition &pos,
198         UErrorCode &status) const;
199 UnicodeString &format(
200         const DigitList &number,
201         UnicodeString &appendTo,
202         FieldPosition &pos,
203         UErrorCode &status) const;
204 UnicodeString &format(
205         int64_t number,
206         UnicodeString &appendTo,
207         FieldPositionIterator *posIter,
208         UErrorCode &status) const;
209 UnicodeString &format(
210         double number,
211         UnicodeString &appendTo,
212         FieldPositionIterator *posIter,
213         UErrorCode &status) const;
214 UnicodeString &format(
215         const DigitList &number,
216         UnicodeString &appendTo,
217         FieldPositionIterator *posIter,
218         UErrorCode &status) const;
219 UnicodeString &format(
220         const StringPiece &number,
221         UnicodeString &appendTo,
222         FieldPositionIterator *posIter,
223         UErrorCode &status) const;
224 UnicodeString &format(
225         const VisibleDigitsWithExponent &digits,
226         UnicodeString &appendTo,
227         FieldPosition &pos,
228         UErrorCode &status) const;
229 UnicodeString &format(
230         const VisibleDigitsWithExponent &digits,
231         UnicodeString &appendTo,
232         FieldPositionIterator *posIter,
233         UErrorCode &status) const;
234 
235 UBool operator==(const DecimalFormatImpl &) const;
236 
237 UBool operator!=(const DecimalFormatImpl &other) const {
238     return !(*this == other);
239 }
240 
setRoundingMode(DecimalFormat::ERoundingMode mode)241 void setRoundingMode(DecimalFormat::ERoundingMode mode) {
242     fRoundingMode = mode;
243     fEffPrecision.fMantissa.fExactOnly = (fRoundingMode == DecimalFormat::kRoundUnnecessary);
244     fEffPrecision.fMantissa.fRoundingMode = mode;
245 }
getRoundingMode()246 DecimalFormat::ERoundingMode getRoundingMode() const {
247     return fRoundingMode;
248 }
setFailIfMoreThanMaxDigits(UBool b)249 void setFailIfMoreThanMaxDigits(UBool b) {
250     fEffPrecision.fMantissa.fFailIfOverMax = b;
251 }
isFailIfMoreThanMaxDigits()252 UBool isFailIfMoreThanMaxDigits() const { return fEffPrecision.fMantissa.fFailIfOverMax; }
253 void setMinimumSignificantDigits(int32_t newValue);
254 void setMaximumSignificantDigits(int32_t newValue);
255 void setMinMaxSignificantDigits(int32_t min, int32_t max);
256 void setScientificNotation(UBool newValue);
257 void setSignificantDigitsUsed(UBool newValue);
258 
getMinimumSignificantDigits()259 int32_t getMinimumSignificantDigits() const {
260         return fMinSigDigits; }
getMaximumSignificantDigits()261 int32_t getMaximumSignificantDigits() const {
262         return fMaxSigDigits; }
isScientificNotation()263 UBool isScientificNotation() const { return fUseScientific; }
areSignificantDigitsUsed()264 UBool areSignificantDigitsUsed() const { return fUseSigDigits; }
265 void setGroupingSize(int32_t newValue);
266 void setSecondaryGroupingSize(int32_t newValue);
267 void setMinimumGroupingDigits(int32_t newValue);
getGroupingSize()268 int32_t getGroupingSize() const { return fGrouping.fGrouping; }
getSecondaryGroupingSize()269 int32_t getSecondaryGroupingSize() const { return fGrouping.fGrouping2; }
getMinimumGroupingDigits()270 int32_t getMinimumGroupingDigits() const { return fGrouping.fMinGrouping; }
271 void applyPattern(const UnicodeString &pattern, UErrorCode &status);
272 void applyPatternFavorCurrencyPrecision(
273         const UnicodeString &pattern, UErrorCode &status);
274 void applyPattern(
275         const UnicodeString &pattern, UParseError &perror, UErrorCode &status);
276 void applyLocalizedPattern(const UnicodeString &pattern, UErrorCode &status);
277 void applyLocalizedPattern(
278         const UnicodeString &pattern, UParseError &perror, UErrorCode &status);
279 void setCurrencyUsage(UCurrencyUsage usage, UErrorCode &status);
getCurrencyUsage()280 UCurrencyUsage getCurrencyUsage() const { return fCurrencyUsage; }
281 void setRoundingIncrement(double d);
282 double getRoundingIncrement() const;
283 int32_t getMultiplier() const;
284 void setMultiplier(int32_t m);
getPadCharacter()285 UChar32 getPadCharacter() const { return fAffixes.fPadChar; }
setPadCharacter(UChar32 c)286 void setPadCharacter(UChar32 c) { fAffixes.fPadChar = c; }
getFormatWidth()287 int32_t getFormatWidth() const { return fAffixes.fWidth; }
setFormatWidth(int32_t x)288 void setFormatWidth(int32_t x) { fAffixes.fWidth = x; }
getPadPosition()289 DigitAffixesAndPadding::EPadPosition getPadPosition() const {
290     return fAffixes.fPadPosition;
291 }
setPadPosition(DigitAffixesAndPadding::EPadPosition x)292 void setPadPosition(DigitAffixesAndPadding::EPadPosition x) {
293     fAffixes.fPadPosition = x;
294 }
getMinimumExponentDigits()295 int32_t getMinimumExponentDigits() const {
296     return fEffPrecision.fMinExponentDigits;
297 }
setMinimumExponentDigits(int32_t x)298 void setMinimumExponentDigits(int32_t x) {
299     fEffPrecision.fMinExponentDigits = x;
300 }
isExponentSignAlwaysShown()301 UBool isExponentSignAlwaysShown() const {
302     return fOptions.fExponent.fAlwaysShowSign;
303 }
setExponentSignAlwaysShown(UBool x)304 void setExponentSignAlwaysShown(UBool x) {
305     fOptions.fExponent.fAlwaysShowSign = x;
306 }
isDecimalSeparatorAlwaysShown()307 UBool isDecimalSeparatorAlwaysShown() const {
308     return fOptions.fMantissa.fAlwaysShowDecimal;
309 }
setDecimalSeparatorAlwaysShown(UBool x)310 void setDecimalSeparatorAlwaysShown(UBool x) {
311     fOptions.fMantissa.fAlwaysShowDecimal = x;
312 }
313 UnicodeString &getPositivePrefix(UnicodeString &result) const;
314 UnicodeString &getPositiveSuffix(UnicodeString &result) const;
315 UnicodeString &getNegativePrefix(UnicodeString &result) const;
316 UnicodeString &getNegativeSuffix(UnicodeString &result) const;
317 void setPositivePrefix(const UnicodeString &str);
318 void setPositiveSuffix(const UnicodeString &str);
319 void setNegativePrefix(const UnicodeString &str);
320 void setNegativeSuffix(const UnicodeString &str);
321 UnicodeString &toPattern(UnicodeString& result) const;
322 FixedDecimal &getFixedDecimal(double value, FixedDecimal &result, UErrorCode &status) const;
323 FixedDecimal &getFixedDecimal(DigitList &number, FixedDecimal &result, UErrorCode &status) const;
324 DigitList &round(DigitList &number, UErrorCode &status) const;
325 
326 VisibleDigitsWithExponent &
327 initVisibleDigitsWithExponent(
328         int64_t number,
329         VisibleDigitsWithExponent &digits,
330         UErrorCode &status) const;
331 VisibleDigitsWithExponent &
332 initVisibleDigitsWithExponent(
333         double number,
334         VisibleDigitsWithExponent &digits,
335         UErrorCode &status) const;
336 VisibleDigitsWithExponent &
337 initVisibleDigitsWithExponent(
338         DigitList &number,
339         VisibleDigitsWithExponent &digits,
340         UErrorCode &status) const;
341 
342 void updatePrecision();
343 void updateGrouping();
344 void updateCurrency(UErrorCode &status);
345 
346 
347 private:
348 // Disallow copy and assign
349 DecimalFormatImpl(const DecimalFormatImpl &other);
350 DecimalFormatImpl &operator=(const DecimalFormatImpl &other);
351 NumberFormat *fSuper;
352 DigitList fMultiplier;
353 int32_t fScale;
354 
355 DecimalFormat::ERoundingMode fRoundingMode;
356 
357 // These fields include what the user can see and set.
358 // When the user updates these fields, it triggers automatic updates of
359 // other fields that may be invisible to user
360 
361 // Updating any of the following fields triggers an update to
362 // fEffPrecision.fMantissa.fMin,
363 // fEffPrecision.fMantissa.fMax,
364 // fEffPrecision.fMantissa.fSignificant fields
365 // We have this two phase update because of backward compatibility.
366 // DecimalFormat has to remember all settings even if those settings are
367 // invalid or disabled.
368 int32_t fMinSigDigits;
369 int32_t fMaxSigDigits;
370 UBool fUseScientific;
371 UBool fUseSigDigits;
372 // In addition to these listed above, changes to min/max int digits and
373 // min/max frac digits from fSuper also trigger an update.
374 
375 // Updating any of the following fields triggers an update to
376 // fEffGrouping field Again we do it this way because original
377 // grouping settings have to be retained if grouping is turned off.
378 DigitGrouping fGrouping;
379 // In addition to these listed above, changes to isGroupingUsed in
380 // fSuper also triggers an update to fEffGrouping.
381 
382 // Updating any of the following fields triggers updates on the following:
383 // fMonetary, fRules, fAffixParser, fCurrencyAffixInfo,
384 // fFormatter, fAffixes.fPositivePrefiix, fAffixes.fPositiveSuffix,
385 // fAffixes.fNegativePrefiix, fAffixes.fNegativeSuffix
386 // We do this two phase update because localizing the affix patterns
387 // and formatters can be expensive. Better to do it once with the setters
388 // than each time within format.
389 AffixPattern fPositivePrefixPattern;
390 AffixPattern fNegativePrefixPattern;
391 AffixPattern fPositiveSuffixPattern;
392 AffixPattern fNegativeSuffixPattern;
393 DecimalFormatSymbols *fSymbols;
394 UCurrencyUsage fCurrencyUsage;
395 // In addition to these listed above, changes to getCurrency() in
396 // fSuper also triggers an update.
397 
398 // Optional may be NULL
399 PluralRules *fRules;
400 
401 // These fields are totally hidden from user and are used to derive the affixes
402 // in fAffixes below from the four affix patterns above.
403 UBool fMonetary;
404 AffixPatternParser fAffixParser;
405 CurrencyAffixInfo fCurrencyAffixInfo;
406 
407 // The actual precision used when formatting
408 ScientificPrecision fEffPrecision;
409 
410 // The actual grouping used when formatting
411 DigitGrouping fEffGrouping;
412 SciFormatterOptions fOptions;   // Encapsulates fixed precision options
413 DigitFormatter fFormatter;
414 DigitAffixesAndPadding fAffixes;
415 
416 UnicodeString &formatInt32(
417         int32_t number,
418         UnicodeString &appendTo,
419         FieldPositionHandler &handler,
420         UErrorCode &status) const;
421 
422 UnicodeString &formatInt64(
423         int64_t number,
424         UnicodeString &appendTo,
425         FieldPositionHandler &handler,
426         UErrorCode &status) const;
427 
428 UnicodeString &formatDouble(
429         double number,
430         UnicodeString &appendTo,
431         FieldPositionHandler &handler,
432         UErrorCode &status) const;
433 
434 // Scales for precent or permille symbols
435 UnicodeString &formatDigitList(
436         DigitList &number,
437         UnicodeString &appendTo,
438         FieldPositionHandler &handler,
439         UErrorCode &status) const;
440 
441 // Does not scale for precent or permille symbols
442 UnicodeString &formatAdjustedDigitList(
443         DigitList &number,
444         UnicodeString &appendTo,
445         FieldPositionHandler &handler,
446         UErrorCode &status) const;
447 
448 UnicodeString &formatVisibleDigitsWithExponent(
449         const VisibleDigitsWithExponent &number,
450         UnicodeString &appendTo,
451         FieldPositionHandler &handler,
452         UErrorCode &status) const;
453 
454 VisibleDigitsWithExponent &
455 initVisibleDigitsFromAdjusted(
456         DigitList &number,
457         VisibleDigitsWithExponent &digits,
458         UErrorCode &status) const;
459 
460 template<class T>
461 UBool maybeFormatWithDigitList(
462         T number,
463         UnicodeString &appendTo,
464         FieldPositionHandler &handler,
465         UErrorCode &status) const;
466 
467 template<class T>
468 UBool maybeInitVisibleDigitsFromDigitList(
469         T number,
470         VisibleDigitsWithExponent &digits,
471         UErrorCode &status) const;
472 
473 DigitList &adjustDigitList(DigitList &number, UErrorCode &status) const;
474 
475 void applyPattern(
476         const UnicodeString &pattern,
477         UBool localized, UParseError &perror, UErrorCode &status);
478 
479 ValueFormatter &prepareValueFormatter(ValueFormatter &vf) const;
480 void setMultiplierScale(int32_t s);
481 int32_t getPatternScale() const;
setScale(int32_t s)482 void setScale(int32_t s) { fScale = s; }
getScale()483 int32_t getScale() const { return fScale; }
484 
485 // Updates everything
486 void updateAll(UErrorCode &status);
487 void updateAll(
488         int32_t formattingFlags,
489         UBool updatePrecisionBasedOnCurrency,
490         UErrorCode &status);
491 
492 // Updates from formatting pattern changes
493 void updateForApplyPattern(UErrorCode &status);
494 void updateForApplyPatternFavorCurrencyPrecision(UErrorCode &status);
495 
496 // Updates from changes to third group of attributes
497 void updateFormatting(int32_t changedFormattingFields, UErrorCode &status);
498 void updateFormatting(
499         int32_t changedFormattingFields,
500         UBool updatePrecisionBasedOnCurrency,
501         UErrorCode &status);
502 
503 // Helper functions for updatePrecision
504 void updatePrecisionForScientific();
505 void updatePrecisionForFixed();
506 void extractMinMaxDigits(DigitInterval &min, DigitInterval &max) const;
507 void extractSigDigits(SignificantDigitInterval &sig) const;
508 
509 // Helper functions for updateFormatting
510 void updateFormattingUsesCurrency(int32_t &changedFormattingFields);
511 void updateFormattingPluralRules(
512         int32_t &changedFormattingFields, UErrorCode &status);
513 void updateFormattingAffixParser(int32_t &changedFormattingFields);
514 void updateFormattingCurrencyAffixInfo(
515         int32_t &changedFormattingFields,
516         UBool updatePrecisionBasedOnCurrency,
517         UErrorCode &status);
518 void updateFormattingFixedPointFormatter(
519         int32_t &changedFormattingFields);
520 void updateFormattingLocalizedPositivePrefix(
521         int32_t &changedFormattingFields, UErrorCode &status);
522 void updateFormattingLocalizedPositiveSuffix(
523         int32_t &changedFormattingFields, UErrorCode &status);
524 void updateFormattingLocalizedNegativePrefix(
525         int32_t &changedFormattingFields, UErrorCode &status);
526 void updateFormattingLocalizedNegativeSuffix(
527         int32_t &changedFormattingFields, UErrorCode &status);
528 
529 int32_t computeExponentPatternLength() const;
530 int32_t countFractionDigitAndDecimalPatternLength(int32_t fracDigitCount) const;
531 UnicodeString &toNumberPattern(
532         UBool hasPadding, int32_t minimumLength, UnicodeString& result) const;
533 
534 int32_t getOldFormatWidth() const;
535 const UnicodeString &getConstSymbol(
536         DecimalFormatSymbols::ENumberFormatSymbol symbol) const;
537 UBool isParseFastpath() const;
538 
539 friend class DecimalFormat;
540 
541 };
542 
543 
544 U_NAMESPACE_END
545 #endif /* #if !UCONFIG_NO_FORMATTING */
546 #endif // DECIMFMTIMPL_H
547 //eof
548