OLD | NEW |
1 /* | 1 /* |
2 ****************************************************************************** | 2 ****************************************************************************** |
3 * Copyright (C) 2014-2015, International Business Machines | 3 * Copyright (C) 2014-2015, International Business Machines |
4 * Corporation and others. All Rights Reserved. | 4 * Corporation and others. All Rights Reserved. |
5 ****************************************************************************** | 5 ****************************************************************************** |
6 * quantityformatter.cpp | 6 * quantityformatter.cpp |
7 */ | 7 */ |
| 8 |
| 9 #include "unicode/utypes.h" |
| 10 |
| 11 #if !UCONFIG_NO_FORMATTING |
| 12 |
8 #include "quantityformatter.h" | 13 #include "quantityformatter.h" |
9 #include "simplepatternformatter.h" | 14 #include "simplepatternformatter.h" |
10 #include "uassert.h" | 15 #include "uassert.h" |
11 #include "unicode/unistr.h" | 16 #include "unicode/unistr.h" |
12 #include "unicode/decimfmt.h" | 17 #include "unicode/decimfmt.h" |
13 #include "cstring.h" | 18 #include "cstring.h" |
14 #include "unicode/plurrule.h" | 19 #include "unicode/plurrule.h" |
15 #include "charstr.h" | 20 #include "charstr.h" |
16 #include "unicode/fmtable.h" | 21 #include "unicode/fmtable.h" |
17 #include "unicode/fieldpos.h" | 22 #include "unicode/fieldpos.h" |
| 23 #include "standardplural.h" |
18 #include "visibledigits.h" | 24 #include "visibledigits.h" |
19 | 25 #include "uassert.h" |
20 #if !UCONFIG_NO_FORMATTING | |
21 | 26 |
22 U_NAMESPACE_BEGIN | 27 U_NAMESPACE_BEGIN |
23 | 28 |
24 // other must always be first. | |
25 static const char * const gPluralForms[] = { | |
26 "other", "zero", "one", "two", "few", "many"}; | |
27 | |
28 static int32_t getPluralIndex(const char *pluralForm) { | |
29 int32_t len = UPRV_LENGTHOF(gPluralForms); | |
30 for (int32_t i = 0; i < len; ++i) { | |
31 if (uprv_strcmp(pluralForm, gPluralForms[i]) == 0) { | |
32 return i; | |
33 } | |
34 } | |
35 return -1; | |
36 } | |
37 | |
38 QuantityFormatter::QuantityFormatter() { | 29 QuantityFormatter::QuantityFormatter() { |
39 for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) { | 30 for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) { |
40 formatters[i] = NULL; | 31 formatters[i] = NULL; |
41 } | 32 } |
42 } | 33 } |
43 | 34 |
44 QuantityFormatter::QuantityFormatter(const QuantityFormatter &other) { | 35 QuantityFormatter::QuantityFormatter(const QuantityFormatter &other) { |
45 for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) { | 36 for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) { |
46 if (other.formatters[i] == NULL) { | 37 if (other.formatters[i] == NULL) { |
47 formatters[i] = NULL; | 38 formatters[i] = NULL; |
(...skipping 25 matching lines...) Expand all Loading... |
73 } | 64 } |
74 } | 65 } |
75 | 66 |
76 void QuantityFormatter::reset() { | 67 void QuantityFormatter::reset() { |
77 for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) { | 68 for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) { |
78 delete formatters[i]; | 69 delete formatters[i]; |
79 formatters[i] = NULL; | 70 formatters[i] = NULL; |
80 } | 71 } |
81 } | 72 } |
82 | 73 |
83 UBool QuantityFormatter::add( | 74 UBool QuantityFormatter::addIfAbsent( |
84 const char *variant, | 75 const char *variant, |
85 const UnicodeString &rawPattern, | 76 const UnicodeString &rawPattern, |
86 UErrorCode &status) { | 77 UErrorCode &status) { |
| 78 int32_t pluralIndex = StandardPlural::indexFromString(variant, status); |
87 if (U_FAILURE(status)) { | 79 if (U_FAILURE(status)) { |
88 return FALSE; | 80 return FALSE; |
89 } | 81 } |
90 int32_t pluralIndex = getPluralIndex(variant); | 82 if (formatters[pluralIndex] != NULL) { |
91 if (pluralIndex == -1) { | 83 return TRUE; |
92 status = U_ILLEGAL_ARGUMENT_ERROR; | |
93 return FALSE; | |
94 } | 84 } |
95 SimplePatternFormatter *newFmt = | 85 SimplePatternFormatter *newFmt = new SimplePatternFormatter(rawPattern, 0, 1
, status); |
96 new SimplePatternFormatter(rawPattern); | |
97 if (newFmt == NULL) { | 86 if (newFmt == NULL) { |
98 status = U_MEMORY_ALLOCATION_ERROR; | 87 status = U_MEMORY_ALLOCATION_ERROR; |
99 return FALSE; | 88 return FALSE; |
100 } | 89 } |
101 if (newFmt->getPlaceholderCount() > 1) { | 90 if (U_FAILURE(status)) { |
102 delete newFmt; | 91 delete newFmt; |
103 status = U_ILLEGAL_ARGUMENT_ERROR; | |
104 return FALSE; | 92 return FALSE; |
105 } | 93 } |
106 delete formatters[pluralIndex]; | |
107 formatters[pluralIndex] = newFmt; | 94 formatters[pluralIndex] = newFmt; |
108 return TRUE; | 95 return TRUE; |
109 } | 96 } |
110 | 97 |
111 UBool QuantityFormatter::isValid() const { | 98 UBool QuantityFormatter::isValid() const { |
112 return formatters[0] != NULL; | 99 return formatters[StandardPlural::OTHER] != NULL; |
113 } | 100 } |
114 | 101 |
115 const SimplePatternFormatter *QuantityFormatter::getByVariant( | 102 const SimplePatternFormatter *QuantityFormatter::getByVariant( |
116 const char *variant) const { | 103 const char *variant) const { |
117 int32_t pluralIndex = getPluralIndex(variant); | 104 U_ASSERT(isValid()); |
118 if (pluralIndex == -1) { | 105 int32_t pluralIndex = StandardPlural::indexOrOtherIndexFromString(variant); |
119 pluralIndex = 0; | |
120 } | |
121 const SimplePatternFormatter *pattern = formatters[pluralIndex]; | 106 const SimplePatternFormatter *pattern = formatters[pluralIndex]; |
122 if (pattern == NULL) { | 107 if (pattern == NULL) { |
123 pattern = formatters[0]; | 108 pattern = formatters[StandardPlural::OTHER]; |
124 } | 109 } |
125 return pattern; | 110 return pattern; |
126 } | 111 } |
127 | 112 |
128 UnicodeString &QuantityFormatter::format( | 113 UnicodeString &QuantityFormatter::format( |
129 const Formattable& quantity, | 114 const Formattable &number, |
130 const NumberFormat &fmt, | 115 const NumberFormat &fmt, |
131 const PluralRules &rules, | 116 const PluralRules &rules, |
132 UnicodeString &appendTo, | 117 UnicodeString &appendTo, |
133 FieldPosition &pos, | 118 FieldPosition &pos, |
134 UErrorCode &status) const { | 119 UErrorCode &status) const { |
| 120 UnicodeString formattedNumber; |
| 121 StandardPlural::Form p = selectPlural(number, fmt, rules, formattedNumber, p
os, status); |
135 if (U_FAILURE(status)) { | 122 if (U_FAILURE(status)) { |
136 return appendTo; | 123 return appendTo; |
137 } | 124 } |
138 UnicodeString count; | 125 const SimplePatternFormatter *pattern = formatters[p]; |
| 126 if (pattern == NULL) { |
| 127 pattern = formatters[StandardPlural::OTHER]; |
| 128 if (pattern == NULL) { |
| 129 status = U_INVALID_STATE_ERROR; |
| 130 return appendTo; |
| 131 } |
| 132 } |
| 133 return format(*pattern, formattedNumber, appendTo, pos, status); |
| 134 } |
| 135 |
| 136 // The following methods live here so that class PluralRules does not depend on
number formatting, |
| 137 // and the SimplePatternFormatter does not depend on FieldPosition. |
| 138 |
| 139 StandardPlural::Form QuantityFormatter::selectPlural( |
| 140 const Formattable &number, |
| 141 const NumberFormat &fmt, |
| 142 const PluralRules &rules, |
| 143 UnicodeString &formattedNumber, |
| 144 FieldPosition &pos, |
| 145 UErrorCode &status) { |
| 146 if (U_FAILURE(status)) { |
| 147 return StandardPlural::OTHER; |
| 148 } |
| 149 UnicodeString pluralKeyword; |
139 VisibleDigitsWithExponent digits; | 150 VisibleDigitsWithExponent digits; |
140 const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(&fmt); | 151 const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(&fmt); |
141 if (decFmt != NULL) { | 152 if (decFmt != NULL) { |
142 decFmt->initVisibleDigitsWithExponent(quantity, digits, status); | 153 decFmt->initVisibleDigitsWithExponent(number, digits, status); |
143 if (U_FAILURE(status)) { | 154 if (U_FAILURE(status)) { |
144 return appendTo; | 155 return StandardPlural::OTHER; |
145 } | 156 } |
146 count = rules.select(digits); | 157 pluralKeyword = rules.select(digits); |
| 158 decFmt->format(digits, formattedNumber, pos, status); |
147 } else { | 159 } else { |
148 if (quantity.getType() == Formattable::kDouble) { | 160 if (number.getType() == Formattable::kDouble) { |
149 count = rules.select(quantity.getDouble()); | 161 pluralKeyword = rules.select(number.getDouble()); |
150 } else if (quantity.getType() == Formattable::kLong) { | 162 } else if (number.getType() == Formattable::kLong) { |
151 count = rules.select(quantity.getLong()); | 163 pluralKeyword = rules.select(number.getLong()); |
152 } else if (quantity.getType() == Formattable::kInt64) { | 164 } else if (number.getType() == Formattable::kInt64) { |
153 count = rules.select((double) quantity.getInt64()); | 165 pluralKeyword = rules.select((double) number.getInt64()); |
154 } else { | 166 } else { |
155 status = U_ILLEGAL_ARGUMENT_ERROR; | 167 status = U_ILLEGAL_ARGUMENT_ERROR; |
156 return appendTo; | 168 return StandardPlural::OTHER; |
157 } | 169 } |
| 170 fmt.format(number, formattedNumber, pos, status); |
158 } | 171 } |
159 CharString buffer; | 172 return StandardPlural::orOtherFromString(pluralKeyword); |
160 buffer.appendInvariantChars(count, status); | 173 } |
| 174 |
| 175 UnicodeString &QuantityFormatter::format( |
| 176 const SimplePatternFormatter &pattern, |
| 177 const UnicodeString &value, |
| 178 UnicodeString &appendTo, |
| 179 FieldPosition &pos, |
| 180 UErrorCode &status) { |
161 if (U_FAILURE(status)) { | 181 if (U_FAILURE(status)) { |
162 return appendTo; | 182 return appendTo; |
163 } | 183 } |
164 const SimplePatternFormatter *pattern = getByVariant(buffer.data()); | 184 const UnicodeString *param = &value; |
165 if (pattern == NULL) { | 185 int32_t offset; |
166 status = U_INVALID_STATE_ERROR; | 186 pattern.formatAndAppend(¶m, 1, appendTo, &offset, 1, status); |
167 return appendTo; | 187 if (pos.getBeginIndex() != 0 || pos.getEndIndex() != 0) { |
168 } | 188 if (offset >= 0) { |
169 UnicodeString formattedNumber; | 189 pos.setBeginIndex(pos.getBeginIndex() + offset); |
170 FieldPosition fpos(pos.getField()); | 190 pos.setEndIndex(pos.getEndIndex() + offset); |
171 if (decFmt != NULL) { | 191 } else { |
172 decFmt->format(digits, formattedNumber, fpos, status); | 192 pos.setBeginIndex(0); |
173 } else { | 193 pos.setEndIndex(0); |
174 fmt.format(quantity, formattedNumber, fpos, status); | |
175 } | |
176 const UnicodeString *params[1] = {&formattedNumber}; | |
177 int32_t offsets[1]; | |
178 pattern->formatAndAppend( | |
179 params, | |
180 UPRV_LENGTHOF(params), | |
181 appendTo, | |
182 offsets, | |
183 UPRV_LENGTHOF(offsets), | |
184 status); | |
185 if (offsets[0] != -1) { | |
186 if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) { | |
187 pos.setBeginIndex(fpos.getBeginIndex() + offsets[0]); | |
188 pos.setEndIndex(fpos.getEndIndex() + offsets[0]); | |
189 } | 194 } |
190 } | 195 } |
191 return appendTo; | 196 return appendTo; |
192 } | 197 } |
193 | 198 |
194 U_NAMESPACE_END | 199 U_NAMESPACE_END |
195 | 200 |
196 #endif /* #if !UCONFIG_NO_FORMATTING */ | 201 #endif /* #if !UCONFIG_NO_FORMATTING */ |
OLD | NEW |