1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 ******************************************************************************
5 * Copyright (C) 2014-2016, International Business Machines
6 * Corporation and others. All Rights Reserved.
7 ******************************************************************************
8 * quantityformatter.cpp
11 #include "unicode/utypes.h"
13 #if !UCONFIG_NO_FORMATTING
15 #include "unicode/simpleformatter.h"
16 #include "quantityformatter.h"
18 #include "unicode/unistr.h"
19 #include "unicode/decimfmt.h"
21 #include "unicode/plurrule.h"
23 #include "unicode/fmtable.h"
24 #include "unicode/fieldpos.h"
25 #include "standardplural.h"
27 #include "number_decimalquantity.h"
28 #include "number_utypes.h"
29 #include "formatted_string_builder.h"
33 QuantityFormatter::QuantityFormatter() {
34 for (int32_t i
= 0; i
< UPRV_LENGTHOF(formatters
); ++i
) {
39 QuantityFormatter::QuantityFormatter(const QuantityFormatter
&other
) {
40 for (int32_t i
= 0; i
< UPRV_LENGTHOF(formatters
); ++i
) {
41 if (other
.formatters
[i
] == NULL
) {
44 formatters
[i
] = new SimpleFormatter(*other
.formatters
[i
]);
49 QuantityFormatter
&QuantityFormatter::operator=(
50 const QuantityFormatter
& other
) {
54 for (int32_t i
= 0; i
< UPRV_LENGTHOF(formatters
); ++i
) {
56 if (other
.formatters
[i
] == NULL
) {
59 formatters
[i
] = new SimpleFormatter(*other
.formatters
[i
]);
65 QuantityFormatter::~QuantityFormatter() {
66 for (int32_t i
= 0; i
< UPRV_LENGTHOF(formatters
); ++i
) {
71 void QuantityFormatter::reset() {
72 for (int32_t i
= 0; i
< UPRV_LENGTHOF(formatters
); ++i
) {
78 UBool
QuantityFormatter::addIfAbsent(
80 const UnicodeString
&rawPattern
,
82 int32_t pluralIndex
= StandardPlural::indexFromString(variant
, status
);
83 if (U_FAILURE(status
)) {
86 if (formatters
[pluralIndex
] != NULL
) {
89 SimpleFormatter
*newFmt
= new SimpleFormatter(rawPattern
, 0, 1, status
);
91 status
= U_MEMORY_ALLOCATION_ERROR
;
94 if (U_FAILURE(status
)) {
98 formatters
[pluralIndex
] = newFmt
;
102 UBool
QuantityFormatter::isValid() const {
103 return formatters
[StandardPlural::OTHER
] != NULL
;
106 const SimpleFormatter
*QuantityFormatter::getByVariant(
107 const char *variant
) const {
109 int32_t pluralIndex
= StandardPlural::indexOrOtherIndexFromString(variant
);
110 const SimpleFormatter
*pattern
= formatters
[pluralIndex
];
111 if (pattern
== NULL
) {
112 pattern
= formatters
[StandardPlural::OTHER
];
117 UnicodeString
&QuantityFormatter::format(
118 const Formattable
&number
,
119 const NumberFormat
&fmt
,
120 const PluralRules
&rules
,
121 UnicodeString
&appendTo
,
123 UErrorCode
&status
) const {
124 UnicodeString formattedNumber
;
125 StandardPlural::Form p
= selectPlural(number
, fmt
, rules
, formattedNumber
, pos
, status
);
126 if (U_FAILURE(status
)) {
129 const SimpleFormatter
*pattern
= formatters
[p
];
130 if (pattern
== NULL
) {
131 pattern
= formatters
[StandardPlural::OTHER
];
132 if (pattern
== NULL
) {
133 status
= U_INVALID_STATE_ERROR
;
137 return format(*pattern
, formattedNumber
, appendTo
, pos
, status
);
140 // The following methods live here so that class PluralRules does not depend on number formatting,
141 // and the SimpleFormatter does not depend on FieldPosition.
143 StandardPlural::Form
QuantityFormatter::selectPlural(
144 const Formattable
&number
,
145 const NumberFormat
&fmt
,
146 const PluralRules
&rules
,
147 UnicodeString
&formattedNumber
,
149 UErrorCode
&status
) {
150 if (U_FAILURE(status
)) {
151 return StandardPlural::OTHER
;
153 UnicodeString pluralKeyword
;
154 const DecimalFormat
*decFmt
= dynamic_cast<const DecimalFormat
*>(&fmt
);
155 if (decFmt
!= NULL
) {
156 number::impl::DecimalQuantity dq
;
157 decFmt
->formatToDecimalQuantity(number
, dq
, status
);
158 if (U_FAILURE(status
)) {
159 return StandardPlural::OTHER
;
161 pluralKeyword
= rules
.select(dq
);
162 decFmt
->format(number
, formattedNumber
, pos
, status
);
164 if (number
.getType() == Formattable::kDouble
) {
165 pluralKeyword
= rules
.select(number
.getDouble());
166 } else if (number
.getType() == Formattable::kLong
) {
167 pluralKeyword
= rules
.select(number
.getLong());
168 } else if (number
.getType() == Formattable::kInt64
) {
169 pluralKeyword
= rules
.select((double) number
.getInt64());
171 status
= U_ILLEGAL_ARGUMENT_ERROR
;
172 return StandardPlural::OTHER
;
174 fmt
.format(number
, formattedNumber
, pos
, status
);
176 return StandardPlural::orOtherFromString(pluralKeyword
);
179 void QuantityFormatter::formatAndSelect(
181 const NumberFormat
& fmt
,
182 const PluralRules
& rules
,
183 FormattedStringBuilder
& output
,
184 StandardPlural::Form
& pluralForm
,
185 UErrorCode
& status
) {
186 UnicodeString pluralKeyword
;
187 const DecimalFormat
* df
= dynamic_cast<const DecimalFormat
*>(&fmt
);
189 number::impl::UFormattedNumberData fn
;
190 fn
.quantity
.setToDouble(quantity
);
191 const number::LocalizedNumberFormatter
* lnf
= df
->toNumberFormatter(status
);
192 if (U_FAILURE(status
)) {
195 lnf
->formatImpl(&fn
, status
);
196 if (U_FAILURE(status
)) {
199 output
= std::move(fn
.getStringRef());
200 pluralKeyword
= rules
.select(fn
.quantity
);
202 UnicodeString result
;
203 fmt
.format(quantity
, result
, status
);
204 if (U_FAILURE(status
)) {
207 output
.append(result
, UNUM_FIELD_COUNT
, status
);
208 if (U_FAILURE(status
)) {
211 pluralKeyword
= rules
.select(quantity
);
213 pluralForm
= StandardPlural::orOtherFromString(pluralKeyword
);
216 UnicodeString
&QuantityFormatter::format(
217 const SimpleFormatter
&pattern
,
218 const UnicodeString
&value
,
219 UnicodeString
&appendTo
,
221 UErrorCode
&status
) {
222 if (U_FAILURE(status
)) {
225 const UnicodeString
*param
= &value
;
227 pattern
.formatAndAppend(¶m
, 1, appendTo
, &offset
, 1, status
);
228 if (pos
.getBeginIndex() != 0 || pos
.getEndIndex() != 0) {
230 pos
.setBeginIndex(pos
.getBeginIndex() + offset
);
231 pos
.setEndIndex(pos
.getEndIndex() + offset
);
233 pos
.setBeginIndex(0);
242 #endif /* #if !UCONFIG_NO_FORMATTING */