1// © 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
28U_NAMESPACE_BEGIN
29
30class UnicodeString;
31class FieldPosition;
32class ValueFormatter;
33class FieldPositionHandler;
34class 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
156class DecimalFormatImpl : public UObject {
157public:
158
159DecimalFormatImpl(
160        NumberFormat *super,
161        const Locale &locale,
162        const UnicodeString &pattern,
163        UErrorCode &status);
164DecimalFormatImpl(
165        NumberFormat *super,
166        const UnicodeString &pattern,
167        DecimalFormatSymbols *symbolsToAdopt,
168        UParseError &parseError,
169        UErrorCode &status);
170DecimalFormatImpl(
171        NumberFormat *super,
172        const DecimalFormatImpl &other,
173        UErrorCode &status);
174DecimalFormatImpl &assign(
175        const DecimalFormatImpl &other, UErrorCode &status);
176virtual ~DecimalFormatImpl();
177void adoptDecimalFormatSymbols(DecimalFormatSymbols *symbolsToAdopt);
178const DecimalFormatSymbols &getDecimalFormatSymbols() const {
179    return *fSymbols;
180}
181UnicodeString &format(
182        int32_t number,
183        UnicodeString &appendTo,
184        FieldPosition &pos,
185        UErrorCode &status) const;
186UnicodeString &format(
187        int32_t number,
188        UnicodeString &appendTo,
189        FieldPositionIterator *posIter,
190        UErrorCode &status) const;
191UnicodeString &format(
192        int64_t number,
193        UnicodeString &appendTo,
194        FieldPosition &pos,
195        UErrorCode &status) const;
196UnicodeString &format(
197        double number,
198        UnicodeString &appendTo,
199        FieldPosition &pos,
200        UErrorCode &status) const;
201UnicodeString &format(
202        const DigitList &number,
203        UnicodeString &appendTo,
204        FieldPosition &pos,
205        UErrorCode &status) const;
206UnicodeString &format(
207        int64_t number,
208        UnicodeString &appendTo,
209        FieldPositionIterator *posIter,
210        UErrorCode &status) const;
211UnicodeString &format(
212        double number,
213        UnicodeString &appendTo,
214        FieldPositionIterator *posIter,
215        UErrorCode &status) const;
216UnicodeString &format(
217        const DigitList &number,
218        UnicodeString &appendTo,
219        FieldPositionIterator *posIter,
220        UErrorCode &status) const;
221UnicodeString &format(
222        StringPiece number,
223        UnicodeString &appendTo,
224        FieldPositionIterator *posIter,
225        UErrorCode &status) const;
226UnicodeString &format(
227        const VisibleDigitsWithExponent &digits,
228        UnicodeString &appendTo,
229        FieldPosition &pos,
230        UErrorCode &status) const;
231UnicodeString &format(
232        const VisibleDigitsWithExponent &digits,
233        UnicodeString &appendTo,
234        FieldPositionIterator *posIter,
235        UErrorCode &status) const;
236
237UBool operator==(const DecimalFormatImpl &) const;
238
239UBool operator!=(const DecimalFormatImpl &other) const {
240    return !(*this == other);
241}
242
243void setRoundingMode(DecimalFormat::ERoundingMode mode) {
244    fRoundingMode = mode;
245    fEffPrecision.fMantissa.fExactOnly = (fRoundingMode == DecimalFormat::kRoundUnnecessary);
246    fEffPrecision.fMantissa.fRoundingMode = mode;
247}
248DecimalFormat::ERoundingMode getRoundingMode() const {
249    return fRoundingMode;
250}
251void setFailIfMoreThanMaxDigits(UBool b) {
252    fEffPrecision.fMantissa.fFailIfOverMax = b;
253}
254UBool isFailIfMoreThanMaxDigits() const { return fEffPrecision.fMantissa.fFailIfOverMax; }
255void setMinimumSignificantDigits(int32_t newValue);
256void setMaximumSignificantDigits(int32_t newValue);
257void setMinMaxSignificantDigits(int32_t min, int32_t max);
258void setScientificNotation(UBool newValue);
259void setSignificantDigitsUsed(UBool newValue);
260
261int32_t getMinimumSignificantDigits() const {
262        return fMinSigDigits; }
263int32_t getMaximumSignificantDigits() const {
264        return fMaxSigDigits; }
265UBool isScientificNotation() const { return fUseScientific; }
266UBool areSignificantDigitsUsed() const { return fUseSigDigits; }
267void setGroupingSize(int32_t newValue);
268void setSecondaryGroupingSize(int32_t newValue);
269void setMinimumGroupingDigits(int32_t newValue);
270int32_t getGroupingSize() const { return fGrouping.fGrouping; }
271int32_t getSecondaryGroupingSize() const { return fGrouping.fGrouping2; }
272int32_t getMinimumGroupingDigits() const { return fGrouping.fMinGrouping; }
273void applyPattern(const UnicodeString &pattern, UErrorCode &status);
274void applyPatternFavorCurrencyPrecision(
275        const UnicodeString &pattern, UErrorCode &status);
276void applyPattern(
277        const UnicodeString &pattern, UParseError &perror, UErrorCode &status);
278void applyLocalizedPattern(const UnicodeString &pattern, UErrorCode &status);
279void applyLocalizedPattern(
280        const UnicodeString &pattern, UParseError &perror, UErrorCode &status);
281void setCurrencyUsage(UCurrencyUsage usage, UErrorCode &status);
282UCurrencyUsage getCurrencyUsage() const { return fCurrencyUsage; }
283void setRoundingIncrement(double d);
284double getRoundingIncrement() const;
285int32_t getMultiplier() const;
286void setMultiplier(int32_t m);
287UChar32 getPadCharacter() const { return fAffixes.fPadChar; }
288void setPadCharacter(UChar32 c) { fAffixes.fPadChar = c; }
289int32_t getFormatWidth() const { return fAffixes.fWidth; }
290void setFormatWidth(int32_t x) { fAffixes.fWidth = x; }
291DigitAffixesAndPadding::EPadPosition getPadPosition() const {
292    return fAffixes.fPadPosition;
293}
294void setPadPosition(DigitAffixesAndPadding::EPadPosition x) {
295    fAffixes.fPadPosition = x;
296}
297int32_t getMinimumExponentDigits() const {
298    return fEffPrecision.fMinExponentDigits;
299}
300void setMinimumExponentDigits(int32_t x) {
301    fEffPrecision.fMinExponentDigits = x;
302}
303UBool isExponentSignAlwaysShown() const {
304    return fOptions.fExponent.fAlwaysShowSign;
305}
306void setExponentSignAlwaysShown(UBool x) {
307    fOptions.fExponent.fAlwaysShowSign = x;
308}
309UBool isDecimalSeparatorAlwaysShown() const {
310    return fOptions.fMantissa.fAlwaysShowDecimal;
311}
312void setDecimalSeparatorAlwaysShown(UBool x) {
313    fOptions.fMantissa.fAlwaysShowDecimal = x;
314}
315UnicodeString &getPositivePrefix(UnicodeString &result) const;
316UnicodeString &getPositiveSuffix(UnicodeString &result) const;
317UnicodeString &getNegativePrefix(UnicodeString &result) const;
318UnicodeString &getNegativeSuffix(UnicodeString &result) const;
319void setPositivePrefix(const UnicodeString &str);
320void setPositiveSuffix(const UnicodeString &str);
321void setNegativePrefix(const UnicodeString &str);
322void setNegativeSuffix(const UnicodeString &str);
323UnicodeString &toPattern(UnicodeString& result) const;
324FixedDecimal &getFixedDecimal(double value, FixedDecimal &result, UErrorCode &status) const;
325FixedDecimal &getFixedDecimal(DigitList &number, FixedDecimal &result, UErrorCode &status) const;
326DigitList &round(DigitList &number, UErrorCode &status) const;
327
328VisibleDigitsWithExponent &
329initVisibleDigitsWithExponent(
330        int64_t number,
331        VisibleDigitsWithExponent &digits,
332        UErrorCode &status) const;
333VisibleDigitsWithExponent &
334initVisibleDigitsWithExponent(
335        double number,
336        VisibleDigitsWithExponent &digits,
337        UErrorCode &status) const;
338VisibleDigitsWithExponent &
339initVisibleDigitsWithExponent(
340        DigitList &number,
341        VisibleDigitsWithExponent &digits,
342        UErrorCode &status) const;
343
344void updatePrecision();
345void updateGrouping();
346void updateCurrency(UErrorCode &status);
347
348
349private:
350// Disallow copy and assign
351DecimalFormatImpl(const DecimalFormatImpl &other);
352DecimalFormatImpl &operator=(const DecimalFormatImpl &other);
353NumberFormat *fSuper;
354DigitList fMultiplier;
355int32_t fScale;
356
357DecimalFormat::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.
370int32_t fMinSigDigits;
371int32_t fMaxSigDigits;
372UBool fUseScientific;
373UBool 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.
380DigitGrouping 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.
391AffixPattern fPositivePrefixPattern;
392AffixPattern fNegativePrefixPattern;
393AffixPattern fPositiveSuffixPattern;
394AffixPattern fNegativeSuffixPattern;
395DecimalFormatSymbols *fSymbols;
396UCurrencyUsage fCurrencyUsage;
397// In addition to these listed above, changes to getCurrency() in
398// fSuper also triggers an update.
399
400// Optional may be NULL
401PluralRules *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.
405UBool fMonetary;
406AffixPatternParser fAffixParser;
407CurrencyAffixInfo fCurrencyAffixInfo;
408
409// The actual precision used when formatting
410ScientificPrecision fEffPrecision;
411
412// The actual grouping used when formatting
413DigitGrouping fEffGrouping;
414SciFormatterOptions fOptions;   // Encapsulates fixed precision options
415DigitFormatter fFormatter;
416DigitAffixesAndPadding fAffixes;
417
418UnicodeString &formatInt32(
419        int32_t number,
420        UnicodeString &appendTo,
421        FieldPositionHandler &handler,
422        UErrorCode &status) const;
423
424UnicodeString &formatInt64(
425        int64_t number,
426        UnicodeString &appendTo,
427        FieldPositionHandler &handler,
428        UErrorCode &status) const;
429
430UnicodeString &formatDouble(
431        double number,
432        UnicodeString &appendTo,
433        FieldPositionHandler &handler,
434        UErrorCode &status) const;
435
436// Scales for precent or permille symbols
437UnicodeString &formatDigitList(
438        DigitList &number,
439        UnicodeString &appendTo,
440        FieldPositionHandler &handler,
441        UErrorCode &status) const;
442
443// Does not scale for precent or permille symbols
444UnicodeString &formatAdjustedDigitList(
445        DigitList &number,
446        UnicodeString &appendTo,
447        FieldPositionHandler &handler,
448        UErrorCode &status) const;
449
450UnicodeString &formatVisibleDigitsWithExponent(
451        const VisibleDigitsWithExponent &number,
452        UnicodeString &appendTo,
453        FieldPositionHandler &handler,
454        UErrorCode &status) const;
455
456VisibleDigitsWithExponent &
457initVisibleDigitsFromAdjusted(
458        DigitList &number,
459        VisibleDigitsWithExponent &digits,
460        UErrorCode &status) const;
461
462template<class T>
463UBool maybeFormatWithDigitList(
464        T number,
465        UnicodeString &appendTo,
466        FieldPositionHandler &handler,
467        UErrorCode &status) const;
468
469template<class T>
470UBool maybeInitVisibleDigitsFromDigitList(
471        T number,
472        VisibleDigitsWithExponent &digits,
473        UErrorCode &status) const;
474
475DigitList &adjustDigitList(DigitList &number, UErrorCode &status) const;
476
477void applyPattern(
478        const UnicodeString &pattern,
479        UBool localized, UParseError &perror, UErrorCode &status);
480
481ValueFormatter &prepareValueFormatter(ValueFormatter &vf) const;
482void setMultiplierScale(int32_t s);
483int32_t getPatternScale() const;
484void setScale(int32_t s) { fScale = s; }
485int32_t getScale() const { return fScale; }
486
487// Updates everything
488void updateAll(UErrorCode &status);
489void updateAll(
490        int32_t formattingFlags,
491        UBool updatePrecisionBasedOnCurrency,
492        UErrorCode &status);
493
494// Updates from formatting pattern changes
495void updateForApplyPattern(UErrorCode &status);
496void updateForApplyPatternFavorCurrencyPrecision(UErrorCode &status);
497
498// Updates from changes to third group of attributes
499void updateFormatting(int32_t changedFormattingFields, UErrorCode &status);
500void updateFormatting(
501        int32_t changedFormattingFields,
502        UBool updatePrecisionBasedOnCurrency,
503        UErrorCode &status);
504
505// Helper functions for updatePrecision
506void updatePrecisionForScientific();
507void updatePrecisionForFixed();
508void extractMinMaxDigits(DigitInterval &min, DigitInterval &max) const;
509void extractSigDigits(SignificantDigitInterval &sig) const;
510
511// Helper functions for updateFormatting
512void updateFormattingUsesCurrency(int32_t &changedFormattingFields);
513void updateFormattingPluralRules(
514        int32_t &changedFormattingFields, UErrorCode &status);
515void updateFormattingAffixParser(int32_t &changedFormattingFields);
516void updateFormattingCurrencyAffixInfo(
517        int32_t &changedFormattingFields,
518        UBool updatePrecisionBasedOnCurrency,
519        UErrorCode &status);
520void updateFormattingFixedPointFormatter(
521        int32_t &changedFormattingFields);
522void updateFormattingLocalizedPositivePrefix(
523        int32_t &changedFormattingFields, UErrorCode &status);
524void updateFormattingLocalizedPositiveSuffix(
525        int32_t &changedFormattingFields, UErrorCode &status);
526void updateFormattingLocalizedNegativePrefix(
527        int32_t &changedFormattingFields, UErrorCode &status);
528void updateFormattingLocalizedNegativeSuffix(
529        int32_t &changedFormattingFields, UErrorCode &status);
530
531int32_t computeExponentPatternLength() const;
532int32_t countFractionDigitAndDecimalPatternLength(int32_t fracDigitCount) const;
533UnicodeString &toNumberPattern(
534        UBool hasPadding, int32_t minimumLength, UnicodeString& result) const;
535
536int32_t getOldFormatWidth() const;
537const UnicodeString &getConstSymbol(
538        DecimalFormatSymbols::ENumberFormatSymbol symbol) const;
539UBool isParseFastpath() const;
540
541friend class DecimalFormat;
542
543};
544
545
546U_NAMESPACE_END
547#endif /* #if !UCONFIG_NO_FORMATTING */
548#endif // DECIMFMTIMPL_H
549//eof
550