tor-browser

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

NumberRangeFormat.h (7439B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 #ifndef intl_components_NumberRangeFormat_h_
      5 #define intl_components_NumberRangeFormat_h_
      6 
      7 #include "mozilla/FloatingPoint.h"
      8 #include "mozilla/intl/ICUError.h"
      9 #include "mozilla/intl/NumberFormat.h"
     10 #include "mozilla/Result.h"
     11 #include "mozilla/UniquePtr.h"
     12 
     13 #include <stdint.h>
     14 #include <string_view>
     15 
     16 #include "unicode/utypes.h"
     17 
     18 struct UFormattedNumberRange;
     19 struct UNumberRangeFormatter;
     20 struct UPluralRules;
     21 
     22 namespace mozilla::intl {
     23 
     24 /**
     25 * NumberRangeFormatOptions supports the same set of options as
     26 * NumberFormatOptions and additionally allows to control how to display ranges.
     27 */
     28 struct MOZ_STACK_CLASS NumberRangeFormatOptions : public NumberFormatOptions {
     29  /**
     30   * Controls if and how to collapse identical parts in a range.
     31   */
     32  enum class RangeCollapse {
     33    /**
     34     * Apply locale-specific heuristics.
     35     */
     36    Auto,
     37 
     38    /**
     39     * Never collapse identical parts.
     40     */
     41    None,
     42 
     43    /**
     44     * Collapse identical unit parts.
     45     */
     46    Unit,
     47 
     48    /**
     49     * Collapse all identical parts.
     50     */
     51    All,
     52  } mRangeCollapse = RangeCollapse::Auto;
     53 
     54  /**
     55   * Controls how to display identical numbers.
     56   */
     57  enum class RangeIdentityFallback {
     58    /**
     59     * Display the range as a single value.
     60     */
     61    SingleValue,
     62 
     63    /**
     64     * Display the range as a single value if both numbers were equal before
     65     * rounding. Otherwise display with a locale-sensitive approximation
     66     * pattern.
     67     */
     68    ApproximatelyOrSingleValue,
     69 
     70    /**
     71     * Display with a locale-sensitive approximation pattern.
     72     */
     73    Approximately,
     74 
     75    /**
     76     * Display as a range expression.
     77     */
     78    Range,
     79  } mRangeIdentityFallback = RangeIdentityFallback::SingleValue;
     80 };
     81 
     82 /**
     83 * A NumberRangeFormat implementation that roughly mirrors the API provided by
     84 * the ECMA-402 Intl.NumberFormat object for formatting number ranges.
     85 *
     86 * https://tc39.es/ecma402/#numberformat-objects
     87 */
     88 class NumberRangeFormat final {
     89 public:
     90  /**
     91   * Initialize a new NumberRangeFormat for the provided locale and using the
     92   * provided options.
     93   *
     94   * https://tc39.es/ecma402/#sec-initializenumberformat
     95   */
     96  static Result<UniquePtr<NumberRangeFormat>, ICUError> TryCreate(
     97      std::string_view aLocale, const NumberRangeFormatOptions& aOptions);
     98 
     99  NumberRangeFormat() = default;
    100  NumberRangeFormat(const NumberRangeFormat&) = delete;
    101  NumberRangeFormat& operator=(const NumberRangeFormat&) = delete;
    102 
    103  ~NumberRangeFormat();
    104 
    105  /**
    106   * Formats a double range to a utf-16 string. The string view is valid until
    107   * another number range is formatted. Accessing the string view after this
    108   * event is undefined behavior.
    109   *
    110   * https://tc39.es/ecma402/#sec-formatnumericrange
    111   */
    112  Result<std::u16string_view, ICUError> format(double start, double end) const {
    113    if (!formatInternal(start, end)) {
    114      return Err(ICUError::InternalError);
    115    }
    116 
    117    return formatResult();
    118  }
    119 
    120  /**
    121   * Formats a double range to a utf-16 string, and fills the provided parts
    122   * vector. The string view is valid until another number is formatted.
    123   * Accessing the string view after this event is undefined behavior.
    124   *
    125   * https://tc39.es/ecma402/#sec-partitionnumberrangepattern
    126   */
    127  Result<std::u16string_view, ICUError> formatToParts(
    128      double start, double end, NumberPartVector& parts) const {
    129    if (!formatInternal(start, end)) {
    130      return Err(ICUError::InternalError);
    131    }
    132 
    133    bool isNegativeStart = !std::isnan(start) && IsNegative(start);
    134    bool isNegativeEnd = !std::isnan(end) && IsNegative(end);
    135 
    136    return formatResultToParts(Some(start), isNegativeStart, Some(end),
    137                               isNegativeEnd, parts);
    138  }
    139 
    140  /**
    141   * Formats a decimal number range to a utf-16 string. The string view is valid
    142   * until another number range is formatted. Accessing the string view after
    143   * this event is undefined behavior.
    144   *
    145   * https://tc39.es/ecma402/#sec-formatnumericrange
    146   */
    147  Result<std::u16string_view, ICUError> format(std::string_view start,
    148                                               std::string_view end) const {
    149    if (!formatInternal(start, end)) {
    150      return Err(ICUError::InternalError);
    151    }
    152 
    153    return formatResult();
    154  }
    155 
    156  /**
    157   * Formats a string encoded decimal number range to a utf-16 string, and fills
    158   * the provided parts vector. The string view is valid until another number is
    159   * formatted. Accessing the string view after this event is undefined
    160   * behavior.
    161   *
    162   * https://tc39.es/ecma402/#sec-partitionnumberrangepattern
    163   */
    164  Result<std::u16string_view, ICUError> formatToParts(
    165      std::string_view start, std::string_view end,
    166      NumberPartVector& parts) const {
    167    if (!formatInternal(start, end)) {
    168      return Err(ICUError::InternalError);
    169    }
    170 
    171    Maybe<double> numStart = Nothing();
    172    if (start == "Infinity" || start == "+Infinity") {
    173      numStart.emplace(PositiveInfinity<double>());
    174    } else if (start == "-Infinity") {
    175      numStart.emplace(NegativeInfinity<double>());
    176    } else {
    177      // Not currently expected, so we assert here.
    178      MOZ_ASSERT(start != "NaN");
    179    }
    180 
    181    Maybe<double> numEnd = Nothing();
    182    if (end == "Infinity" || end == "+Infinity") {
    183      numEnd.emplace(PositiveInfinity<double>());
    184    } else if (end == "-Infinity") {
    185      numEnd.emplace(NegativeInfinity<double>());
    186    } else {
    187      // Not currently expected, so we assert here.
    188      MOZ_ASSERT(end != "NaN");
    189    }
    190 
    191    bool isNegativeStart = !start.empty() && start[0] == '-';
    192    bool isNegativeEnd = !end.empty() && end[0] == '-';
    193 
    194    return formatResultToParts(numStart, isNegativeStart, numEnd, isNegativeEnd,
    195                               parts);
    196  }
    197 
    198  /**
    199   * Formats the number range and selects the keyword by using a provided
    200   * UPluralRules object.
    201   *
    202   * https://tc39.es/ecma402/#sec-intl.pluralrules.prototype.selectrange
    203   *
    204   * TODO(1713917) This is necessary because both PluralRules and
    205   * NumberRangeFormat have a shared dependency on the raw UFormattedNumberRange
    206   * type. Once we transition to using ICU4X, the FFI calls should no
    207   * longer require such shared dependencies. At that time, this
    208   * functionality should be removed from NumberRangeFormat and invoked
    209   * solely from PluralRules.
    210   */
    211  Result<int32_t, ICUError> selectForRange(
    212      double start, double end, char16_t* keyword, int32_t keywordSize,
    213      const UPluralRules* pluralRules) const;
    214 
    215 private:
    216  UNumberRangeFormatter* mNumberRangeFormatter = nullptr;
    217  UFormattedNumberRange* mFormattedNumberRange = nullptr;
    218  bool mFormatForUnit = false;
    219 
    220  Result<Ok, ICUError> initialize(std::string_view aLocale,
    221                                  const NumberRangeFormatOptions& aOptions);
    222 
    223  [[nodiscard]] bool formatInternal(double start, double end) const;
    224 
    225  [[nodiscard]] bool formatInternal(std::string_view start,
    226                                    std::string_view end) const;
    227 
    228  Result<std::u16string_view, ICUError> formatResult() const;
    229 
    230  Result<std::u16string_view, ICUError> formatResultToParts(
    231      Maybe<double> start, bool startIsNegative, Maybe<double> end,
    232      bool endIsNegative, NumberPartVector& parts) const;
    233 };
    234 
    235 }  // namespace mozilla::intl
    236 
    237 #endif