1 /*
2  * Copyright (C) 2015, International Business Machines
3  * Corporation and others.  All Rights Reserved.
4  *
5  * file name: digitaffixesandpadding.cpp
6  */
7 
8 #include "unicode/utypes.h"
9 
10 #if !UCONFIG_NO_FORMATTING
11 
12 #include "unicode/plurrule.h"
13 #include "charstr.h"
14 #include "digitaffix.h"
15 #include "digitaffixesandpadding.h"
16 #include "digitlst.h"
17 #include "uassert.h"
18 #include "valueformatter.h"
19 #include "visibledigits.h"
20 
21 U_NAMESPACE_BEGIN
22 
23 UBool
needsPluralRules() const24 DigitAffixesAndPadding::needsPluralRules() const {
25     return (
26             fPositivePrefix.hasMultipleVariants() ||
27             fPositiveSuffix.hasMultipleVariants() ||
28             fNegativePrefix.hasMultipleVariants() ||
29             fNegativeSuffix.hasMultipleVariants());
30 }
31 
32 UnicodeString &
formatInt32(int32_t value,const ValueFormatter & formatter,FieldPositionHandler & handler,const PluralRules * optPluralRules,UnicodeString & appendTo,UErrorCode & status) const33 DigitAffixesAndPadding::formatInt32(
34         int32_t value,
35         const ValueFormatter &formatter,
36         FieldPositionHandler &handler,
37         const PluralRules *optPluralRules,
38         UnicodeString &appendTo,
39         UErrorCode &status) const {
40     if (U_FAILURE(status)) {
41         return appendTo;
42     }
43     if (optPluralRules != NULL || fWidth > 0 || !formatter.isFastFormattable(value)) {
44         VisibleDigitsWithExponent digits;
45         formatter.toVisibleDigitsWithExponent(
46                 (int64_t) value, digits, status);
47         return format(
48                 digits,
49                 formatter,
50                 handler,
51                 optPluralRules,
52                 appendTo,
53                 status);
54     }
55     UBool bPositive = value >= 0;
56     const DigitAffix *prefix = bPositive ? &fPositivePrefix.getOtherVariant() : &fNegativePrefix.getOtherVariant();
57     const DigitAffix *suffix = bPositive ? &fPositiveSuffix.getOtherVariant() : &fNegativeSuffix.getOtherVariant();
58     if (value < 0) {
59         value = -value;
60     }
61     prefix->format(handler, appendTo);
62     formatter.formatInt32(value, handler, appendTo);
63     return suffix->format(handler, appendTo);
64 }
65 
66 static UnicodeString &
formatAffix(const DigitAffix * affix,FieldPositionHandler & handler,UnicodeString & appendTo)67 formatAffix(
68         const DigitAffix *affix,
69         FieldPositionHandler &handler,
70         UnicodeString &appendTo) {
71     if (affix) {
72         affix->format(handler, appendTo);
73     }
74     return appendTo;
75 }
76 
77 static int32_t
countAffixChar32(const DigitAffix * affix)78 countAffixChar32(const DigitAffix *affix) {
79     if (affix) {
80         return affix->countChar32();
81     }
82     return 0;
83 }
84 
85 UnicodeString &
format(const VisibleDigitsWithExponent & digits,const ValueFormatter & formatter,FieldPositionHandler & handler,const PluralRules * optPluralRules,UnicodeString & appendTo,UErrorCode & status) const86 DigitAffixesAndPadding::format(
87         const VisibleDigitsWithExponent &digits,
88         const ValueFormatter &formatter,
89         FieldPositionHandler &handler,
90         const PluralRules *optPluralRules,
91         UnicodeString &appendTo,
92         UErrorCode &status) const {
93     if (U_FAILURE(status)) {
94         return appendTo;
95     }
96     const DigitAffix *prefix = NULL;
97     const DigitAffix *suffix = NULL;
98     if (!digits.isNaN()) {
99         UBool bPositive = !digits.isNegative();
100         const PluralAffix *pluralPrefix = bPositive ? &fPositivePrefix : &fNegativePrefix;
101         const PluralAffix *pluralSuffix = bPositive ? &fPositiveSuffix : &fNegativeSuffix;
102         if (optPluralRules == NULL || digits.isInfinite()) {
103             prefix = &pluralPrefix->getOtherVariant();
104             suffix = &pluralSuffix->getOtherVariant();
105         } else {
106             UnicodeString count(optPluralRules->select(digits));
107             prefix = &pluralPrefix->getByCategory(count);
108             suffix = &pluralSuffix->getByCategory(count);
109         }
110     }
111     if (fWidth <= 0) {
112         formatAffix(prefix, handler, appendTo);
113         formatter.format(digits, handler, appendTo);
114         return formatAffix(suffix, handler, appendTo);
115     }
116     int32_t codePointCount = countAffixChar32(prefix) + formatter.countChar32(digits) + countAffixChar32(suffix);
117     int32_t paddingCount = fWidth - codePointCount;
118     switch (fPadPosition) {
119     case kPadBeforePrefix:
120         appendPadding(paddingCount, appendTo);
121         formatAffix(prefix, handler, appendTo);
122         formatter.format(digits, handler, appendTo);
123         return formatAffix(suffix, handler, appendTo);
124     case kPadAfterPrefix:
125         formatAffix(prefix, handler, appendTo);
126         appendPadding(paddingCount, appendTo);
127         formatter.format(digits, handler, appendTo);
128         return formatAffix(suffix, handler, appendTo);
129     case kPadBeforeSuffix:
130         formatAffix(prefix, handler, appendTo);
131         formatter.format(digits, handler, appendTo);
132         appendPadding(paddingCount, appendTo);
133         return formatAffix(suffix, handler, appendTo);
134     case kPadAfterSuffix:
135         formatAffix(prefix, handler, appendTo);
136         formatter.format(digits, handler, appendTo);
137         formatAffix(suffix, handler, appendTo);
138         return appendPadding(paddingCount, appendTo);
139     default:
140         U_ASSERT(FALSE);
141         return appendTo;
142     }
143 }
144 
145 UnicodeString &
format(DigitList & value,const ValueFormatter & formatter,FieldPositionHandler & handler,const PluralRules * optPluralRules,UnicodeString & appendTo,UErrorCode & status) const146 DigitAffixesAndPadding::format(
147         DigitList &value,
148         const ValueFormatter &formatter,
149         FieldPositionHandler &handler,
150         const PluralRules *optPluralRules,
151         UnicodeString &appendTo,
152         UErrorCode &status) const {
153     VisibleDigitsWithExponent digits;
154     formatter.toVisibleDigitsWithExponent(
155             value, digits, status);
156     if (U_FAILURE(status)) {
157         return appendTo;
158     }
159     return format(
160             digits, formatter, handler, optPluralRules, appendTo, status);
161 }
162 
163 UnicodeString &
appendPadding(int32_t paddingCount,UnicodeString & appendTo) const164 DigitAffixesAndPadding::appendPadding(int32_t paddingCount, UnicodeString &appendTo) const {
165     for (int32_t i = 0; i < paddingCount; ++i) {
166         appendTo.append(fPadChar);
167     }
168     return appendTo;
169 }
170 
171 
172 U_NAMESPACE_END
173 #endif /* #if !UCONFIG_NO_FORMATTING */
174