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