tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

quantityformatter.cpp (7733B)


      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 "uassert.h"
     27 #include "number_decimalquantity.h"
     28 #include "number_utypes.h"
     29 #include "formatted_string_builder.h"
     30 
     31 U_NAMESPACE_BEGIN
     32 
     33 QuantityFormatter::QuantityFormatter() {
     34    for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
     35        formatters[i] = nullptr;
     36    }
     37 }
     38 
     39 QuantityFormatter::QuantityFormatter(const QuantityFormatter &other) {
     40    for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
     41        if (other.formatters[i] == nullptr) {
     42            formatters[i] = nullptr;
     43        } else {
     44            formatters[i] = new SimpleFormatter(*other.formatters[i]);
     45        }
     46    }
     47 }
     48 
     49 QuantityFormatter &QuantityFormatter::operator=(
     50        const QuantityFormatter& other) {
     51    if (this == &other) {
     52        return *this;
     53    }
     54    for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
     55        delete formatters[i];
     56        if (other.formatters[i] == nullptr) {
     57            formatters[i] = nullptr;
     58        } else {
     59            formatters[i] = new SimpleFormatter(*other.formatters[i]);
     60        }
     61    }
     62    return *this;
     63 }
     64 
     65 QuantityFormatter::~QuantityFormatter() {
     66    for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
     67        delete formatters[i];
     68    }
     69 }
     70 
     71 void QuantityFormatter::reset() {
     72    for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
     73        delete formatters[i];
     74        formatters[i] = nullptr;
     75    }
     76 }
     77 
     78 UBool QuantityFormatter::addIfAbsent(
     79        const char *variant,
     80        const UnicodeString &rawPattern,
     81        UErrorCode &status) {
     82    int32_t pluralIndex = StandardPlural::indexFromString(variant, status);
     83    if (U_FAILURE(status)) {
     84        return false;
     85    }
     86    if (formatters[pluralIndex] != nullptr) {
     87        return true;
     88    }
     89    SimpleFormatter *newFmt = new SimpleFormatter(rawPattern, 0, 1, status);
     90    if (newFmt == nullptr) {
     91        status = U_MEMORY_ALLOCATION_ERROR;
     92        return false;
     93    }
     94    if (U_FAILURE(status)) {
     95        delete newFmt;
     96        return false;
     97    }
     98    formatters[pluralIndex] = newFmt;
     99    return true;
    100 }
    101 
    102 UBool QuantityFormatter::isValid() const {
    103    return formatters[StandardPlural::OTHER] != nullptr;
    104 }
    105 
    106 const SimpleFormatter *QuantityFormatter::getByVariant(
    107        const char *variant) const {
    108    U_ASSERT(isValid());
    109    int32_t pluralIndex = StandardPlural::indexOrOtherIndexFromString(variant);
    110    const SimpleFormatter *pattern = formatters[pluralIndex];
    111    if (pattern == nullptr) {
    112        pattern = formatters[StandardPlural::OTHER];
    113    }
    114    return pattern;
    115 }
    116 
    117 UnicodeString &QuantityFormatter::format(
    118            const Formattable &number,
    119            const NumberFormat &fmt,
    120            const PluralRules &rules,
    121            UnicodeString &appendTo,
    122            FieldPosition &pos,
    123            UErrorCode &status) const {
    124    UnicodeString formattedNumber;
    125    StandardPlural::Form p = selectPlural(number, fmt, rules, formattedNumber, pos, status);
    126    if (U_FAILURE(status)) {
    127        return appendTo;
    128    }
    129    const SimpleFormatter *pattern = formatters[p];
    130    if (pattern == nullptr) {
    131        pattern = formatters[StandardPlural::OTHER];
    132        if (pattern == nullptr) {
    133            status = U_INVALID_STATE_ERROR;
    134            return appendTo;
    135        }
    136    }
    137    return format(*pattern, formattedNumber, appendTo, pos, status);
    138 }
    139 
    140 // The following methods live here so that class PluralRules does not depend on number formatting,
    141 // and the SimpleFormatter does not depend on FieldPosition.
    142 
    143 StandardPlural::Form QuantityFormatter::selectPlural(
    144            const Formattable &number,
    145            const NumberFormat &fmt,
    146            const PluralRules &rules,
    147            UnicodeString &formattedNumber,
    148            FieldPosition &pos,
    149            UErrorCode &status) {
    150    if (U_FAILURE(status)) {
    151        return StandardPlural::OTHER;
    152    }
    153    UnicodeString pluralKeyword;
    154    const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(&fmt);
    155    if (decFmt != nullptr) {
    156        number::impl::DecimalQuantity dq;
    157        decFmt->formatToDecimalQuantity(number, dq, status);
    158        if (U_FAILURE(status)) {
    159            return StandardPlural::OTHER;
    160        }
    161        pluralKeyword = rules.select(dq);
    162        decFmt->format(number, formattedNumber, pos, status);
    163    } else {
    164        if (number.getType() == Formattable::kDouble) {
    165            pluralKeyword = rules.select(number.getDouble());
    166        } else if (number.getType() == Formattable::kLong) {
    167            pluralKeyword = rules.select(number.getLong());
    168        } else if (number.getType() == Formattable::kInt64) {
    169            pluralKeyword = rules.select(static_cast<double>(number.getInt64()));
    170        } else {
    171            status = U_ILLEGAL_ARGUMENT_ERROR;
    172            return StandardPlural::OTHER;
    173        }
    174        fmt.format(number, formattedNumber, pos, status);
    175    }
    176    return StandardPlural::orOtherFromString(pluralKeyword);
    177 }
    178 
    179 void QuantityFormatter::formatAndSelect(
    180        double quantity,
    181        const NumberFormat& fmt,
    182        const PluralRules& rules,
    183        FormattedStringBuilder& output,
    184        StandardPlural::Form& pluralForm,
    185        UErrorCode& status) {
    186    UnicodeString pluralKeyword;
    187    const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(&fmt);
    188    if (df != nullptr) {
    189        number::impl::UFormattedNumberData fn;
    190        fn.quantity.setToDouble(quantity);
    191        const number::LocalizedNumberFormatter* lnf = df->toNumberFormatter(status);
    192        if (U_FAILURE(status)) {
    193            return;
    194        }
    195        lnf->formatImpl(&fn, status);
    196        if (U_FAILURE(status)) {
    197            return;
    198        }
    199        output = std::move(fn.getStringRef());
    200        pluralKeyword = rules.select(fn.quantity);
    201    } else {
    202        UnicodeString result;
    203        fmt.format(quantity, result, status);
    204        if (U_FAILURE(status)) {
    205            return;
    206        }
    207        // This code path is probably RBNF. Use the generic numeric field.
    208        output.append(result, kGeneralNumericField, status);
    209        if (U_FAILURE(status)) {
    210            return;
    211        }
    212        pluralKeyword = rules.select(quantity);
    213    }
    214    pluralForm = StandardPlural::orOtherFromString(pluralKeyword);
    215 }
    216 
    217 UnicodeString &QuantityFormatter::format(
    218            const SimpleFormatter &pattern,
    219            const UnicodeString &value,
    220            UnicodeString &appendTo,
    221            FieldPosition &pos,
    222            UErrorCode &status) {
    223    if (U_FAILURE(status)) {
    224        return appendTo;
    225    }
    226    const UnicodeString *param = &value;
    227    int32_t offset;
    228    pattern.formatAndAppend(&param, 1, appendTo, &offset, 1, status);
    229    if (pos.getBeginIndex() != 0 || pos.getEndIndex() != 0) {
    230        if (offset >= 0) {
    231            pos.setBeginIndex(pos.getBeginIndex() + offset);
    232            pos.setEndIndex(pos.getEndIndex() + offset);
    233        } else {
    234            pos.setBeginIndex(0);
    235            pos.setEndIndex(0);
    236        }
    237    }
    238    return appendTo;
    239 }
    240 
    241 U_NAMESPACE_END
    242 
    243 #endif /* #if !UCONFIG_NO_FORMATTING */