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