tor-browser

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

RelativeTimeFormat.h (4867B)


      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_RelativeTimeFormat_h_
      5 #define intl_components_RelativeTimeFormat_h_
      6 
      7 #include "mozilla/Try.h"
      8 #include "mozilla/intl/ICU4CGlue.h"
      9 #include "mozilla/intl/ICUError.h"
     10 #include "mozilla/intl/NumberPart.h"
     11 
     12 #include "unicode/ureldatefmt.h"
     13 #include "unicode/utypes.h"
     14 
     15 namespace mozilla::intl {
     16 
     17 struct RelativeTimeFormatOptions {
     18  enum class Style { Short, Narrow, Long };
     19  Style style = Style::Long;
     20 
     21  enum class Numeric {
     22    /**
     23     * Only strings with numeric components like `1 day ago`.
     24     */
     25    Always,
     26    /**
     27     * Natural-language strings like `yesterday` when possible,
     28     * otherwise strings with numeric components as in `7 months ago`.
     29     */
     30    Auto,
     31  };
     32  Numeric numeric = Numeric::Always;
     33 };
     34 
     35 /**
     36 * A RelativeTimeFormat implementation that roughly mirrors the API provided by
     37 * the ECMA-402 Intl.RelativeTimeFormat object.
     38 *
     39 * https://tc39.es/ecma402/#relativetimeformat-objects
     40 */
     41 class RelativeTimeFormat final {
     42 public:
     43  /**
     44   *
     45   * Initialize a new RelativeTimeFormat for the provided locale and using the
     46   * provided options.
     47   *
     48   * https://tc39.es/ecma402/#sec-InitializeRelativeTimeFormat
     49   */
     50  static Result<UniquePtr<RelativeTimeFormat>, ICUError> TryCreate(
     51      const char* aLocale, const RelativeTimeFormatOptions& aOptions);
     52 
     53  RelativeTimeFormat() = default;
     54 
     55  RelativeTimeFormat(RelativeTimeFormatOptions::Numeric aNumeric,
     56                     URelativeDateTimeFormatter* aFormatter,
     57                     UFormattedRelativeDateTime* aFormattedRelativeDateTime);
     58 
     59  RelativeTimeFormat(const RelativeTimeFormat&) = delete;
     60  RelativeTimeFormat& operator=(const RelativeTimeFormat&) = delete;
     61  ~RelativeTimeFormat();
     62 
     63  enum class FormatUnit {
     64    Second,
     65    Minute,
     66    Hour,
     67    Day,
     68    Week,
     69    Month,
     70    Quarter,
     71    Year
     72  };
     73 
     74  /**
     75   * Formats a double to the provider buffer (either utf-8 or utf-16)
     76   *
     77   * https://tc39.es/ecma402/#sec-FormatRelativeTime
     78   */
     79  template <typename B>
     80  Result<Ok, ICUError> format(double aNumber, FormatUnit aUnit,
     81                              B& aBuffer) const {
     82    static_assert(
     83        std::is_same_v<typename B::CharType, char> ||
     84            std::is_same_v<typename B::CharType, char16_t>,
     85        "The only buffer CharTypes supported by RelativeTimeFormat are char "
     86        "(for UTF-8 support) and char16_t (for UTF-16 support).");
     87 
     88    auto fmt = mNumeric == RelativeTimeFormatOptions::Numeric::Auto
     89                   ? ureldatefmt_format
     90                   : ureldatefmt_formatNumeric;
     91 
     92    if constexpr (std::is_same_v<typename B::CharType, char>) {
     93      mozilla::Vector<char16_t, StackU16VectorSize> u16Vec;
     94 
     95      MOZ_TRY(FillBufferWithICUCall(
     96          u16Vec, [this, aNumber, aUnit, fmt](UChar* target, int32_t length,
     97                                              UErrorCode* status) {
     98            return fmt(mFormatter, aNumber, ToURelativeDateTimeUnit(aUnit),
     99                       target, length, status);
    100          }));
    101 
    102      if (!FillBuffer(u16Vec, aBuffer)) {
    103        return Err(ICUError::OutOfMemory);
    104      }
    105      return Ok{};
    106    } else {
    107      static_assert(std::is_same_v<typename B::CharType, char16_t>);
    108 
    109      return FillBufferWithICUCall(
    110          aBuffer, [this, aNumber, aUnit, fmt](UChar* target, int32_t length,
    111                                               UErrorCode* status) {
    112            return fmt(mFormatter, aNumber, ToURelativeDateTimeUnit(aUnit),
    113                       target, length, status);
    114          });
    115    }
    116  }
    117 
    118  /**
    119   * Formats the relative time to a utf-16 string, and fills the provided parts
    120   * vector. The string view is valid until another time is formatted.
    121   * Accessing the string view after this event is undefined behavior.
    122   *
    123   * This is utf-16 only because the only current use case is in
    124   * SpiderMonkey. Supporting utf-8 would require recalculating the offsets
    125   * in NumberPartVector from fixed width to variable width, which might be
    126   * tricky to get right and is work that won't be necessary if we switch to
    127   * ICU4X (see Bug 1723120).
    128   *
    129   * https://tc39.es/ecma402/#sec-FormatRelativeTimeToParts
    130   */
    131  Result<Span<const char16_t>, ICUError> formatToParts(
    132      double aNumber, FormatUnit aUnit, NumberPartVector& aParts) const;
    133 
    134 private:
    135  RelativeTimeFormatOptions::Numeric mNumeric =
    136      RelativeTimeFormatOptions::Numeric::Always;
    137  URelativeDateTimeFormatter* mFormatter = nullptr;
    138  UFormattedRelativeDateTime* mFormattedRelativeDateTime = nullptr;
    139 
    140  static constexpr size_t StackU16VectorSize = 128;
    141 
    142  URelativeDateTimeUnit ToURelativeDateTimeUnit(FormatUnit unit) const;
    143 };
    144 
    145 }  // namespace mozilla::intl
    146 
    147 #endif