164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert// Copyright (C) 2016 and later: Unicode, Inc. and others. 264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html 3fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius/* 4fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius****************************************************************************** 58de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert* Copyright (C) 2014-2016, International Business Machines 6fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius* Corporation and others. All Rights Reserved. 7fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius****************************************************************************** 8fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius* quantityformatter.cpp 9fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius*/ 108ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer 118ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer#include "unicode/utypes.h" 128ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer 138ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer#if !UCONFIG_NO_FORMATTING 148ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer 158de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert#include "unicode/simpleformatter.h" 16fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "quantityformatter.h" 17fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "uassert.h" 18fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/unistr.h" 19fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/decimfmt.h" 20fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "cstring.h" 21fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/plurrule.h" 22fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "charstr.h" 23fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/fmtable.h" 24fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/fieldpos.h" 250b3ec0516c035ea443fdc334025048597c740be1Markus Scherer#include "standardplural.h" 26c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert#include "visibledigits.h" 278ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer#include "uassert.h" 28fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius 29fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusU_NAMESPACE_BEGIN 30fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius 31fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusQuantityFormatter::QuantityFormatter() { 32f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) { 33fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius formatters[i] = NULL; 34fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } 35fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius} 36fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius 37fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusQuantityFormatter::QuantityFormatter(const QuantityFormatter &other) { 38f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) { 39fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius if (other.formatters[i] == NULL) { 40fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius formatters[i] = NULL; 41fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } else { 428de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert formatters[i] = new SimpleFormatter(*other.formatters[i]); 43fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } 44fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } 45fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius} 46fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius 47fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusQuantityFormatter &QuantityFormatter::operator=( 48fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius const QuantityFormatter& other) { 49fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius if (this == &other) { 50fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius return *this; 51fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } 52f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) { 53fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius delete formatters[i]; 54fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius if (other.formatters[i] == NULL) { 55fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius formatters[i] = NULL; 56fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } else { 578de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert formatters[i] = new SimpleFormatter(*other.formatters[i]); 58fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } 59fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } 60fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius return *this; 61fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius} 62fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius 63fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusQuantityFormatter::~QuantityFormatter() { 64f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) { 65fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius delete formatters[i]; 66fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } 67fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius} 68fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius 69fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusvoid QuantityFormatter::reset() { 70f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) { 71fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius delete formatters[i]; 72fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius formatters[i] = NULL; 73fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } 74fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius} 75fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius 768ce198ebe2317b05a969826d0b629cb2d0b894a2Markus SchererUBool QuantityFormatter::addIfAbsent( 77fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius const char *variant, 787d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer const UnicodeString &rawPattern, 79fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius UErrorCode &status) { 800b3ec0516c035ea443fdc334025048597c740be1Markus Scherer int32_t pluralIndex = StandardPlural::indexFromString(variant, status); 81fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius if (U_FAILURE(status)) { 82fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius return FALSE; 83fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } 848ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer if (formatters[pluralIndex] != NULL) { 858ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer return TRUE; 868ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer } 878de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert SimpleFormatter *newFmt = new SimpleFormatter(rawPattern, 0, 1, status); 88fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius if (newFmt == NULL) { 89fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius status = U_MEMORY_ALLOCATION_ERROR; 90fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius return FALSE; 91fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } 927d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer if (U_FAILURE(status)) { 93fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius delete newFmt; 94fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius return FALSE; 95fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } 96fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius formatters[pluralIndex] = newFmt; 97fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius return TRUE; 98fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius} 99fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius 100fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusUBool QuantityFormatter::isValid() const { 1010b3ec0516c035ea443fdc334025048597c740be1Markus Scherer return formatters[StandardPlural::OTHER] != NULL; 102fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius} 103fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius 1048de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubertconst SimpleFormatter *QuantityFormatter::getByVariant( 105f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius const char *variant) const { 1068ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer U_ASSERT(isValid()); 1070b3ec0516c035ea443fdc334025048597c740be1Markus Scherer int32_t pluralIndex = StandardPlural::indexOrOtherIndexFromString(variant); 1088de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert const SimpleFormatter *pattern = formatters[pluralIndex]; 109f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius if (pattern == NULL) { 1100b3ec0516c035ea443fdc334025048597c740be1Markus Scherer pattern = formatters[StandardPlural::OTHER]; 111f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius } 112f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius return pattern; 113f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius} 114f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 115fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusUnicodeString &QuantityFormatter::format( 1167d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer const Formattable &number, 117fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius const NumberFormat &fmt, 118fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius const PluralRules &rules, 119fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius UnicodeString &appendTo, 120fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius FieldPosition &pos, 121fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius UErrorCode &status) const { 1227d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer UnicodeString formattedNumber; 1237d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer StandardPlural::Form p = selectPlural(number, fmt, rules, formattedNumber, pos, status); 124fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius if (U_FAILURE(status)) { 125fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius return appendTo; 126fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } 1278de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert const SimpleFormatter *pattern = formatters[p]; 1287d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer if (pattern == NULL) { 1297d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer pattern = formatters[StandardPlural::OTHER]; 1307d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer if (pattern == NULL) { 1317d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer status = U_INVALID_STATE_ERROR; 1327d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer return appendTo; 1337d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer } 1347d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer } 1357d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer return format(*pattern, formattedNumber, appendTo, pos, status); 1367d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer} 1377d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer 1387d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer// The following methods live here so that class PluralRules does not depend on number formatting, 1398de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert// and the SimpleFormatter does not depend on FieldPosition. 1407d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer 1417d219b1ec89c9f70eedb20b1190fc678a1011519Markus SchererStandardPlural::Form QuantityFormatter::selectPlural( 1427d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer const Formattable &number, 1437d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer const NumberFormat &fmt, 1447d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer const PluralRules &rules, 1457d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer UnicodeString &formattedNumber, 1467d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer FieldPosition &pos, 1477d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer UErrorCode &status) { 1487d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer if (U_FAILURE(status)) { 1497d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer return StandardPlural::OTHER; 1507d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer } 1517d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer UnicodeString pluralKeyword; 152c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert VisibleDigitsWithExponent digits; 153fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(&fmt); 154fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius if (decFmt != NULL) { 1557d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer decFmt->initVisibleDigitsWithExponent(number, digits, status); 156fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius if (U_FAILURE(status)) { 1577d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer return StandardPlural::OTHER; 158fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } 1597d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer pluralKeyword = rules.select(digits); 1607d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer decFmt->format(digits, formattedNumber, pos, status); 161fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } else { 1627d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer if (number.getType() == Formattable::kDouble) { 1637d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer pluralKeyword = rules.select(number.getDouble()); 1647d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer } else if (number.getType() == Formattable::kLong) { 1657d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer pluralKeyword = rules.select(number.getLong()); 1667d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer } else if (number.getType() == Formattable::kInt64) { 1677d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer pluralKeyword = rules.select((double) number.getInt64()); 168fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } else { 169fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius status = U_ILLEGAL_ARGUMENT_ERROR; 1707d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer return StandardPlural::OTHER; 171fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } 1727d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer fmt.format(number, formattedNumber, pos, status); 173fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } 1747d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer return StandardPlural::orOtherFromString(pluralKeyword); 1757d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer} 1767d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer 1777d219b1ec89c9f70eedb20b1190fc678a1011519Markus SchererUnicodeString &QuantityFormatter::format( 1788de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert const SimpleFormatter &pattern, 1797d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer const UnicodeString &value, 1807d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer UnicodeString &appendTo, 1817d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer FieldPosition &pos, 1827d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer UErrorCode &status) { 183fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius if (U_FAILURE(status)) { 184fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius return appendTo; 185fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } 1867d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer const UnicodeString *param = &value; 1877d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer int32_t offset; 1887d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer pattern.formatAndAppend(¶m, 1, appendTo, &offset, 1, status); 1897d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer if (pos.getBeginIndex() != 0 || pos.getEndIndex() != 0) { 1907d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer if (offset >= 0) { 1917d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer pos.setBeginIndex(pos.getBeginIndex() + offset); 1927d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer pos.setEndIndex(pos.getEndIndex() + offset); 1937d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer } else { 1947d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer pos.setBeginIndex(0); 1957d219b1ec89c9f70eedb20b1190fc678a1011519Markus Scherer pos.setEndIndex(0); 196fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } 197fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } 198fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius return appendTo; 199fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius} 200fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius 201fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusU_NAMESPACE_END 202fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius 203fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#endif /* #if !UCONFIG_NO_FORMATTING */ 204