blob: ed80b38b500d1465db2ec2388bbba08ad9ee1fb6 [file] [log] [blame]
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08001/*
2******************************************************************************
Jungshik Shin70f82502016-01-29 00:32:36 -08003* Copyright (C) 2014-2015, International Business Machines
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -08004* 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"
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080014#include "unicode/plurrule.h"
15#include "charstr.h"
16#include "unicode/fmtable.h"
17#include "unicode/fieldpos.h"
Jungshik Shin70f82502016-01-29 00:32:36 -080018#include "visibledigits.h"
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -080019
20#if !UCONFIG_NO_FORMATTING
21
22U_NAMESPACE_BEGIN
23
24// other must always be first.
25static const char * const gPluralForms[] = {
26 "other", "zero", "one", "two", "few", "many"};
27
28static int32_t getPluralIndex(const char *pluralForm) {
29 int32_t len = UPRV_LENGTHOF(gPluralForms);
30 for (int32_t i = 0; i < len; ++i) {
31 if (uprv_strcmp(pluralForm, gPluralForms[i]) == 0) {
32 return i;
33 }
34 }
35 return -1;
36}
37
38QuantityFormatter::QuantityFormatter() {
39 for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
40 formatters[i] = NULL;
41 }
42}
43
44QuantityFormatter::QuantityFormatter(const QuantityFormatter &other) {
45 for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
46 if (other.formatters[i] == NULL) {
47 formatters[i] = NULL;
48 } else {
49 formatters[i] = new SimplePatternFormatter(*other.formatters[i]);
50 }
51 }
52}
53
54QuantityFormatter &QuantityFormatter::operator=(
55 const QuantityFormatter& other) {
56 if (this == &other) {
57 return *this;
58 }
59 for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
60 delete formatters[i];
61 if (other.formatters[i] == NULL) {
62 formatters[i] = NULL;
63 } else {
64 formatters[i] = new SimplePatternFormatter(*other.formatters[i]);
65 }
66 }
67 return *this;
68}
69
70QuantityFormatter::~QuantityFormatter() {
71 for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
72 delete formatters[i];
73 }
74}
75
76void QuantityFormatter::reset() {
77 for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
78 delete formatters[i];
79 formatters[i] = NULL;
80 }
81}
82
83UBool QuantityFormatter::add(
84 const char *variant,
85 const UnicodeString &rawPattern,
86 UErrorCode &status) {
87 if (U_FAILURE(status)) {
88 return FALSE;
89 }
90 int32_t pluralIndex = getPluralIndex(variant);
91 if (pluralIndex == -1) {
92 status = U_ILLEGAL_ARGUMENT_ERROR;
93 return FALSE;
94 }
95 SimplePatternFormatter *newFmt =
96 new SimplePatternFormatter(rawPattern);
97 if (newFmt == NULL) {
98 status = U_MEMORY_ALLOCATION_ERROR;
99 return FALSE;
100 }
101 if (newFmt->getPlaceholderCount() > 1) {
102 delete newFmt;
103 status = U_ILLEGAL_ARGUMENT_ERROR;
104 return FALSE;
105 }
106 delete formatters[pluralIndex];
107 formatters[pluralIndex] = newFmt;
108 return TRUE;
109}
110
111UBool QuantityFormatter::isValid() const {
112 return formatters[0] != NULL;
113}
114
115const SimplePatternFormatter *QuantityFormatter::getByVariant(
116 const char *variant) const {
117 int32_t pluralIndex = getPluralIndex(variant);
118 if (pluralIndex == -1) {
119 pluralIndex = 0;
120 }
121 const SimplePatternFormatter *pattern = formatters[pluralIndex];
122 if (pattern == NULL) {
123 pattern = formatters[0];
124 }
125 return pattern;
126}
127
128UnicodeString &QuantityFormatter::format(
129 const Formattable& quantity,
130 const NumberFormat &fmt,
131 const PluralRules &rules,
132 UnicodeString &appendTo,
133 FieldPosition &pos,
134 UErrorCode &status) const {
135 if (U_FAILURE(status)) {
136 return appendTo;
137 }
138 UnicodeString count;
Jungshik Shin70f82502016-01-29 00:32:36 -0800139 VisibleDigitsWithExponent digits;
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800140 const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(&fmt);
141 if (decFmt != NULL) {
Jungshik Shin70f82502016-01-29 00:32:36 -0800142 decFmt->initVisibleDigitsWithExponent(quantity, digits, status);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800143 if (U_FAILURE(status)) {
144 return appendTo;
145 }
Jungshik Shin70f82502016-01-29 00:32:36 -0800146 count = rules.select(digits);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800147 } else {
148 if (quantity.getType() == Formattable::kDouble) {
149 count = rules.select(quantity.getDouble());
150 } else if (quantity.getType() == Formattable::kLong) {
151 count = rules.select(quantity.getLong());
152 } else if (quantity.getType() == Formattable::kInt64) {
153 count = rules.select((double) quantity.getInt64());
154 } else {
155 status = U_ILLEGAL_ARGUMENT_ERROR;
156 return appendTo;
157 }
158 }
159 CharString buffer;
160 buffer.appendInvariantChars(count, status);
161 if (U_FAILURE(status)) {
162 return appendTo;
163 }
164 const SimplePatternFormatter *pattern = getByVariant(buffer.data());
165 if (pattern == NULL) {
166 status = U_INVALID_STATE_ERROR;
167 return appendTo;
168 }
169 UnicodeString formattedNumber;
170 FieldPosition fpos(pos.getField());
Jungshik Shin70f82502016-01-29 00:32:36 -0800171 if (decFmt != NULL) {
172 decFmt->format(digits, formattedNumber, fpos, status);
173 } else {
174 fmt.format(quantity, formattedNumber, fpos, status);
175 }
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800176 const UnicodeString *params[1] = {&formattedNumber};
177 int32_t offsets[1];
Jungshik Shin70f82502016-01-29 00:32:36 -0800178 pattern->formatAndAppend(
179 params,
180 UPRV_LENGTHOF(params),
181 appendTo,
182 offsets,
183 UPRV_LENGTHOF(offsets),
184 status);
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800185 if (offsets[0] != -1) {
186 if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) {
187 pos.setBeginIndex(fpos.getBeginIndex() + offsets[0]);
188 pos.setEndIndex(fpos.getEndIndex() + offsets[0]);
189 }
190 }
191 return appendTo;
192}
193
194U_NAMESPACE_END
195
196#endif /* #if !UCONFIG_NO_FORMATTING */