1// Copyright (C) 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 29U_NAMESPACE_BEGIN 30 31QuantityFormatter::QuantityFormatter() { 32 for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) { 33 formatters[i] = NULL; 34 } 35} 36 37QuantityFormatter::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 47QuantityFormatter &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 63QuantityFormatter::~QuantityFormatter() { 64 for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) { 65 delete formatters[i]; 66 } 67} 68 69void QuantityFormatter::reset() { 70 for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) { 71 delete formatters[i]; 72 formatters[i] = NULL; 73 } 74} 75 76UBool 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 100UBool QuantityFormatter::isValid() const { 101 return formatters[StandardPlural::OTHER] != NULL; 102} 103 104const 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 115UnicodeString &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 141StandardPlural::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 VisibleDigitsWithExponent digits; 153 const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(&fmt); 154 if (decFmt != NULL) { 155 decFmt->initVisibleDigitsWithExponent(number, digits, status); 156 if (U_FAILURE(status)) { 157 return StandardPlural::OTHER; 158 } 159 pluralKeyword = rules.select(digits); 160 decFmt->format(digits, 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 177UnicodeString &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(¶m, 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 201U_NAMESPACE_END 202 203#endif /* #if !UCONFIG_NO_FORMATTING */ 204