2 ********************************************************************************
3 * Copyright (C) 2015, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 ********************************************************************************
8 ********************************************************************************
11 #ifndef DECIMFMTIMPL_H
12 #define DECIMFMTIMPL_H
14 #include "unicode/utypes.h"
16 #if !UCONFIG_NO_FORMATTING
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"
31 class FieldPositionHandler
;
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.
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.
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.
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.
55 * Directed acyclic graph (DAG):
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.
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.
73 * We use a DAG for three reasons.
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.
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.
88 * Third, the DAG abstracts away the complex interaction among the legacy
89 * attributes of the DecimalFormat API.
91 * Only the independent attributes of the DAG have setters and getters.
92 * Derived attributes have no setters (and often no getters either).
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.
99 * Implementation of the DAG:
101 * The DAG consists of three smaller DAGs:
102 * 1. Grouping attributes
103 * 2. Precision attributes
104 * 3. Formatting attributes.
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
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.
125 * Maintenance of the updateFormatting() method.
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.
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.
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.
154 class DecimalFormatImpl
: public UObject
{
159 const Locale
&locale
,
160 const UnicodeString
&pattern
,
164 const UnicodeString
&pattern
,
165 DecimalFormatSymbols
*symbolsToAdopt
,
166 UParseError
&parseError
,
170 const DecimalFormatImpl
&other
,
172 DecimalFormatImpl
&assign(
173 const DecimalFormatImpl
&other
, UErrorCode
&status
);
174 virtual ~DecimalFormatImpl();
175 void adoptDecimalFormatSymbols(DecimalFormatSymbols
*symbolsToAdopt
);
176 const DecimalFormatSymbols
&getDecimalFormatSymbols() const {
179 UnicodeString
&format(
181 UnicodeString
&appendTo
,
183 UErrorCode
&status
) const;
184 UnicodeString
&format(
186 UnicodeString
&appendTo
,
187 FieldPositionIterator
*posIter
,
188 UErrorCode
&status
) const;
189 UnicodeString
&format(
191 UnicodeString
&appendTo
,
193 UErrorCode
&status
) const;
194 UnicodeString
&format(
196 UnicodeString
&appendTo
,
198 UErrorCode
&status
) const;
199 UnicodeString
&format(
200 const DigitList
&number
,
201 UnicodeString
&appendTo
,
203 UErrorCode
&status
) const;
204 UnicodeString
&format(
206 UnicodeString
&appendTo
,
207 FieldPositionIterator
*posIter
,
208 UErrorCode
&status
) const;
209 UnicodeString
&format(
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
,
228 UErrorCode
&status
) const;
229 UnicodeString
&format(
230 const VisibleDigitsWithExponent
&digits
,
231 UnicodeString
&appendTo
,
232 FieldPositionIterator
*posIter
,
233 UErrorCode
&status
) const;
235 UBool
operator==(const DecimalFormatImpl
&) const;
237 UBool
operator!=(const DecimalFormatImpl
&other
) const {
238 return !(*this == other
);
241 void setRoundingMode(DecimalFormat::ERoundingMode mode
) {
242 fRoundingMode
= mode
;
243 fEffPrecision
.fMantissa
.fExactOnly
= (fRoundingMode
== DecimalFormat::kRoundUnnecessary
);
244 fEffPrecision
.fMantissa
.fRoundingMode
= mode
;
246 DecimalFormat::ERoundingMode
getRoundingMode() const {
247 return fRoundingMode
;
249 void setFailIfMoreThanMaxDigits(UBool b
) {
250 fEffPrecision
.fMantissa
.fFailIfOverMax
= b
;
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
);
259 int32_t getMinimumSignificantDigits() const {
260 return fMinSigDigits
; }
261 int32_t getMaximumSignificantDigits() const {
262 return fMaxSigDigits
; }
263 UBool
isScientificNotation() const { return fUseScientific
; }
264 UBool
areSignificantDigitsUsed() const { return fUseSigDigits
; }
265 void setGroupingSize(int32_t newValue
);
266 void setSecondaryGroupingSize(int32_t newValue
);
267 void setMinimumGroupingDigits(int32_t newValue
);
268 int32_t getGroupingSize() const { return fGrouping
.fGrouping
; }
269 int32_t getSecondaryGroupingSize() const { return fGrouping
.fGrouping2
; }
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
);
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
);
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
);
285 UChar32
getPadCharacter() const { return fAffixes
.fPadChar
; }
286 void setPadCharacter(UChar32 c
) { fAffixes
.fPadChar
= c
; }
287 int32_t getFormatWidth() const { return fAffixes
.fWidth
; }
288 void setFormatWidth(int32_t x
) { fAffixes
.fWidth
= x
; }
289 DigitAffixesAndPadding::EPadPosition
getPadPosition() const {
290 return fAffixes
.fPadPosition
;
292 void setPadPosition(DigitAffixesAndPadding::EPadPosition x
) {
293 fAffixes
.fPadPosition
= x
;
295 int32_t getMinimumExponentDigits() const {
296 return fEffPrecision
.fMinExponentDigits
;
298 void setMinimumExponentDigits(int32_t x
) {
299 fEffPrecision
.fMinExponentDigits
= x
;
301 UBool
isExponentSignAlwaysShown() const {
302 return fOptions
.fExponent
.fAlwaysShowSign
;
304 void setExponentSignAlwaysShown(UBool x
) {
305 fOptions
.fExponent
.fAlwaysShowSign
= x
;
307 UBool
isDecimalSeparatorAlwaysShown() const {
308 return fOptions
.fMantissa
.fAlwaysShowDecimal
;
310 void setDecimalSeparatorAlwaysShown(UBool x
) {
311 fOptions
.fMantissa
.fAlwaysShowDecimal
= x
;
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;
326 VisibleDigitsWithExponent
&
327 initVisibleDigitsWithExponent(
329 VisibleDigitsWithExponent
&digits
,
330 UErrorCode
&status
) const;
331 VisibleDigitsWithExponent
&
332 initVisibleDigitsWithExponent(
334 VisibleDigitsWithExponent
&digits
,
335 UErrorCode
&status
) const;
336 VisibleDigitsWithExponent
&
337 initVisibleDigitsWithExponent(
339 VisibleDigitsWithExponent
&digits
,
340 UErrorCode
&status
) const;
342 void updatePrecision();
343 void updateGrouping();
344 void updateCurrency(UErrorCode
&status
);
348 // Disallow copy and assign
349 DecimalFormatImpl(const DecimalFormatImpl
&other
);
350 DecimalFormatImpl
&operator=(const DecimalFormatImpl
&other
);
351 NumberFormat
*fSuper
;
352 DigitList fMultiplier
;
355 DecimalFormat::ERoundingMode fRoundingMode
;
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
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
;
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.
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.
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.
398 // Optional may be NULL
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.
404 AffixPatternParser fAffixParser
;
405 CurrencyAffixInfo fCurrencyAffixInfo
;
407 // The actual precision used when formatting
408 ScientificPrecision fEffPrecision
;
410 // The actual grouping used when formatting
411 DigitGrouping fEffGrouping
;
412 SciFormatterOptions fOptions
; // Encapsulates fixed precision options
413 DigitFormatter fFormatter
;
414 DigitAffixesAndPadding fAffixes
;
416 UnicodeString
&formatInt32(
418 UnicodeString
&appendTo
,
419 FieldPositionHandler
&handler
,
420 UErrorCode
&status
) const;
422 UnicodeString
&formatInt64(
424 UnicodeString
&appendTo
,
425 FieldPositionHandler
&handler
,
426 UErrorCode
&status
) const;
428 UnicodeString
&formatDouble(
430 UnicodeString
&appendTo
,
431 FieldPositionHandler
&handler
,
432 UErrorCode
&status
) const;
434 // Scales for precent or permille symbols
435 UnicodeString
&formatDigitList(
437 UnicodeString
&appendTo
,
438 FieldPositionHandler
&handler
,
439 UErrorCode
&status
) const;
441 // Does not scale for precent or permille symbols
442 UnicodeString
&formatAdjustedDigitList(
444 UnicodeString
&appendTo
,
445 FieldPositionHandler
&handler
,
446 UErrorCode
&status
) const;
448 UnicodeString
&formatVisibleDigitsWithExponent(
449 const VisibleDigitsWithExponent
&number
,
450 UnicodeString
&appendTo
,
451 FieldPositionHandler
&handler
,
452 UErrorCode
&status
) const;
454 VisibleDigitsWithExponent
&
455 initVisibleDigitsFromAdjusted(
457 VisibleDigitsWithExponent
&digits
,
458 UErrorCode
&status
) const;
461 UBool
maybeFormatWithDigitList(
463 UnicodeString
&appendTo
,
464 FieldPositionHandler
&handler
,
465 UErrorCode
&status
) const;
468 UBool
maybeInitVisibleDigitsFromDigitList(
470 VisibleDigitsWithExponent
&digits
,
471 UErrorCode
&status
) const;
473 DigitList
&adjustDigitList(DigitList
&number
, UErrorCode
&status
) const;
476 const UnicodeString
&pattern
,
477 UBool localized
, UParseError
&perror
, UErrorCode
&status
);
479 ValueFormatter
&prepareValueFormatter(ValueFormatter
&vf
) const;
480 void setMultiplierScale(int32_t s
);
481 int32_t getPatternScale() const;
482 void setScale(int32_t s
) { fScale
= s
; }
483 int32_t getScale() const { return fScale
; }
485 // Updates everything
486 void updateAll(UErrorCode
&status
);
488 int32_t formattingFlags
,
489 UBool updatePrecisionBasedOnCurrency
,
492 // Updates from formatting pattern changes
493 void updateForApplyPattern(UErrorCode
&status
);
494 void updateForApplyPatternFavorCurrencyPrecision(UErrorCode
&status
);
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
,
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;
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
,
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
);
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;
534 int32_t getOldFormatWidth() const;
535 const UnicodeString
&getConstSymbol(
536 DecimalFormatSymbols::ENumberFormatSymbol symbol
) const;
537 UBool
isParseFastpath() const;
539 friend class DecimalFormat
;
545 #endif /* #if !UCONFIG_NO_FORMATTING */
546 #endif // DECIMFMTIMPL_H