tor-browser

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

numrange_fluent.cpp (14090B)


      1 // © 2018 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 // Allow implicit conversion from char16_t* to UnicodeString for this file:
      9 // Helpful in toString methods and elsewhere.
     10 #define UNISTR_FROM_STRING_EXPLICIT
     11 
     12 #include "numrange_impl.h"
     13 #include "util.h"
     14 #include "number_utypes.h"
     15 #include "number_decnum.h"
     16 
     17 using namespace icu;
     18 using namespace icu::number;
     19 using namespace icu::number::impl;
     20 
     21 
     22 // This function needs to be declared in this namespace so it can be friended.
     23 // NOTE: In Java, this logic is handled in the resolve() function.
     24 void icu::number::impl::touchRangeLocales(RangeMacroProps& macros) {
     25    macros.formatter1.fMacros.locale = macros.locale;
     26    macros.formatter2.fMacros.locale = macros.locale;
     27 }
     28 
     29 
     30 template<typename Derived>
     31 Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(const UnlocalizedNumberFormatter& formatter) const& {
     32    Derived copy(*this);
     33    copy.fMacros.formatter1 = formatter;
     34    copy.fMacros.singleFormatter = true;
     35    touchRangeLocales(copy.fMacros);
     36    return copy;
     37 }
     38 
     39 template<typename Derived>
     40 Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(const UnlocalizedNumberFormatter& formatter) && {
     41    Derived move(std::move(*this));
     42    move.fMacros.formatter1 = formatter;
     43    move.fMacros.singleFormatter = true;
     44    touchRangeLocales(move.fMacros);
     45    return move;
     46 }
     47 
     48 template<typename Derived>
     49 Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(UnlocalizedNumberFormatter&& formatter) const& {
     50    Derived copy(*this);
     51    copy.fMacros.formatter1 = std::move(formatter);
     52    copy.fMacros.singleFormatter = true;
     53    touchRangeLocales(copy.fMacros);
     54    return copy;
     55 }
     56 
     57 template<typename Derived>
     58 Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(UnlocalizedNumberFormatter&& formatter) && {
     59    Derived move(std::move(*this));
     60    move.fMacros.formatter1 = std::move(formatter);
     61    move.fMacros.singleFormatter = true;
     62    touchRangeLocales(move.fMacros);
     63    return move;
     64 }
     65 
     66 template<typename Derived>
     67 Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(const UnlocalizedNumberFormatter& formatter) const& {
     68    Derived copy(*this);
     69    copy.fMacros.formatter1 = formatter;
     70    copy.fMacros.singleFormatter = false;
     71    touchRangeLocales(copy.fMacros);
     72    return copy;
     73 }
     74 
     75 template<typename Derived>
     76 Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(const UnlocalizedNumberFormatter& formatter) && {
     77    Derived move(std::move(*this));
     78    move.fMacros.formatter1 = formatter;
     79    move.fMacros.singleFormatter = false;
     80    touchRangeLocales(move.fMacros);
     81    return move;
     82 }
     83 
     84 template<typename Derived>
     85 Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(UnlocalizedNumberFormatter&& formatter) const& {
     86    Derived copy(*this);
     87    copy.fMacros.formatter1 = std::move(formatter);
     88    copy.fMacros.singleFormatter = false;
     89    touchRangeLocales(copy.fMacros);
     90    return copy;
     91 }
     92 
     93 template<typename Derived>
     94 Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(UnlocalizedNumberFormatter&& formatter) && {
     95    Derived move(std::move(*this));
     96    move.fMacros.formatter1 = std::move(formatter);
     97    move.fMacros.singleFormatter = false;
     98    touchRangeLocales(move.fMacros);
     99    return move;
    100 }
    101 
    102 template<typename Derived>
    103 Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(const UnlocalizedNumberFormatter& formatter) const& {
    104    Derived copy(*this);
    105    copy.fMacros.formatter2 = formatter;
    106    copy.fMacros.singleFormatter = false;
    107    touchRangeLocales(copy.fMacros);
    108    return copy;
    109 }
    110 
    111 template<typename Derived>
    112 Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(const UnlocalizedNumberFormatter& formatter) && {
    113    Derived move(std::move(*this));
    114    move.fMacros.formatter2 = formatter;
    115    move.fMacros.singleFormatter = false;
    116    touchRangeLocales(move.fMacros);
    117    return move;
    118 }
    119 
    120 template<typename Derived>
    121 Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(UnlocalizedNumberFormatter&& formatter) const& {
    122    Derived copy(*this);
    123    copy.fMacros.formatter2 = std::move(formatter);
    124    copy.fMacros.singleFormatter = false;
    125    touchRangeLocales(copy.fMacros);
    126    return copy;
    127 }
    128 
    129 template<typename Derived>
    130 Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(UnlocalizedNumberFormatter&& formatter) && {
    131    Derived move(std::move(*this));
    132    move.fMacros.formatter2 = std::move(formatter);
    133    move.fMacros.singleFormatter = false;
    134    touchRangeLocales(move.fMacros);
    135    return move;
    136 }
    137 
    138 template<typename Derived>
    139 Derived NumberRangeFormatterSettings<Derived>::collapse(UNumberRangeCollapse collapse) const& {
    140    Derived copy(*this);
    141    copy.fMacros.collapse = collapse;
    142    return copy;
    143 }
    144 
    145 template<typename Derived>
    146 Derived NumberRangeFormatterSettings<Derived>::collapse(UNumberRangeCollapse collapse) && {
    147    Derived move(std::move(*this));
    148    move.fMacros.collapse = collapse;
    149    return move;
    150 }
    151 
    152 template<typename Derived>
    153 Derived NumberRangeFormatterSettings<Derived>::identityFallback(UNumberRangeIdentityFallback identityFallback) const& {
    154    Derived copy(*this);
    155    copy.fMacros.identityFallback = identityFallback;
    156    return copy;
    157 }
    158 
    159 template<typename Derived>
    160 Derived NumberRangeFormatterSettings<Derived>::identityFallback(UNumberRangeIdentityFallback identityFallback) && {
    161    Derived move(std::move(*this));
    162    move.fMacros.identityFallback = identityFallback;
    163    return move;
    164 }
    165 
    166 template<typename Derived>
    167 LocalPointer<Derived> NumberRangeFormatterSettings<Derived>::clone() const & {
    168    return LocalPointer<Derived>(new Derived(*this));
    169 }
    170 
    171 template<typename Derived>
    172 LocalPointer<Derived> NumberRangeFormatterSettings<Derived>::clone() && {
    173    return LocalPointer<Derived>(new Derived(std::move(*this)));
    174 }
    175 
    176 // Declare all classes that implement NumberRangeFormatterSettings
    177 // See https://stackoverflow.com/a/495056/1407170
    178 template
    179 class icu::number::NumberRangeFormatterSettings<icu::number::UnlocalizedNumberRangeFormatter>;
    180 template
    181 class icu::number::NumberRangeFormatterSettings<icu::number::LocalizedNumberRangeFormatter>;
    182 
    183 
    184 UnlocalizedNumberRangeFormatter NumberRangeFormatter::with() {
    185    UnlocalizedNumberRangeFormatter result;
    186    return result;
    187 }
    188 
    189 LocalizedNumberRangeFormatter NumberRangeFormatter::withLocale(const Locale& locale) {
    190    return with().locale(locale);
    191 }
    192 
    193 
    194 template<typename T> using NFS = NumberRangeFormatterSettings<T>;
    195 using LNF = LocalizedNumberRangeFormatter;
    196 using UNF = UnlocalizedNumberRangeFormatter;
    197 
    198 UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(const UNF& other)
    199        : UNF(static_cast<const NFS<UNF>&>(other)) {}
    200 
    201 UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(const NFS<UNF>& other)
    202        : NFS<UNF>(other) {
    203    // No additional fields to assign
    204 }
    205 
    206 // Make default copy constructor call the NumberRangeFormatterSettings copy constructor.
    207 UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(UNF&& src) noexcept
    208        : UNF(static_cast<NFS<UNF>&&>(src)) {}
    209 
    210 UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(NFS<UNF>&& src) noexcept
    211        : NFS<UNF>(std::move(src)) {
    212    // No additional fields to assign
    213 }
    214 
    215 UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(const impl::RangeMacroProps &macros) {
    216    fMacros = macros;
    217 }
    218 
    219 UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(impl::RangeMacroProps &&macros) {
    220    fMacros = macros;
    221 }
    222 
    223 UnlocalizedNumberRangeFormatter& UnlocalizedNumberRangeFormatter::operator=(const UNF& other) {
    224    NFS<UNF>::operator=(static_cast<const NFS<UNF>&>(other));
    225    // No additional fields to assign
    226    return *this;
    227 }
    228 
    229 UnlocalizedNumberRangeFormatter& UnlocalizedNumberRangeFormatter::operator=(UNF&& src) noexcept {
    230    NFS<UNF>::operator=(static_cast<NFS<UNF>&&>(src));
    231    // No additional fields to assign
    232    return *this;
    233 }
    234 
    235 // Make default copy constructor call the NumberRangeFormatterSettings copy constructor.
    236 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const LNF& other)
    237        : LNF(static_cast<const NFS<LNF>&>(other)) {}
    238 
    239 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const NFS<LNF>& other)
    240        : NFS<LNF>(other) {
    241    // No additional fields to assign
    242 }
    243 
    244 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(LocalizedNumberRangeFormatter&& src) noexcept
    245        : LNF(static_cast<NFS<LNF>&&>(src)) {}
    246 
    247 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(NFS<LNF>&& src) noexcept
    248        : NFS<LNF>(std::move(src)) {
    249    // Steal the compiled formatter
    250    LNF&& _src = static_cast<LNF&&>(src);
    251 #ifndef __wasi__
    252    auto* stolen = _src.fAtomicFormatter.exchange(nullptr);
    253    delete fAtomicFormatter.exchange(stolen);
    254 #else
    255    delete fAtomicFormatter;
    256    fAtomicFormatter = _src.fAtomicFormatter;
    257    _src.fAtomicFormatter = nullptr;
    258 #endif
    259 }
    260 
    261 LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(const LNF& other) {
    262    if (this == &other) { return *this; }  // self-assignment: no-op
    263    NFS<LNF>::operator=(static_cast<const NFS<LNF>&>(other));
    264    // Do not steal; just clear
    265 #ifndef __wasi__
    266    delete fAtomicFormatter.exchange(nullptr);
    267 #else
    268    delete fAtomicFormatter;
    269 #endif
    270    return *this;
    271 }
    272 
    273 LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(LNF&& src) noexcept {
    274    NFS<LNF>::operator=(static_cast<NFS<LNF>&&>(src));
    275    // Steal the compiled formatter
    276 #ifndef __wasi__
    277    auto* stolen = src.fAtomicFormatter.exchange(nullptr);
    278    delete fAtomicFormatter.exchange(stolen);
    279 #else
    280    delete fAtomicFormatter;
    281    fAtomicFormatter = src.fAtomicFormatter;
    282    src.fAtomicFormatter = nullptr;
    283 #endif
    284    return *this;
    285 }
    286 
    287 
    288 LocalizedNumberRangeFormatter::~LocalizedNumberRangeFormatter() {
    289 #ifndef __wasi__
    290    delete fAtomicFormatter.exchange(nullptr);
    291 #else
    292    delete fAtomicFormatter;
    293 #endif
    294 }
    295 
    296 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const RangeMacroProps& macros, const Locale& locale) {
    297    fMacros = macros;
    298    fMacros.locale = locale;
    299    touchRangeLocales(fMacros);
    300 }
    301 
    302 LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(RangeMacroProps&& macros, const Locale& locale) {
    303    fMacros = std::move(macros);
    304    fMacros.locale = locale;
    305    touchRangeLocales(fMacros);
    306 }
    307 
    308 LocalizedNumberRangeFormatter UnlocalizedNumberRangeFormatter::locale(const Locale& locale) const& {
    309    return LocalizedNumberRangeFormatter(fMacros, locale);
    310 }
    311 
    312 LocalizedNumberRangeFormatter UnlocalizedNumberRangeFormatter::locale(const Locale& locale)&& {
    313    return LocalizedNumberRangeFormatter(std::move(fMacros), locale);
    314 }
    315 
    316 
    317 UnlocalizedNumberRangeFormatter LocalizedNumberRangeFormatter::withoutLocale() const & {
    318    RangeMacroProps macros(fMacros);
    319    macros.locale = Locale();
    320    return UnlocalizedNumberRangeFormatter(macros);
    321 }
    322 
    323 UnlocalizedNumberRangeFormatter LocalizedNumberRangeFormatter::withoutLocale() && {
    324    RangeMacroProps macros(std::move(fMacros));
    325    macros.locale = Locale();
    326    return UnlocalizedNumberRangeFormatter(std::move(macros));
    327 }
    328 
    329 
    330 FormattedNumberRange LocalizedNumberRangeFormatter::formatFormattableRange(
    331        const Formattable& first, const Formattable& second, UErrorCode& status) const {
    332    if (U_FAILURE(status)) {
    333        return FormattedNumberRange(U_ILLEGAL_ARGUMENT_ERROR);
    334    }
    335 
    336    LocalPointer<UFormattedNumberRangeData> results(new UFormattedNumberRangeData(), status);
    337    if (U_FAILURE(status)) {
    338        return FormattedNumberRange(status);
    339    }
    340 
    341    first.populateDecimalQuantity(results->quantity1, status);
    342    if (U_FAILURE(status)) {
    343        return FormattedNumberRange(status);
    344    }
    345 
    346    second.populateDecimalQuantity(results->quantity2, status);
    347    if (U_FAILURE(status)) {
    348        return FormattedNumberRange(status);
    349    }
    350 
    351    formatImpl(*results, first == second, status);
    352 
    353    // Do not save the results object if we encountered a failure.
    354    if (U_SUCCESS(status)) {
    355        return FormattedNumberRange(results.orphan());
    356    } else {
    357        return FormattedNumberRange(status);
    358    }
    359 }
    360 
    361 void LocalizedNumberRangeFormatter::formatImpl(
    362        UFormattedNumberRangeData& results, bool equalBeforeRounding, UErrorCode& status) const {
    363    const auto* impl = getFormatter(status);
    364    if (U_FAILURE(status)) {
    365        return;
    366    }
    367    if (impl == nullptr) {
    368        status = U_INTERNAL_PROGRAM_ERROR;
    369        return;
    370    }
    371    impl->format(results, equalBeforeRounding, status);
    372    if (U_FAILURE(status)) {
    373        return;
    374    }
    375    results.getStringRef().writeTerminator(status);
    376 }
    377 
    378 const impl::NumberRangeFormatterImpl*
    379 LocalizedNumberRangeFormatter::getFormatter(UErrorCode& status) const {
    380    // TODO: Move this into umutex.h? (similar logic also in decimfmt.cpp)
    381    // See ICU-20146
    382 
    383    if (U_FAILURE(status)) {
    384        return nullptr;
    385    }
    386 
    387    // First try to get the pre-computed formatter
    388 #ifndef __wasi__
    389    auto* ptr = fAtomicFormatter.load();
    390 #else
    391    auto* ptr = fAtomicFormatter;
    392 #endif
    393    if (ptr != nullptr) {
    394        return ptr;
    395    }
    396 
    397    // Try computing the formatter on our own
    398    LocalPointer<NumberRangeFormatterImpl> temp(new NumberRangeFormatterImpl(fMacros, status), status);
    399    if (U_FAILURE(status)) {
    400        return nullptr;
    401    }
    402 
    403    // Note: ptr starts as nullptr; during compare_exchange,
    404    // it is set to what is actually stored in the atomic
    405    // if another thread beat us to computing the formatter object.
    406    auto* nonConstThis = const_cast<LocalizedNumberRangeFormatter*>(this);
    407 #ifndef __wasi__
    408    if (!nonConstThis->fAtomicFormatter.compare_exchange_strong(ptr, temp.getAlias())) {
    409        // Another thread beat us to computing the formatter
    410        return ptr;
    411    } else {
    412        // Our copy of the formatter got stored in the atomic
    413        return temp.orphan();
    414    }
    415 #else
    416    nonConstThis->fAtomicFormatter = temp.getAlias();
    417    return temp.orphan();
    418 #endif
    419 
    420 }
    421 
    422 
    423 #endif /* #if !UCONFIG_NO_FORMATTING */