Line data Source code
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 :
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);
178 0 : const DecimalFormatSymbols &getDecimalFormatSymbols() const {
179 0 : 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 :
243 0 : void setRoundingMode(DecimalFormat::ERoundingMode mode) {
244 0 : fRoundingMode = mode;
245 0 : fEffPrecision.fMantissa.fExactOnly = (fRoundingMode == DecimalFormat::kRoundUnnecessary);
246 0 : fEffPrecision.fMantissa.fRoundingMode = mode;
247 0 : }
248 0 : DecimalFormat::ERoundingMode getRoundingMode() const {
249 0 : return fRoundingMode;
250 : }
251 0 : void setFailIfMoreThanMaxDigits(UBool b) {
252 0 : fEffPrecision.fMantissa.fFailIfOverMax = b;
253 0 : }
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 :
261 0 : int32_t getMinimumSignificantDigits() const {
262 0 : return fMinSigDigits; }
263 0 : int32_t getMaximumSignificantDigits() const {
264 0 : return fMaxSigDigits; }
265 0 : UBool isScientificNotation() const { return fUseScientific; }
266 0 : UBool areSignificantDigitsUsed() const { return fUseSigDigits; }
267 : void setGroupingSize(int32_t newValue);
268 : void setSecondaryGroupingSize(int32_t newValue);
269 : void setMinimumGroupingDigits(int32_t newValue);
270 0 : int32_t getGroupingSize() const { return fGrouping.fGrouping; }
271 0 : int32_t getSecondaryGroupingSize() const { return fGrouping.fGrouping2; }
272 0 : 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);
282 0 : 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 0 : UChar32 getPadCharacter() const { return fAffixes.fPadChar; }
288 0 : void setPadCharacter(UChar32 c) { fAffixes.fPadChar = c; }
289 0 : int32_t getFormatWidth() const { return fAffixes.fWidth; }
290 0 : void setFormatWidth(int32_t x) { fAffixes.fWidth = x; }
291 0 : DigitAffixesAndPadding::EPadPosition getPadPosition() const {
292 0 : return fAffixes.fPadPosition;
293 : }
294 0 : void setPadPosition(DigitAffixesAndPadding::EPadPosition x) {
295 0 : fAffixes.fPadPosition = x;
296 0 : }
297 0 : int32_t getMinimumExponentDigits() const {
298 0 : return fEffPrecision.fMinExponentDigits;
299 : }
300 0 : void setMinimumExponentDigits(int32_t x) {
301 0 : fEffPrecision.fMinExponentDigits = x;
302 0 : }
303 0 : UBool isExponentSignAlwaysShown() const {
304 0 : return fOptions.fExponent.fAlwaysShowSign;
305 : }
306 0 : void setExponentSignAlwaysShown(UBool x) {
307 0 : fOptions.fExponent.fAlwaysShowSign = x;
308 0 : }
309 0 : UBool isDecimalSeparatorAlwaysShown() const {
310 0 : return fOptions.fMantissa.fAlwaysShowDecimal;
311 : }
312 0 : void setDecimalSeparatorAlwaysShown(UBool x) {
313 0 : fOptions.fMantissa.fAlwaysShowDecimal = x;
314 0 : }
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;
484 0 : void setScale(int32_t s) { fScale = s; }
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
|