• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "uassert.h"
27 #include "number_decimalquantity.h"
28 
29 U_NAMESPACE_BEGIN
30 
QuantityFormatter()31 QuantityFormatter::QuantityFormatter() {
32     for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
33         formatters[i] = NULL;
34     }
35 }
36 
QuantityFormatter(const QuantityFormatter & other)37 QuantityFormatter::QuantityFormatter(const QuantityFormatter &other) {
38     for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
39         if (other.formatters[i] == NULL) {
40             formatters[i] = NULL;
41         } else {
42             formatters[i] = new SimpleFormatter(*other.formatters[i]);
43         }
44     }
45 }
46 
operator =(const QuantityFormatter & other)47 QuantityFormatter &QuantityFormatter::operator=(
48         const QuantityFormatter& other) {
49     if (this == &other) {
50         return *this;
51     }
52     for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
53         delete formatters[i];
54         if (other.formatters[i] == NULL) {
55             formatters[i] = NULL;
56         } else {
57             formatters[i] = new SimpleFormatter(*other.formatters[i]);
58         }
59     }
60     return *this;
61 }
62 
~QuantityFormatter()63 QuantityFormatter::~QuantityFormatter() {
64     for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
65         delete formatters[i];
66     }
67 }
68 
reset()69 void QuantityFormatter::reset() {
70     for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
71         delete formatters[i];
72         formatters[i] = NULL;
73     }
74 }
75 
addIfAbsent(const char * variant,const UnicodeString & rawPattern,UErrorCode & status)76 UBool QuantityFormatter::addIfAbsent(
77         const char *variant,
78         const UnicodeString &rawPattern,
79         UErrorCode &status) {
80     int32_t pluralIndex = StandardPlural::indexFromString(variant, status);
81     if (U_FAILURE(status)) {
82         return FALSE;
83     }
84     if (formatters[pluralIndex] != NULL) {
85         return TRUE;
86     }
87     SimpleFormatter *newFmt = new SimpleFormatter(rawPattern, 0, 1, status);
88     if (newFmt == NULL) {
89         status = U_MEMORY_ALLOCATION_ERROR;
90         return FALSE;
91     }
92     if (U_FAILURE(status)) {
93         delete newFmt;
94         return FALSE;
95     }
96     formatters[pluralIndex] = newFmt;
97     return TRUE;
98 }
99 
isValid() const100 UBool QuantityFormatter::isValid() const {
101     return formatters[StandardPlural::OTHER] != NULL;
102 }
103 
getByVariant(const char * variant) const104 const SimpleFormatter *QuantityFormatter::getByVariant(
105         const char *variant) const {
106     U_ASSERT(isValid());
107     int32_t pluralIndex = StandardPlural::indexOrOtherIndexFromString(variant);
108     const SimpleFormatter *pattern = formatters[pluralIndex];
109     if (pattern == NULL) {
110         pattern = formatters[StandardPlural::OTHER];
111     }
112     return pattern;
113 }
114 
format(const Formattable & number,const NumberFormat & fmt,const PluralRules & rules,UnicodeString & appendTo,FieldPosition & pos,UErrorCode & status) const115 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     UnicodeString formattedNumber;
123     StandardPlural::Form p = selectPlural(number, fmt, rules, formattedNumber, pos, status);
124     if (U_FAILURE(status)) {
125         return appendTo;
126     }
127     const SimpleFormatter *pattern = formatters[p];
128     if (pattern == NULL) {
129         pattern = formatters[StandardPlural::OTHER];
130         if (pattern == NULL) {
131             status = U_INVALID_STATE_ERROR;
132             return appendTo;
133         }
134     }
135     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 
selectPlural(const Formattable & number,const NumberFormat & fmt,const PluralRules & rules,UnicodeString & formattedNumber,FieldPosition & pos,UErrorCode & status)141 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     if (U_FAILURE(status)) {
149         return StandardPlural::OTHER;
150     }
151     UnicodeString pluralKeyword;
152     const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(&fmt);
153     if (decFmt != NULL) {
154         number::impl::DecimalQuantity dq;
155         decFmt->formatToDecimalQuantity(number, dq, status);
156         if (U_FAILURE(status)) {
157             return StandardPlural::OTHER;
158         }
159         pluralKeyword = rules.select(dq);
160         decFmt->format(number, formattedNumber, pos, status);
161     } else {
162         if (number.getType() == Formattable::kDouble) {
163             pluralKeyword = rules.select(number.getDouble());
164         } else if (number.getType() == Formattable::kLong) {
165             pluralKeyword = rules.select(number.getLong());
166         } else if (number.getType() == Formattable::kInt64) {
167             pluralKeyword = rules.select((double) number.getInt64());
168         } else {
169             status = U_ILLEGAL_ARGUMENT_ERROR;
170             return StandardPlural::OTHER;
171         }
172         fmt.format(number, formattedNumber, pos, status);
173     }
174     return StandardPlural::orOtherFromString(pluralKeyword);
175 }
176 
format(const SimpleFormatter & pattern,const UnicodeString & value,UnicodeString & appendTo,FieldPosition & pos,UErrorCode & status)177 UnicodeString &QuantityFormatter::format(
178             const SimpleFormatter &pattern,
179             const UnicodeString &value,
180             UnicodeString &appendTo,
181             FieldPosition &pos,
182             UErrorCode &status) {
183     if (U_FAILURE(status)) {
184         return appendTo;
185     }
186     const UnicodeString *param = &value;
187     int32_t offset;
188     pattern.formatAndAppend(&param, 1, appendTo, &offset, 1, status);
189     if (pos.getBeginIndex() != 0 || pos.getEndIndex() != 0) {
190         if (offset >= 0) {
191             pos.setBeginIndex(pos.getBeginIndex() + offset);
192             pos.setEndIndex(pos.getEndIndex() + offset);
193         } else {
194             pos.setBeginIndex(0);
195             pos.setEndIndex(0);
196         }
197     }
198     return appendTo;
199 }
200 
201 U_NAMESPACE_END
202 
203 #endif /* #if !UCONFIG_NO_FORMATTING */
204