Home | History | Annotate | Download | only in i18n
      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 "visibledigits.h"
     27 #include "uassert.h"
     28 
     29 U_NAMESPACE_BEGIN
     30 
     31 QuantityFormatter::QuantityFormatter() {
     32     for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
     33         formatters[i] = NULL;
     34     }
     35 }
     36 
     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 
     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 
     63 QuantityFormatter::~QuantityFormatter() {
     64     for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
     65         delete formatters[i];
     66     }
     67 }
     68 
     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 
     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 
    100 UBool QuantityFormatter::isValid() const {
    101     return formatters[StandardPlural::OTHER] != NULL;
    102 }
    103 
    104 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 
    115 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 
    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     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 
    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