blob: 9182f9e7d379a84f47ed11c5f283a4dbe3118343 [file] [log] [blame]
Jungshik Shin87232d82017-05-13 21:10:13 -07001// © 2016 and later: Unicode, Inc. and others.
Jungshik Shin5feb9ad2016-10-21 12:52:48 -07002// License & terms of use: http://www.unicode.org/copyright.html
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08003/*
4******************************************************************************
Jungshik Shin5feb9ad2016-10-21 12:52:48 -07005* Copyright (C) 2014-2016, International Business Machines
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08006* Corporation and others. All Rights Reserved.
7******************************************************************************
8* quantityformatter.cpp
9*/
Jungshik Shin825221b2016-01-29 01:05:51 -080010
11#include "unicode/utypes.h"
12
13#if !UCONFIG_NO_FORMATTING
14
Jungshik Shin5feb9ad2016-10-21 12:52:48 -070015#include "unicode/simpleformatter.h"
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080016#include "quantityformatter.h"
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080017#include "uassert.h"
18#include "unicode/unistr.h"
19#include "unicode/decimfmt.h"
20#include "cstring.h"
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080021#include "unicode/plurrule.h"
22#include "charstr.h"
23#include "unicode/fmtable.h"
24#include "unicode/fieldpos.h"
Jungshik Shin825221b2016-01-29 01:05:51 -080025#include "standardplural.h"
Jungshik Shin825221b2016-01-29 01:05:51 -080026#include "uassert.h"
Jungshik Shina9a2bd32018-07-07 03:36:01 -070027#include "number_decimalquantity.h"
Frank Tang69c72a62019-04-03 21:41:21 -070028#include "number_utypes.h"
29#include "number_stringbuilder.h"
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080030
31U_NAMESPACE_BEGIN
32
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080033QuantityFormatter::QuantityFormatter() {
34 for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
35 formatters[i] = NULL;
36 }
37}
38
39QuantityFormatter::QuantityFormatter(const QuantityFormatter &other) {
40 for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
41 if (other.formatters[i] == NULL) {
42 formatters[i] = NULL;
43 } else {
Jungshik Shin5feb9ad2016-10-21 12:52:48 -070044 formatters[i] = new SimpleFormatter(*other.formatters[i]);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080045 }
46 }
47}
48
49QuantityFormatter &QuantityFormatter::operator=(
50 const QuantityFormatter& other) {
51 if (this == &other) {
52 return *this;
53 }
54 for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
55 delete formatters[i];
56 if (other.formatters[i] == NULL) {
57 formatters[i] = NULL;
58 } else {
Jungshik Shin5feb9ad2016-10-21 12:52:48 -070059 formatters[i] = new SimpleFormatter(*other.formatters[i]);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080060 }
61 }
62 return *this;
63}
64
65QuantityFormatter::~QuantityFormatter() {
66 for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
67 delete formatters[i];
68 }
69}
70
71void QuantityFormatter::reset() {
72 for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
73 delete formatters[i];
74 formatters[i] = NULL;
75 }
76}
77
Jungshik Shin825221b2016-01-29 01:05:51 -080078UBool QuantityFormatter::addIfAbsent(
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080079 const char *variant,
80 const UnicodeString &rawPattern,
81 UErrorCode &status) {
Jungshik Shin825221b2016-01-29 01:05:51 -080082 int32_t pluralIndex = StandardPlural::indexFromString(variant, status);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080083 if (U_FAILURE(status)) {
84 return FALSE;
85 }
Jungshik Shin825221b2016-01-29 01:05:51 -080086 if (formatters[pluralIndex] != NULL) {
87 return TRUE;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080088 }
Jungshik Shin5feb9ad2016-10-21 12:52:48 -070089 SimpleFormatter *newFmt = new SimpleFormatter(rawPattern, 0, 1, status);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080090 if (newFmt == NULL) {
91 status = U_MEMORY_ALLOCATION_ERROR;
92 return FALSE;
93 }
Jungshik Shin825221b2016-01-29 01:05:51 -080094 if (U_FAILURE(status)) {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080095 delete newFmt;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080096 return FALSE;
97 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080098 formatters[pluralIndex] = newFmt;
99 return TRUE;
100}
101
102UBool QuantityFormatter::isValid() const {
Jungshik Shin825221b2016-01-29 01:05:51 -0800103 return formatters[StandardPlural::OTHER] != NULL;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800104}
105
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700106const SimpleFormatter *QuantityFormatter::getByVariant(
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800107 const char *variant) const {
Jungshik Shin825221b2016-01-29 01:05:51 -0800108 U_ASSERT(isValid());
109 int32_t pluralIndex = StandardPlural::indexOrOtherIndexFromString(variant);
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700110 const SimpleFormatter *pattern = formatters[pluralIndex];
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800111 if (pattern == NULL) {
Jungshik Shin825221b2016-01-29 01:05:51 -0800112 pattern = formatters[StandardPlural::OTHER];
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800113 }
114 return pattern;
115}
116
117UnicodeString &QuantityFormatter::format(
Jungshik Shin825221b2016-01-29 01:05:51 -0800118 const Formattable &number,
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800119 const NumberFormat &fmt,
120 const PluralRules &rules,
121 UnicodeString &appendTo,
122 FieldPosition &pos,
123 UErrorCode &status) const {
Jungshik Shin825221b2016-01-29 01:05:51 -0800124 UnicodeString formattedNumber;
125 StandardPlural::Form p = selectPlural(number, fmt, rules, formattedNumber, pos, status);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800126 if (U_FAILURE(status)) {
127 return appendTo;
128 }
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700129 const SimpleFormatter *pattern = formatters[p];
Jungshik Shin825221b2016-01-29 01:05:51 -0800130 if (pattern == NULL) {
131 pattern = formatters[StandardPlural::OTHER];
132 if (pattern == NULL) {
133 status = U_INVALID_STATE_ERROR;
134 return appendTo;
135 }
136 }
137 return format(*pattern, formattedNumber, appendTo, pos, status);
138}
139
140// The following methods live here so that class PluralRules does not depend on number formatting,
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700141// and the SimpleFormatter does not depend on FieldPosition.
Jungshik Shin825221b2016-01-29 01:05:51 -0800142
143StandardPlural::Form QuantityFormatter::selectPlural(
144 const Formattable &number,
145 const NumberFormat &fmt,
146 const PluralRules &rules,
147 UnicodeString &formattedNumber,
148 FieldPosition &pos,
149 UErrorCode &status) {
150 if (U_FAILURE(status)) {
151 return StandardPlural::OTHER;
152 }
153 UnicodeString pluralKeyword;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800154 const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(&fmt);
155 if (decFmt != NULL) {
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700156 number::impl::DecimalQuantity dq;
157 decFmt->formatToDecimalQuantity(number, dq, status);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800158 if (U_FAILURE(status)) {
Jungshik Shin825221b2016-01-29 01:05:51 -0800159 return StandardPlural::OTHER;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800160 }
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700161 pluralKeyword = rules.select(dq);
162 decFmt->format(number, formattedNumber, pos, status);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800163 } else {
Jungshik Shin825221b2016-01-29 01:05:51 -0800164 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());
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800170 } else {
171 status = U_ILLEGAL_ARGUMENT_ERROR;
Jungshik Shin825221b2016-01-29 01:05:51 -0800172 return StandardPlural::OTHER;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800173 }
Jungshik Shin825221b2016-01-29 01:05:51 -0800174 fmt.format(number, formattedNumber, pos, status);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800175 }
Jungshik Shin825221b2016-01-29 01:05:51 -0800176 return StandardPlural::orOtherFromString(pluralKeyword);
177}
178
Frank Tang69c72a62019-04-03 21:41:21 -0700179void QuantityFormatter::formatAndSelect(
180 double quantity,
181 const NumberFormat& fmt,
182 const PluralRules& rules,
183 number::impl::NumberStringBuilder& output,
184 StandardPlural::Form& pluralForm,
185 UErrorCode& status) {
186 UnicodeString pluralKeyword;
187 const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(&fmt);
188 if (df != nullptr) {
189 number::impl::UFormattedNumberData fn;
190 fn.quantity.setToDouble(quantity);
191 df->toNumberFormatter().formatImpl(&fn, status);
192 if (U_FAILURE(status)) {
193 return;
194 }
195 output = std::move(fn.getStringRef());
196 pluralKeyword = rules.select(fn.quantity);
197 } else {
198 UnicodeString result;
199 fmt.format(quantity, result, status);
200 if (U_FAILURE(status)) {
201 return;
202 }
203 output.append(result, UNUM_FIELD_COUNT, status);
204 if (U_FAILURE(status)) {
205 return;
206 }
207 pluralKeyword = rules.select(quantity);
208 }
209 pluralForm = StandardPlural::orOtherFromString(pluralKeyword);
210}
211
Jungshik Shin825221b2016-01-29 01:05:51 -0800212UnicodeString &QuantityFormatter::format(
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700213 const SimpleFormatter &pattern,
Jungshik Shin825221b2016-01-29 01:05:51 -0800214 const UnicodeString &value,
215 UnicodeString &appendTo,
216 FieldPosition &pos,
217 UErrorCode &status) {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800218 if (U_FAILURE(status)) {
219 return appendTo;
220 }
Jungshik Shin825221b2016-01-29 01:05:51 -0800221 const UnicodeString *param = &value;
222 int32_t offset;
223 pattern.formatAndAppend(&param, 1, appendTo, &offset, 1, status);
224 if (pos.getBeginIndex() != 0 || pos.getEndIndex() != 0) {
225 if (offset >= 0) {
226 pos.setBeginIndex(pos.getBeginIndex() + offset);
227 pos.setEndIndex(pos.getEndIndex() + offset);
228 } else {
229 pos.setBeginIndex(0);
230 pos.setEndIndex(0);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800231 }
232 }
233 return appendTo;
234}
235
236U_NAMESPACE_END
237
238#endif /* #if !UCONFIG_NO_FORMATTING */