tor-browser

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

number_usageprefs.cpp (6737B)


      1 // © 2020 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 
      4 #include "unicode/utypes.h"
      5 
      6 #if !UCONFIG_NO_FORMATTING
      7 
      8 #include "number_usageprefs.h"
      9 #include "cstring.h"
     10 #include "number_decimalquantity.h"
     11 #include "number_microprops.h"
     12 #include "number_roundingutils.h"
     13 #include "number_skeletons.h"
     14 #include "unicode/char16ptr.h"
     15 #include "unicode/currunit.h"
     16 #include "unicode/fmtable.h"
     17 #include "unicode/measure.h"
     18 #include "unicode/numberformatter.h"
     19 #include "unicode/platform.h"
     20 #include "unicode/unum.h"
     21 #include "unicode/urename.h"
     22 #include "units_data.h"
     23 
     24 using namespace icu;
     25 using namespace icu::number;
     26 using namespace icu::number::impl;
     27 using icu::StringSegment;
     28 using icu::units::ConversionRates;
     29 
     30 // Copy constructor
     31 StringProp::StringProp(const StringProp &other) : StringProp() {
     32    this->operator=(other);
     33 }
     34 
     35 // Copy assignment operator
     36 StringProp &StringProp::operator=(const StringProp &other) {
     37    if (this == &other) { return *this; }  // self-assignment: no-op
     38    fLength = 0;
     39    fError = other.fError;
     40    if (fValue != nullptr) {
     41        uprv_free(fValue);
     42        fValue = nullptr;
     43    }
     44    if (other.fValue == nullptr) {
     45        return *this;
     46    }
     47    if (U_FAILURE(other.fError)) {
     48        // We don't bother trying to allocating memory if we're in any case busy
     49        // copying an errored StringProp.
     50        return *this;
     51    }
     52    fValue = static_cast<char*>(uprv_malloc(other.fLength + 1));
     53    if (fValue == nullptr) {
     54        fError = U_MEMORY_ALLOCATION_ERROR;
     55        return *this;
     56    }
     57    fLength = other.fLength;
     58    uprv_strncpy(fValue, other.fValue, fLength + 1);
     59    return *this;
     60 }
     61 
     62 // Move constructor
     63 StringProp::StringProp(StringProp &&src) noexcept : fValue(src.fValue),
     64                                                      fLength(src.fLength),
     65                                                      fError(src.fError) {
     66    // Take ownership away from src if necessary
     67    src.fValue = nullptr;
     68 }
     69 
     70 // Move assignment operator
     71 StringProp &StringProp::operator=(StringProp &&src) noexcept {
     72    if (this == &src) {
     73        return *this;
     74    }
     75    if (fValue != nullptr) {
     76        uprv_free(fValue);
     77    }
     78    fValue = src.fValue;
     79    fLength = src.fLength;
     80    fError = src.fError;
     81    // Take ownership away from src if necessary
     82    src.fValue = nullptr;
     83    return *this;
     84 }
     85 
     86 StringProp::~StringProp() {
     87    if (fValue != nullptr) {
     88        uprv_free(fValue);
     89        fValue = nullptr;
     90    }
     91 }
     92 
     93 void StringProp::set(StringPiece value) {
     94    if (fValue != nullptr) {
     95        uprv_free(fValue);
     96        fValue = nullptr;
     97    }
     98    fLength = value.length();
     99    fValue = static_cast<char*>(uprv_malloc(fLength + 1));
    100    if (fValue == nullptr) {
    101        fLength = 0;
    102        fError = U_MEMORY_ALLOCATION_ERROR;
    103        return;
    104    }
    105    if (fLength > 0) {
    106        uprv_strncpy(fValue, value.data(), fLength);
    107    }
    108    fValue[fLength] = 0;
    109 }
    110 
    111 // Populates micros.mixedMeasures and modifies quantity, based on the values in
    112 // measures.
    113 void mixedMeasuresToMicros(const MaybeStackVector<Measure> &measures, DecimalQuantity *quantity,
    114                           MicroProps *micros, UErrorCode status) {
    115    micros->mixedMeasuresCount = measures.length();
    116 
    117    if (micros->mixedMeasures.getCapacity() < micros->mixedMeasuresCount) {
    118        if (micros->mixedMeasures.resize(micros->mixedMeasuresCount) == nullptr) {
    119            status = U_MEMORY_ALLOCATION_ERROR;
    120            return;
    121        }
    122    }
    123 
    124    for (int32_t i = 0; i < micros->mixedMeasuresCount; i++) {
    125        switch (measures[i]->getNumber().getType()) {
    126        case Formattable::kInt64:
    127            micros->mixedMeasures[i] = measures[i]->getNumber().getInt64();
    128            break;
    129 
    130        case Formattable::kDouble:
    131            U_ASSERT(micros->indexOfQuantity < 0);
    132            quantity->setToDouble(measures[i]->getNumber().getDouble());
    133            micros->indexOfQuantity = i;
    134            break;
    135 
    136        default:
    137            U_ASSERT(0 == "Found a Measure Number which is neither a double nor an int");
    138            UPRV_UNREACHABLE_EXIT;
    139            break;
    140        }
    141 
    142        if (U_FAILURE(status)) {
    143            return;
    144        }
    145    }
    146 
    147    if (micros->indexOfQuantity < 0) {
    148        // There is no quantity.
    149        status = U_INTERNAL_PROGRAM_ERROR;
    150    }
    151 }
    152 
    153 UsagePrefsHandler::UsagePrefsHandler(const Locale &locale,
    154                                     const MeasureUnit &inputUnit,
    155                                     const StringPiece usage,
    156                                     const MicroPropsGenerator *parent,
    157                                     UErrorCode &status)
    158    : fUnitsRouter(inputUnit, locale, usage, status),
    159      fParent(parent) {
    160 }
    161 
    162 void UsagePrefsHandler::processQuantity(DecimalQuantity &quantity, MicroProps &micros,
    163                                        UErrorCode &status) const {
    164    fParent->processQuantity(quantity, micros, status);
    165    if (U_FAILURE(status)) {
    166        return;
    167    }
    168 
    169    quantity.roundToInfinity(); // Enables toDouble
    170    const units::RouteResult routed = fUnitsRouter.route(quantity.toDouble(), &micros.rounder, status);
    171    if (U_FAILURE(status)) {
    172        return;
    173    }
    174    const MaybeStackVector<Measure>& routedMeasures = routed.measures;
    175    micros.outputUnit = routed.outputUnit.copy(status).build(status);
    176    if (U_FAILURE(status)) {
    177        return;
    178    }
    179 
    180    mixedMeasuresToMicros(routedMeasures, &quantity, &micros, status);
    181 }
    182 
    183 UnitConversionHandler::UnitConversionHandler(const MeasureUnit &targetUnit,
    184                                             const MicroPropsGenerator *parent, UErrorCode &status)
    185    : fOutputUnit(targetUnit), fParent(parent) {
    186    MeasureUnitImpl tempInput, tempOutput;
    187 
    188    ConversionRates conversionRates(status);
    189    if (U_FAILURE(status)) {
    190        return;
    191    }
    192 
    193    const MeasureUnitImpl &targetUnitImpl =
    194        MeasureUnitImpl::forMeasureUnit(targetUnit, tempOutput, status);
    195    fUnitConverter.adoptInsteadAndCheckErrorCode(
    196        new ComplexUnitsConverter(targetUnitImpl, conversionRates, status), status);
    197 }
    198 
    199 void UnitConversionHandler::processQuantity(DecimalQuantity &quantity, MicroProps &micros,
    200                                            UErrorCode &status) const {
    201    fParent->processQuantity(quantity, micros, status);
    202    if (U_FAILURE(status)) {
    203        return;
    204    }
    205    quantity.roundToInfinity(); // Enables toDouble
    206    MaybeStackVector<Measure> measures =
    207        fUnitConverter->convert(quantity.toDouble(), &micros.rounder, status);
    208    micros.outputUnit = fOutputUnit;
    209    if (U_FAILURE(status)) {
    210        return;
    211    }
    212 
    213    mixedMeasuresToMicros(measures, &quantity, &micros, status);
    214 }
    215 
    216 #endif /* #if !UCONFIG_NO_FORMATTING */