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