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