]> git.saurik.com Git - apple/icu.git/blob - icuSources/i18n/quantityformatter.cpp
ICU-531.30.tar.gz
[apple/icu.git] / icuSources / i18n / quantityformatter.cpp
1 /*
2 ******************************************************************************
3 * Copyright (C) 2014, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 ******************************************************************************
6 * quantityformatter.cpp
7 */
8 #include "quantityformatter.h"
9 #include "simplepatternformatter.h"
10 #include "uassert.h"
11 #include "unicode/unistr.h"
12 #include "unicode/decimfmt.h"
13 #include "cstring.h"
14 #include "plurrule_impl.h"
15 #include "unicode/plurrule.h"
16 #include "charstr.h"
17 #include "unicode/fmtable.h"
18 #include "unicode/fieldpos.h"
19
20 #define LENGTHOF(array) (int32_t)(sizeof(array) / sizeof((array)[0]))
21
22 #if !UCONFIG_NO_FORMATTING
23
24 U_NAMESPACE_BEGIN
25
26 // other must always be first.
27 static const char * const gPluralForms[] = {
28 "other", "zero", "one", "two", "few", "many"};
29
30 static int32_t getPluralIndex(const char *pluralForm) {
31 int32_t len = LENGTHOF(gPluralForms);
32 for (int32_t i = 0; i < len; ++i) {
33 if (uprv_strcmp(pluralForm, gPluralForms[i]) == 0) {
34 return i;
35 }
36 }
37 return -1;
38 }
39
40 QuantityFormatter::QuantityFormatter() {
41 for (int32_t i = 0; i < LENGTHOF(formatters); ++i) {
42 formatters[i] = NULL;
43 }
44 }
45
46 QuantityFormatter::QuantityFormatter(const QuantityFormatter &other) {
47 for (int32_t i = 0; i < LENGTHOF(formatters); ++i) {
48 if (other.formatters[i] == NULL) {
49 formatters[i] = NULL;
50 } else {
51 formatters[i] = new SimplePatternFormatter(*other.formatters[i]);
52 }
53 }
54 }
55
56 QuantityFormatter &QuantityFormatter::operator=(
57 const QuantityFormatter& other) {
58 if (this == &other) {
59 return *this;
60 }
61 for (int32_t i = 0; i < LENGTHOF(formatters); ++i) {
62 delete formatters[i];
63 if (other.formatters[i] == NULL) {
64 formatters[i] = NULL;
65 } else {
66 formatters[i] = new SimplePatternFormatter(*other.formatters[i]);
67 }
68 }
69 return *this;
70 }
71
72 QuantityFormatter::~QuantityFormatter() {
73 for (int32_t i = 0; i < LENGTHOF(formatters); ++i) {
74 delete formatters[i];
75 }
76 }
77
78 void QuantityFormatter::reset() {
79 for (int32_t i = 0; i < LENGTHOF(formatters); ++i) {
80 delete formatters[i];
81 formatters[i] = NULL;
82 }
83 }
84
85 UBool QuantityFormatter::add(
86 const char *variant,
87 const UnicodeString &rawPattern,
88 UErrorCode &status) {
89 if (U_FAILURE(status)) {
90 return FALSE;
91 }
92 int32_t pluralIndex = getPluralIndex(variant);
93 if (pluralIndex == -1) {
94 status = U_ILLEGAL_ARGUMENT_ERROR;
95 return FALSE;
96 }
97 SimplePatternFormatter *newFmt =
98 new SimplePatternFormatter(rawPattern);
99 if (newFmt == NULL) {
100 status = U_MEMORY_ALLOCATION_ERROR;
101 return FALSE;
102 }
103 if (newFmt->getPlaceholderCount() > 1) {
104 delete newFmt;
105 status = U_ILLEGAL_ARGUMENT_ERROR;
106 return FALSE;
107 }
108 delete formatters[pluralIndex];
109 formatters[pluralIndex] = newFmt;
110 return TRUE;
111 }
112
113 UBool QuantityFormatter::isValid() const {
114 return formatters[0] != NULL;
115 }
116
117 UnicodeString &QuantityFormatter::format(
118 const Formattable& quantity,
119 const NumberFormat &fmt,
120 const PluralRules &rules,
121 UnicodeString &appendTo,
122 FieldPosition &pos,
123 UErrorCode &status) const {
124 if (U_FAILURE(status)) {
125 return appendTo;
126 }
127 UnicodeString count;
128 const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(&fmt);
129 if (decFmt != NULL) {
130 FixedDecimal fd = decFmt->getFixedDecimal(quantity, status);
131 if (U_FAILURE(status)) {
132 return appendTo;
133 }
134 count = rules.select(fd);
135 } else {
136 if (quantity.getType() == Formattable::kDouble) {
137 count = rules.select(quantity.getDouble());
138 } else if (quantity.getType() == Formattable::kLong) {
139 count = rules.select(quantity.getLong());
140 } else if (quantity.getType() == Formattable::kInt64) {
141 count = rules.select((double) quantity.getInt64());
142 } else {
143 status = U_ILLEGAL_ARGUMENT_ERROR;
144 return appendTo;
145 }
146 }
147 CharString buffer;
148 buffer.appendInvariantChars(count, status);
149 if (U_FAILURE(status)) {
150 return appendTo;
151 }
152 int32_t pluralIndex = getPluralIndex(buffer.data());
153 if (pluralIndex == -1) {
154 pluralIndex = 0;
155 }
156 const SimplePatternFormatter *pattern = formatters[pluralIndex];
157 if (pattern == NULL) {
158 pattern = formatters[0];
159 }
160 if (pattern == NULL) {
161 status = U_INVALID_STATE_ERROR;
162 return appendTo;
163 }
164 UnicodeString formattedNumber;
165 FieldPosition fpos(pos.getField());
166 fmt.format(quantity, formattedNumber, fpos, status);
167 const UnicodeString *params[1] = {&formattedNumber};
168 int32_t offsets[1];
169 pattern->format(params, LENGTHOF(params), appendTo, offsets, LENGTHOF(offsets), status);
170 if (offsets[0] != -1) {
171 if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) {
172 pos.setBeginIndex(fpos.getBeginIndex() + offsets[0]);
173 pos.setEndIndex(fpos.getEndIndex() + offsets[0]);
174 }
175 }
176 return appendTo;
177 }
178
179 U_NAMESPACE_END
180
181 #endif /* #if !UCONFIG_NO_FORMATTING */