1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 ********************************************************************************
5 * Copyright (C) 2015, International Business Machines
6 * Corporation and others. All Rights Reserved.
7 ********************************************************************************
10 ********************************************************************************
13 #ifndef DECIMFMTIMPL_H
14 #define DECIMFMTIMPL_H
16 #include "unicode/utypes.h"
18 #if !UCONFIG_NO_FORMATTING
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"
33 class FieldPositionHandler
;
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.
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.
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.
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.
57 * Directed acyclic graph (DAG):
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.
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.
75 * We use a DAG for three reasons.
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.
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.
90 * Third, the DAG abstracts away the complex interaction among the legacy
91 * attributes of the DecimalFormat API.
93 * Only the independent attributes of the DAG have setters and getters.
94 * Derived attributes have no setters (and often no getters either).
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.
101 * Implementation of the DAG:
103 * The DAG consists of three smaller DAGs:
104 * 1. Grouping attributes
105 * 2. Precision attributes
106 * 3. Formatting attributes.
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
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.
127 * Maintenance of the updateFormatting() method.
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.
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.
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.
156 class DecimalFormatImpl
: public UObject
{
161 const Locale
&locale
,
162 const UnicodeString
&pattern
,
166 const UnicodeString
&pattern
,
167 DecimalFormatSymbols
*symbolsToAdopt
,
168 UParseError
&parseError
,
172 const DecimalFormatImpl
&other
,
174 DecimalFormatImpl
&assign(
175 const DecimalFormatImpl
&other
, UErrorCode
&status
);
176 virtual ~DecimalFormatImpl();
177 void adoptDecimalFormatSymbols(DecimalFormatSymbols
*symbolsToAdopt
);
178 const DecimalFormatSymbols
&getDecimalFormatSymbols() const {
181 UnicodeString
&format(
183 UnicodeString
&appendTo
,
185 UErrorCode
&status
) const;
186 UnicodeString
&format(
188 UnicodeString
&appendTo
,
189 FieldPositionIterator
*posIter
,
190 UErrorCode
&status
) const;
191 UnicodeString
&format(
193 UnicodeString
&appendTo
,
195 UErrorCode
&status
) const;
196 UnicodeString
&format(
198 UnicodeString
&appendTo
,
200 UErrorCode
&status
) const;
201 UnicodeString
&format(
202 const DigitList
&number
,
203 UnicodeString
&appendTo
,
205 UErrorCode
&status
) const;
206 UnicodeString
&format(
208 UnicodeString
&appendTo
,
209 FieldPositionIterator
*posIter
,
210 UErrorCode
&status
) const;
211 UnicodeString
&format(
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(
223 UnicodeString
&appendTo
,
224 FieldPositionIterator
*posIter
,
225 UErrorCode
&status
) const;
226 UnicodeString
&format(
227 const VisibleDigitsWithExponent
&digits
,
228 UnicodeString
&appendTo
,
230 UErrorCode
&status
) const;
231 UnicodeString
&format(
232 const VisibleDigitsWithExponent
&digits
,
233 UnicodeString
&appendTo
,
234 FieldPositionIterator
*posIter
,
235 UErrorCode
&status
) const;
237 UBool
operator==(const DecimalFormatImpl
&) const;
239 UBool
operator!=(const DecimalFormatImpl
&other
) const {
240 return !(*this == other
);
243 void setRoundingMode(DecimalFormat::ERoundingMode mode
) {
244 fRoundingMode
= mode
;
245 fEffPrecision
.fMantissa
.fExactOnly
= (fRoundingMode
== DecimalFormat::kRoundUnnecessary
);
246 fEffPrecision
.fMantissa
.fRoundingMode
= mode
;
248 DecimalFormat::ERoundingMode
getRoundingMode() const {
249 return fRoundingMode
;
251 void setFailIfMoreThanMaxDigits(UBool b
) {
252 fEffPrecision
.fMantissa
.fFailIfOverMax
= b
;
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
);
261 int32_t getMinimumSignificantDigits() const {
262 return fMinSigDigits
; }
263 int32_t getMaximumSignificantDigits() const {
264 return fMaxSigDigits
; }
265 UBool
isScientificNotation() const { return fUseScientific
; }
266 UBool
areSignificantDigitsUsed() const { return fUseSigDigits
; }
267 void setGroupingSize(int32_t newValue
);
268 void setSecondaryGroupingSize(int32_t newValue
);
269 void setMinimumGroupingDigits(int32_t newValue
);
270 int32_t getGroupingSize() const { return fGrouping
.fGrouping
; }
271 int32_t getSecondaryGroupingSize() const { return fGrouping
.fGrouping2
; }
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
);
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
);
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
);
287 UChar32
getPadCharacter() const { return fAffixes
.fPadChar
; }
288 void setPadCharacter(UChar32 c
) { fAffixes
.fPadChar
= c
; }
289 int32_t getFormatWidth() const { return fAffixes
.fWidth
; }
290 void setFormatWidth(int32_t x
) { fAffixes
.fWidth
= x
; }
291 DigitAffixesAndPadding::EPadPosition
getPadPosition() const {
292 return fAffixes
.fPadPosition
;
294 void setPadPosition(DigitAffixesAndPadding::EPadPosition x
) {
295 fAffixes
.fPadPosition
= x
;
297 int32_t getMinimumExponentDigits() const {
298 return fEffPrecision
.fMinExponentDigits
;
300 void setMinimumExponentDigits(int32_t x
) {
301 fEffPrecision
.fMinExponentDigits
= x
;
303 UBool
isExponentSignAlwaysShown() const {
304 return fOptions
.fExponent
.fAlwaysShowSign
;
306 void setExponentSignAlwaysShown(UBool x
) {
307 fOptions
.fExponent
.fAlwaysShowSign
= x
;
309 UBool
isDecimalSeparatorAlwaysShown() const {
310 return fOptions
.fMantissa
.fAlwaysShowDecimal
;
312 void setDecimalSeparatorAlwaysShown(UBool x
) {
313 fOptions
.fMantissa
.fAlwaysShowDecimal
= x
;
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;
328 VisibleDigitsWithExponent
&
329 initVisibleDigitsWithExponent(
331 VisibleDigitsWithExponent
&digits
,
332 UErrorCode
&status
) const;
333 VisibleDigitsWithExponent
&
334 initVisibleDigitsWithExponent(
336 VisibleDigitsWithExponent
&digits
,
337 UErrorCode
&status
) const;
338 VisibleDigitsWithExponent
&
339 initVisibleDigitsWithExponent(
341 VisibleDigitsWithExponent
&digits
,
342 UErrorCode
&status
) const;
344 void updatePrecision();
345 void updateGrouping();
346 void updateCurrency(UErrorCode
&status
);
349 UBool
getFormatFullPrecision() const { return fFormatFullPrecision
; }
350 void setFormatFullPrecision(UBool formatFullPrecision
) { fFormatFullPrecision
= formatFullPrecision
; }
353 // Disallow copy and assign
354 DecimalFormatImpl(const DecimalFormatImpl
&other
);
355 DecimalFormatImpl
&operator=(const DecimalFormatImpl
&other
);
356 NumberFormat
*fSuper
;
357 DigitList fMultiplier
;
360 DecimalFormat::ERoundingMode fRoundingMode
;
362 // These fields include what the user can see and set.
363 // When the user updates these fields, it triggers automatic updates of
364 // other fields that may be invisible to user
366 // Updating any of the following fields triggers an update to
367 // fEffPrecision.fMantissa.fMin,
368 // fEffPrecision.fMantissa.fMax,
369 // fEffPrecision.fMantissa.fSignificant fields
370 // We have this two phase update because of backward compatibility.
371 // DecimalFormat has to remember all settings even if those settings are
372 // invalid or disabled.
373 int32_t fMinSigDigits
;
374 int32_t fMaxSigDigits
;
375 UBool fUseScientific
;
377 // In addition to these listed above, changes to min/max int digits and
378 // min/max frac digits from fSuper also trigger an update.
380 // Updating any of the following fields triggers an update to
381 // fEffGrouping field Again we do it this way because original
382 // grouping settings have to be retained if grouping is turned off.
383 DigitGrouping fGrouping
;
384 // In addition to these listed above, changes to isGroupingUsed in
385 // fSuper also triggers an update to fEffGrouping.
387 // Updating any of the following fields triggers updates on the following:
388 // fMonetary, fRules, fAffixParser, fCurrencyAffixInfo,
389 // fFormatter, fAffixes.fPositivePrefiix, fAffixes.fPositiveSuffix,
390 // fAffixes.fNegativePrefiix, fAffixes.fNegativeSuffix
391 // We do this two phase update because localizing the affix patterns
392 // and formatters can be expensive. Better to do it once with the setters
393 // than each time within format.
394 AffixPattern fPositivePrefixPattern
;
395 AffixPattern fNegativePrefixPattern
;
396 AffixPattern fPositiveSuffixPattern
;
397 AffixPattern fNegativeSuffixPattern
;
398 DecimalFormatSymbols
*fSymbols
;
399 UCurrencyUsage fCurrencyUsage
;
400 // In addition to these listed above, changes to getCurrency() in
401 // fSuper also triggers an update.
403 // Optional may be NULL
406 // These fields are totally hidden from user and are used to derive the affixes
407 // in fAffixes below from the four affix patterns above.
409 AffixPatternParser fAffixParser
;
410 CurrencyAffixInfo fCurrencyAffixInfo
;
412 // The actual precision used when formatting
413 ScientificPrecision fEffPrecision
;
415 // The actual grouping used when formatting
416 DigitGrouping fEffGrouping
;
417 SciFormatterOptions fOptions
; // Encapsulates fixed precision options
418 DigitFormatter fFormatter
;
419 DigitAffixesAndPadding fAffixes
;
421 // Flag to cap double conversion precision at DBL_DIG digits (Apple specific)
422 UBool fFormatFullPrecision
;
424 UnicodeString
&formatInt32(
426 UnicodeString
&appendTo
,
427 FieldPositionHandler
&handler
,
428 UErrorCode
&status
) const;
430 UnicodeString
&formatInt64(
432 UnicodeString
&appendTo
,
433 FieldPositionHandler
&handler
,
434 UErrorCode
&status
) const;
436 UnicodeString
&formatDouble(
438 UnicodeString
&appendTo
,
439 FieldPositionHandler
&handler
,
440 UErrorCode
&status
) const;
442 // Scales for precent or permille symbols
443 UnicodeString
&formatDigitList(
445 UnicodeString
&appendTo
,
446 FieldPositionHandler
&handler
,
447 UErrorCode
&status
) const;
449 // Does not scale for precent or permille symbols
450 UnicodeString
&formatAdjustedDigitList(
452 UnicodeString
&appendTo
,
453 FieldPositionHandler
&handler
,
454 UErrorCode
&status
) const;
456 UnicodeString
&formatVisibleDigitsWithExponent(
457 const VisibleDigitsWithExponent
&number
,
458 UnicodeString
&appendTo
,
459 FieldPositionHandler
&handler
,
460 UErrorCode
&status
) const;
462 VisibleDigitsWithExponent
&
463 initVisibleDigitsFromAdjusted(
465 VisibleDigitsWithExponent
&digits
,
466 UErrorCode
&status
) const;
469 UBool
maybeFormatWithDigitList(
471 UnicodeString
&appendTo
,
472 FieldPositionHandler
&handler
,
473 UErrorCode
&status
) const;
476 UBool
maybeInitVisibleDigitsFromDigitList(
478 VisibleDigitsWithExponent
&digits
,
479 UErrorCode
&status
) const;
481 DigitList
&adjustDigitList(DigitList
&number
, UErrorCode
&status
) const;
484 const UnicodeString
&pattern
,
485 UBool localized
, UParseError
&perror
, UErrorCode
&status
);
487 ValueFormatter
&prepareValueFormatter(ValueFormatter
&vf
) const;
488 void setMultiplierScale(int32_t s
);
489 int32_t getPatternScale() const;
490 void setScale(int32_t s
) { fScale
= s
; }
491 int32_t getScale() const { return fScale
; }
493 // Updates everything
494 void updateAll(UErrorCode
&status
);
496 int32_t formattingFlags
,
497 UBool updatePrecisionBasedOnCurrency
,
500 // Updates from formatting pattern changes
501 void updateForApplyPattern(UErrorCode
&status
);
502 void updateForApplyPatternFavorCurrencyPrecision(UErrorCode
&status
);
504 // Updates from changes to third group of attributes
505 void updateFormatting(int32_t changedFormattingFields
, UErrorCode
&status
);
506 void updateFormatting(
507 int32_t changedFormattingFields
,
508 UBool updatePrecisionBasedOnCurrency
,
511 // Helper functions for updatePrecision
512 void updatePrecisionForScientific();
513 void updatePrecisionForFixed();
514 void extractMinMaxDigits(DigitInterval
&min
, DigitInterval
&max
) const;
515 void extractSigDigits(SignificantDigitInterval
&sig
) const;
517 // Helper functions for updateFormatting
518 void updateFormattingUsesCurrency(int32_t &changedFormattingFields
);
519 void updateFormattingPluralRules(
520 int32_t &changedFormattingFields
, UErrorCode
&status
);
521 void updateFormattingAffixParser(int32_t &changedFormattingFields
);
522 void updateFormattingCurrencyAffixInfo(
523 int32_t &changedFormattingFields
,
524 UBool updatePrecisionBasedOnCurrency
,
526 void updateFormattingFixedPointFormatter(
527 int32_t &changedFormattingFields
);
528 void updateFormattingLocalizedPositivePrefix(
529 int32_t &changedFormattingFields
, UErrorCode
&status
);
530 void updateFormattingLocalizedPositiveSuffix(
531 int32_t &changedFormattingFields
, UErrorCode
&status
);
532 void updateFormattingLocalizedNegativePrefix(
533 int32_t &changedFormattingFields
, UErrorCode
&status
);
534 void updateFormattingLocalizedNegativeSuffix(
535 int32_t &changedFormattingFields
, UErrorCode
&status
);
537 int32_t computeExponentPatternLength() const;
538 int32_t countFractionDigitAndDecimalPatternLength(int32_t fracDigitCount
) const;
539 UnicodeString
&toNumberPattern(
540 UBool hasPadding
, int32_t minimumLength
, UnicodeString
& result
) const;
542 int32_t getOldFormatWidth() const;
543 const UnicodeString
&getConstSymbol(
544 DecimalFormatSymbols::ENumberFormatSymbol symbol
) const;
545 UBool
isParseFastpath() const;
547 friend class DecimalFormat
;
553 #endif /* #if !UCONFIG_NO_FORMATTING */
554 #endif // DECIMFMTIMPL_H