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