1 /*
2 ******************************************************************************
3 * Copyright (C) 2014-2015, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 ******************************************************************************
6 * quantityformatter.cpp
7 */
8
9 #include "unicode/utypes.h"
10
11 #if !UCONFIG_NO_FORMATTING
12
13 #include "quantityformatter.h"
14 #include "simplepatternformatter.h"
15 #include "uassert.h"
16 #include "unicode/unistr.h"
17 #include "unicode/decimfmt.h"
18 #include "cstring.h"
19 #include "unicode/plurrule.h"
20 #include "charstr.h"
21 #include "unicode/fmtable.h"
22 #include "unicode/fieldpos.h"
23 #include "standardplural.h"
24 #include "visibledigits.h"
25 #include "uassert.h"
26
27 U_NAMESPACE_BEGIN
28
QuantityFormatter()29 QuantityFormatter::QuantityFormatter() {
30 for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
31 formatters[i] = NULL;
32 }
33 }
34
QuantityFormatter(const QuantityFormatter & other)35 QuantityFormatter::QuantityFormatter(const QuantityFormatter &other) {
36 for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
37 if (other.formatters[i] == NULL) {
38 formatters[i] = NULL;
39 } else {
40 formatters[i] = new SimplePatternFormatter(*other.formatters[i]);
41 }
42 }
43 }
44
operator =(const QuantityFormatter & other)45 QuantityFormatter &QuantityFormatter::operator=(
46 const QuantityFormatter& other) {
47 if (this == &other) {
48 return *this;
49 }
50 for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
51 delete formatters[i];
52 if (other.formatters[i] == NULL) {
53 formatters[i] = NULL;
54 } else {
55 formatters[i] = new SimplePatternFormatter(*other.formatters[i]);
56 }
57 }
58 return *this;
59 }
60
~QuantityFormatter()61 QuantityFormatter::~QuantityFormatter() {
62 for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
63 delete formatters[i];
64 }
65 }
66
reset()67 void QuantityFormatter::reset() {
68 for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
69 delete formatters[i];
70 formatters[i] = NULL;
71 }
72 }
73
addIfAbsent(const char * variant,const UnicodeString & rawPattern,UErrorCode & status)74 UBool QuantityFormatter::addIfAbsent(
75 const char *variant,
76 const UnicodeString &rawPattern,
77 UErrorCode &status) {
78 int32_t pluralIndex = StandardPlural::indexFromString(variant, status);
79 if (U_FAILURE(status)) {
80 return FALSE;
81 }
82 if (formatters[pluralIndex] != NULL) {
83 return TRUE;
84 }
85 SimplePatternFormatter *newFmt = new SimplePatternFormatter(rawPattern, 0, 1, status);
86 if (newFmt == NULL) {
87 status = U_MEMORY_ALLOCATION_ERROR;
88 return FALSE;
89 }
90 if (U_FAILURE(status)) {
91 delete newFmt;
92 return FALSE;
93 }
94 formatters[pluralIndex] = newFmt;
95 return TRUE;
96 }
97
isValid() const98 UBool QuantityFormatter::isValid() const {
99 return formatters[StandardPlural::OTHER] != NULL;
100 }
101
getByVariant(const char * variant) const102 const SimplePatternFormatter *QuantityFormatter::getByVariant(
103 const char *variant) const {
104 U_ASSERT(isValid());
105 int32_t pluralIndex = StandardPlural::indexOrOtherIndexFromString(variant);
106 const SimplePatternFormatter *pattern = formatters[pluralIndex];
107 if (pattern == NULL) {
108 pattern = formatters[StandardPlural::OTHER];
109 }
110 return pattern;
111 }
112
format(const Formattable & number,const NumberFormat & fmt,const PluralRules & rules,UnicodeString & appendTo,FieldPosition & pos,UErrorCode & status) const113 UnicodeString &QuantityFormatter::format(
114 const Formattable &number,
115 const NumberFormat &fmt,
116 const PluralRules &rules,
117 UnicodeString &appendTo,
118 FieldPosition &pos,
119 UErrorCode &status) const {
120 UnicodeString formattedNumber;
121 StandardPlural::Form p = selectPlural(number, fmt, rules, formattedNumber, pos, status);
122 if (U_FAILURE(status)) {
123 return appendTo;
124 }
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
selectPlural(const Formattable & number,const NumberFormat & fmt,const PluralRules & rules,UnicodeString & formattedNumber,FieldPosition & pos,UErrorCode & status)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;
150 VisibleDigitsWithExponent digits;
151 const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(&fmt);
152 if (decFmt != NULL) {
153 decFmt->initVisibleDigitsWithExponent(number, digits, status);
154 if (U_FAILURE(status)) {
155 return StandardPlural::OTHER;
156 }
157 pluralKeyword = rules.select(digits);
158 decFmt->format(digits, formattedNumber, pos, status);
159 } else {
160 if (number.getType() == Formattable::kDouble) {
161 pluralKeyword = rules.select(number.getDouble());
162 } else if (number.getType() == Formattable::kLong) {
163 pluralKeyword = rules.select(number.getLong());
164 } else if (number.getType() == Formattable::kInt64) {
165 pluralKeyword = rules.select((double) number.getInt64());
166 } else {
167 status = U_ILLEGAL_ARGUMENT_ERROR;
168 return StandardPlural::OTHER;
169 }
170 fmt.format(number, formattedNumber, pos, status);
171 }
172 return StandardPlural::orOtherFromString(pluralKeyword);
173 }
174
format(const SimplePatternFormatter & pattern,const UnicodeString & value,UnicodeString & appendTo,FieldPosition & pos,UErrorCode & status)175 UnicodeString &QuantityFormatter::format(
176 const SimplePatternFormatter &pattern,
177 const UnicodeString &value,
178 UnicodeString &appendTo,
179 FieldPosition &pos,
180 UErrorCode &status) {
181 if (U_FAILURE(status)) {
182 return appendTo;
183 }
184 const UnicodeString *param = &value;
185 int32_t offset;
186 pattern.formatAndAppend(¶m, 1, appendTo, &offset, 1, status);
187 if (pos.getBeginIndex() != 0 || pos.getEndIndex() != 0) {
188 if (offset >= 0) {
189 pos.setBeginIndex(pos.getBeginIndex() + offset);
190 pos.setEndIndex(pos.getEndIndex() + offset);
191 } else {
192 pos.setBeginIndex(0);
193 pos.setEndIndex(0);
194 }
195 }
196 return appendTo;
197 }
198
199 U_NAMESPACE_END
200
201 #endif /* #if !UCONFIG_NO_FORMATTING */
202