tor-browser

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

numberrangeformatter.h (26413B)


      1 // © 2018 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 
      4 #ifndef __NUMBERRANGEFORMATTER_H__
      5 #define __NUMBERRANGEFORMATTER_H__
      6 
      7 #include "unicode/utypes.h"
      8 
      9 #if U_SHOW_CPLUSPLUS_API
     10 
     11 #if !UCONFIG_NO_FORMATTING
     12 
     13 #include "unicode/appendable.h"
     14 #include "unicode/fieldpos.h"
     15 #include "unicode/formattedvalue.h"
     16 #include "unicode/fpositer.h"
     17 #include "unicode/numberformatter.h"
     18 #include "unicode/unumberrangeformatter.h"
     19 
     20 #ifndef __wasi__
     21 #include <atomic>
     22 #endif
     23 
     24 /**
     25 * \file
     26 * \brief C++ API: Library for localized formatting of number, currency, and unit ranges.
     27 *
     28 * The main entrypoint to the formatting of ranges of numbers, including currencies and other units of measurement.
     29 * <p>
     30 * Usage example:
     31 * <p>
     32 * <pre>
     33 * NumberRangeFormatter::with()
     34 *     .identityFallback(UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE)
     35 *     .numberFormatterFirst(NumberFormatter::with().adoptUnit(MeasureUnit::createMeter()))
     36 *     .numberFormatterSecond(NumberFormatter::with().adoptUnit(MeasureUnit::createKilometer()))
     37 *     .locale("en-GB")
     38 *     .formatFormattableRange(750, 1.2, status)
     39 *     .toString(status);
     40 * // => "750 m - 1.2 km"
     41 * </pre>
     42 * <p>
     43 * Like NumberFormatter, NumberRangeFormatter instances (i.e., LocalizedNumberRangeFormatter
     44 * and UnlocalizedNumberRangeFormatter) are immutable and thread-safe. This API is based on the
     45 * <em>fluent</em> design pattern popularized by libraries such as Google's Guava.
     46 *
     47 * @author Shane Carr
     48 */
     49 
     50 
     51 U_NAMESPACE_BEGIN
     52 
     53 // Forward declarations:
     54 class PluralRules;
     55 
     56 namespace number {  // icu::number
     57 
     58 // Forward declarations:
     59 class UnlocalizedNumberRangeFormatter;
     60 class LocalizedNumberRangeFormatter;
     61 class FormattedNumberRange;
     62 
     63 namespace impl {
     64 
     65 // Forward declarations:
     66 struct RangeMacroProps;
     67 class DecimalQuantity;
     68 class UFormattedNumberRangeData;
     69 class NumberRangeFormatterImpl;
     70 struct UFormattedNumberRangeImpl;
     71 
     72 } // namespace impl
     73 
     74 // Other helper classes would go here, but there are none.
     75 
     76 namespace impl {  // icu::number::impl
     77 
     78 // Do not enclose entire MacroProps with #ifndef U_HIDE_INTERNAL_API, needed for a protected field
     79 /** @internal */
     80 struct RangeMacroProps : public UMemory {
     81    /** @internal */
     82    UnlocalizedNumberFormatter formatter1; // = NumberFormatter::with();
     83 
     84    /** @internal */
     85    UnlocalizedNumberFormatter formatter2; // = NumberFormatter::with();
     86 
     87    /** @internal */
     88    bool singleFormatter = true;
     89 
     90    /** @internal */
     91    UNumberRangeCollapse collapse = UNUM_RANGE_COLLAPSE_AUTO;
     92 
     93    /** @internal */
     94    UNumberRangeIdentityFallback identityFallback = UNUM_IDENTITY_FALLBACK_APPROXIMATELY;
     95 
     96    /** @internal */
     97    Locale locale;
     98 
     99    // NOTE: Uses default copy and move constructors.
    100 
    101    /**
    102     * Check all members for errors.
    103     * @internal
    104     */
    105    bool copyErrorTo(UErrorCode &status) const {
    106        return formatter1.copyErrorTo(status) || formatter2.copyErrorTo(status);
    107    }
    108 };
    109 
    110 } // namespace impl
    111 
    112 /**
    113 * An abstract base class for specifying settings related to number formatting. This class is implemented by
    114 * {@link UnlocalizedNumberRangeFormatter} and {@link LocalizedNumberRangeFormatter}. This class is not intended for
    115 * public subclassing.
    116 */
    117 template<typename Derived>
    118 class U_I18N_API NumberRangeFormatterSettings {
    119  public:
    120    /**
    121     * Sets the NumberFormatter instance to use for the numbers in the range. The same formatter is applied to both
    122     * sides of the range.
    123     * <p>
    124     * The NumberFormatter instances must not have a locale applied yet; the locale specified on the
    125     * NumberRangeFormatter will be used.
    126     *
    127     * @param formatter
    128     *            The formatter to use for both numbers in the range.
    129     * @return The fluent chain.
    130     * @stable ICU 63
    131     */
    132    Derived numberFormatterBoth(const UnlocalizedNumberFormatter &formatter) const &;
    133 
    134    /**
    135     * Overload of numberFormatterBoth() for use on an rvalue reference.
    136     *
    137     * @param formatter
    138     *            The formatter to use for both numbers in the range.
    139     * @return The fluent chain.
    140     * @see #numberFormatterBoth
    141     * @stable ICU 63
    142     */
    143    Derived numberFormatterBoth(const UnlocalizedNumberFormatter &formatter) &&;
    144 
    145    /**
    146     * Overload of numberFormatterBoth() for use on an rvalue reference.
    147     *
    148     * @param formatter
    149     *            The formatter to use for both numbers in the range.
    150     * @return The fluent chain.
    151     * @see #numberFormatterBoth
    152     * @stable ICU 63
    153     */
    154    Derived numberFormatterBoth(UnlocalizedNumberFormatter &&formatter) const &;
    155 
    156    /**
    157     * Overload of numberFormatterBoth() for use on an rvalue reference.
    158     *
    159     * @param formatter
    160     *            The formatter to use for both numbers in the range.
    161     * @return The fluent chain.
    162     * @see #numberFormatterBoth
    163     * @stable ICU 63
    164     */
    165    Derived numberFormatterBoth(UnlocalizedNumberFormatter &&formatter) &&;
    166 
    167    /**
    168     * Sets the NumberFormatter instance to use for the first number in the range.
    169     * <p>
    170     * The NumberFormatter instances must not have a locale applied yet; the locale specified on the
    171     * NumberRangeFormatter will be used.
    172     *
    173     * @param formatterFirst
    174     *            The formatter to use for the first number in the range.
    175     * @return The fluent chain.
    176     * @stable ICU 63
    177     */
    178    Derived numberFormatterFirst(const UnlocalizedNumberFormatter &formatterFirst) const &;
    179 
    180    /**
    181     * Overload of numberFormatterFirst() for use on an rvalue reference.
    182     *
    183     * @param formatterFirst
    184     *            The formatter to use for the first number in the range.
    185     * @return The fluent chain.
    186     * @see #numberFormatterFirst
    187     * @stable ICU 63
    188     */
    189    Derived numberFormatterFirst(const UnlocalizedNumberFormatter &formatterFirst) &&;
    190 
    191    /**
    192     * Overload of numberFormatterFirst() for use on an rvalue reference.
    193     *
    194     * @param formatterFirst
    195     *            The formatter to use for the first number in the range.
    196     * @return The fluent chain.
    197     * @see #numberFormatterFirst
    198     * @stable ICU 63
    199     */
    200    Derived numberFormatterFirst(UnlocalizedNumberFormatter &&formatterFirst) const &;
    201 
    202    /**
    203     * Overload of numberFormatterFirst() for use on an rvalue reference.
    204     *
    205     * @param formatterFirst
    206     *            The formatter to use for the first number in the range.
    207     * @return The fluent chain.
    208     * @see #numberFormatterFirst
    209     * @stable ICU 63
    210     */
    211    Derived numberFormatterFirst(UnlocalizedNumberFormatter &&formatterFirst) &&;
    212 
    213    /**
    214     * Sets the NumberFormatter instance to use for the second number in the range.
    215     * <p>
    216     * The NumberFormatter instances must not have a locale applied yet; the locale specified on the
    217     * NumberRangeFormatter will be used.
    218     *
    219     * @param formatterSecond
    220     *            The formatter to use for the second number in the range.
    221     * @return The fluent chain.
    222     * @stable ICU 63
    223     */
    224    Derived numberFormatterSecond(const UnlocalizedNumberFormatter &formatterSecond) const &;
    225 
    226    /**
    227     * Overload of numberFormatterSecond() for use on an rvalue reference.
    228     *
    229     * @param formatterSecond
    230     *            The formatter to use for the second number in the range.
    231     * @return The fluent chain.
    232     * @see #numberFormatterSecond
    233     * @stable ICU 63
    234     */
    235    Derived numberFormatterSecond(const UnlocalizedNumberFormatter &formatterSecond) &&;
    236 
    237    /**
    238     * Overload of numberFormatterSecond() for use on an rvalue reference.
    239     *
    240     * @param formatterSecond
    241     *            The formatter to use for the second number in the range.
    242     * @return The fluent chain.
    243     * @see #numberFormatterSecond
    244     * @stable ICU 63
    245     */
    246    Derived numberFormatterSecond(UnlocalizedNumberFormatter &&formatterSecond) const &;
    247 
    248    /**
    249     * Overload of numberFormatterSecond() for use on an rvalue reference.
    250     *
    251     * @param formatterSecond
    252     *            The formatter to use for the second number in the range.
    253     * @return The fluent chain.
    254     * @see #numberFormatterSecond
    255     * @stable ICU 63
    256     */
    257    Derived numberFormatterSecond(UnlocalizedNumberFormatter &&formatterSecond) &&;
    258 
    259    /**
    260     * Sets the aggressiveness of "collapsing" fields across the range separator. Possible values:
    261     * <p>
    262     * <ul>
    263     * <li>ALL: "3-5K miles"</li>
    264     * <li>UNIT: "3K - 5K miles"</li>
    265     * <li>NONE: "3K miles - 5K miles"</li>
    266     * <li>AUTO: usually UNIT or NONE, depending on the locale and formatter settings</li>
    267     * </ul>
    268     * <p>
    269     * The default value is AUTO.
    270     *
    271     * @param collapse
    272     *            The collapsing strategy to use for this range.
    273     * @return The fluent chain.
    274     * @stable ICU 63
    275     */
    276    Derived collapse(UNumberRangeCollapse collapse) const &;
    277 
    278    /**
    279     * Overload of collapse() for use on an rvalue reference.
    280     *
    281     * @param collapse
    282     *            The collapsing strategy to use for this range.
    283     * @return The fluent chain.
    284     * @see #collapse
    285     * @stable ICU 63
    286     */
    287    Derived collapse(UNumberRangeCollapse collapse) &&;
    288 
    289    /**
    290     * Sets the behavior when the two sides of the range are the same. This could happen if the same two numbers are
    291     * passed to the formatFormattableRange function, or if different numbers are passed to the function but they
    292     * become the same after rounding rules are applied. Possible values:
    293     * <p>
    294     * <ul>
    295     * <li>SINGLE_VALUE: "5 miles"</li>
    296     * <li>APPROXIMATELY_OR_SINGLE_VALUE: "~5 miles" or "5 miles", depending on whether the number was the same before
    297     * rounding was applied</li>
    298     * <li>APPROXIMATELY: "~5 miles"</li>
    299     * <li>RANGE: "5-5 miles" (with collapse=UNIT)</li>
    300     * </ul>
    301     * <p>
    302     * The default value is APPROXIMATELY.
    303     *
    304     * @param identityFallback
    305     *            The strategy to use when formatting two numbers that end up being the same.
    306     * @return The fluent chain.
    307     * @stable ICU 63
    308     */
    309    Derived identityFallback(UNumberRangeIdentityFallback identityFallback) const &;
    310 
    311    /**
    312     * Overload of identityFallback() for use on an rvalue reference.
    313     *
    314     * @param identityFallback
    315     *            The strategy to use when formatting two numbers that end up being the same.
    316     * @return The fluent chain.
    317     * @see #identityFallback
    318     * @stable ICU 63
    319     */
    320    Derived identityFallback(UNumberRangeIdentityFallback identityFallback) &&;
    321 
    322    /**
    323     * Returns the current (Un)LocalizedNumberRangeFormatter as a LocalPointer
    324     * wrapping a heap-allocated copy of the current object.
    325     *
    326     * This is equivalent to new-ing the move constructor with a value object
    327     * as the argument.
    328     *
    329     * @return A wrapped (Un)LocalizedNumberRangeFormatter pointer, or a wrapped
    330     *         nullptr on failure.
    331     * @stable ICU 64
    332     */
    333    LocalPointer<Derived> clone() const &;
    334 
    335    /**
    336     * Overload of clone for use on an rvalue reference.
    337     *
    338     * @return A wrapped (Un)LocalizedNumberRangeFormatter pointer, or a wrapped
    339     *         nullptr on failure.
    340     * @stable ICU 64
    341     */
    342    LocalPointer<Derived> clone() &&;
    343 
    344    /**
    345     * Sets the UErrorCode if an error occurred in the fluent chain.
    346     * Preserves older error codes in the outErrorCode.
    347     * @return true if U_FAILURE(outErrorCode)
    348     * @stable ICU 63
    349     */
    350    UBool copyErrorTo(UErrorCode &outErrorCode) const {
    351        if (U_FAILURE(outErrorCode)) {
    352            // Do not overwrite the older error code
    353            return true;
    354        }
    355        fMacros.copyErrorTo(outErrorCode);
    356        return U_FAILURE(outErrorCode);
    357    }
    358 
    359    // NOTE: Uses default copy and move constructors.
    360 
    361  private:
    362    impl::RangeMacroProps fMacros;
    363 
    364    // Don't construct me directly!  Use (Un)LocalizedNumberFormatter.
    365    NumberRangeFormatterSettings() = default;
    366 
    367    friend class LocalizedNumberRangeFormatter;
    368    friend class UnlocalizedNumberRangeFormatter;
    369 };
    370 
    371 // Explicit instantiations in source/i18n/numrange_fluent.cpp.
    372 // (MSVC treats imports/exports of explicit instantiations differently.)
    373 #ifndef _MSC_VER
    374 extern template class NumberRangeFormatterSettings<UnlocalizedNumberRangeFormatter>;
    375 extern template class NumberRangeFormatterSettings<LocalizedNumberRangeFormatter>;
    376 #endif
    377 
    378 /**
    379 * A NumberRangeFormatter that does not yet have a locale. In order to format, a locale must be specified.
    380 *
    381 * Instances of this class are immutable and thread-safe.
    382 *
    383 * @see NumberRangeFormatter
    384 * @stable ICU 63
    385 */
    386 class U_I18N_API UnlocalizedNumberRangeFormatter
    387        : public NumberRangeFormatterSettings<UnlocalizedNumberRangeFormatter>, public UMemory {
    388 
    389  public:
    390    /**
    391     * Associate the given locale with the number range formatter. The locale is used for picking the
    392     * appropriate symbols, formats, and other data for number display.
    393     *
    394     * @param locale
    395     *            The locale to use when loading data for number formatting.
    396     * @return The fluent chain.
    397     * @stable ICU 63
    398     */
    399    LocalizedNumberRangeFormatter locale(const icu::Locale &locale) const &;
    400 
    401    /**
    402     * Overload of locale() for use on an rvalue reference.
    403     *
    404     * @param locale
    405     *            The locale to use when loading data for number formatting.
    406     * @return The fluent chain.
    407     * @see #locale
    408     * @stable ICU 63
    409     */
    410    LocalizedNumberRangeFormatter locale(const icu::Locale &locale) &&;
    411 
    412    /**
    413     * Default constructor: puts the formatter into a valid but undefined state.
    414     *
    415     * @stable ICU 63
    416     */
    417    UnlocalizedNumberRangeFormatter() = default;
    418 
    419    /**
    420     * Returns a copy of this UnlocalizedNumberRangeFormatter.
    421     * @stable ICU 63
    422     */
    423    UnlocalizedNumberRangeFormatter(const UnlocalizedNumberRangeFormatter &other);
    424 
    425    /**
    426     * Move constructor:
    427     * The source UnlocalizedNumberRangeFormatter will be left in a valid but undefined state.
    428     * @stable ICU 63
    429     */
    430    UnlocalizedNumberRangeFormatter(UnlocalizedNumberRangeFormatter&& src) noexcept;
    431 
    432    /**
    433     * Copy assignment operator.
    434     * @stable ICU 63
    435     */
    436    UnlocalizedNumberRangeFormatter& operator=(const UnlocalizedNumberRangeFormatter& other);
    437 
    438    /**
    439     * Move assignment operator:
    440     * The source UnlocalizedNumberRangeFormatter will be left in a valid but undefined state.
    441     * @stable ICU 63
    442     */
    443    UnlocalizedNumberRangeFormatter& operator=(UnlocalizedNumberRangeFormatter&& src) noexcept;
    444 
    445  private:
    446    explicit UnlocalizedNumberRangeFormatter(
    447            const NumberRangeFormatterSettings<UnlocalizedNumberRangeFormatter>& other);
    448 
    449    explicit UnlocalizedNumberRangeFormatter(
    450            NumberRangeFormatterSettings<UnlocalizedNumberRangeFormatter>&& src) noexcept;
    451 
    452    explicit UnlocalizedNumberRangeFormatter(const impl::RangeMacroProps &macros);
    453 
    454    explicit UnlocalizedNumberRangeFormatter(impl::RangeMacroProps &&macros);
    455 
    456    // To give the fluent setters access to this class's constructor:
    457    friend class NumberRangeFormatterSettings<UnlocalizedNumberRangeFormatter>;
    458 
    459    // To give NumberRangeFormatter::with() access to this class's constructor:
    460    friend class NumberRangeFormatter;
    461 
    462    // To give LNRF::withoutLocale() access to this class's constructor:
    463    friend class LocalizedNumberRangeFormatter;
    464 };
    465 
    466 /**
    467 * A NumberRangeFormatter that has a locale associated with it; this means .formatRange() methods are available.
    468 *
    469 * Instances of this class are immutable and thread-safe.
    470 *
    471 * @see NumberFormatter
    472 * @stable ICU 63
    473 */
    474 class U_I18N_API_CLASS LocalizedNumberRangeFormatter
    475        : public NumberRangeFormatterSettings<LocalizedNumberRangeFormatter>, public UMemory {
    476  public:
    477    /**
    478     * Format the given Formattables to a string using the settings specified in the NumberRangeFormatter fluent setting
    479     * chain.
    480     *
    481     * @param first
    482     *            The first number in the range, usually to the left in LTR locales.
    483     * @param second
    484     *            The second number in the range, usually to the right in LTR locales.
    485     * @param status
    486     *            Set if an error occurs while formatting.
    487     * @return A FormattedNumberRange object; call .toString() to get the string.
    488     * @stable ICU 63
    489     */
    490    U_I18N_API FormattedNumberRange formatFormattableRange(
    491        const Formattable& first, const Formattable& second, UErrorCode& status) const;
    492 
    493    /**
    494     * Disassociate the locale from this formatter.
    495     *
    496     * @return The fluent chain.
    497     * @stable ICU 75
    498     */
    499    U_I18N_API UnlocalizedNumberRangeFormatter withoutLocale() const &;
    500 
    501    /**
    502     * Overload of withoutLocale() for use on an rvalue reference.
    503     *
    504     * @return The fluent chain.
    505     * @see #withoutLocale
    506     * @stable ICU 75
    507     */
    508    U_I18N_API UnlocalizedNumberRangeFormatter withoutLocale() &&;
    509 
    510    /**
    511     * Default constructor: puts the formatter into a valid but undefined state.
    512     *
    513     * @stable ICU 63
    514     */
    515    U_I18N_API LocalizedNumberRangeFormatter() = default;
    516 
    517    /**
    518     * Returns a copy of this LocalizedNumberRangeFormatter.
    519     * @stable ICU 63
    520     */
    521    U_I18N_API LocalizedNumberRangeFormatter(const LocalizedNumberRangeFormatter &other);
    522 
    523    /**
    524     * Move constructor:
    525     * The source LocalizedNumberRangeFormatter will be left in a valid but undefined state.
    526     * @stable ICU 63
    527     */
    528    U_I18N_API LocalizedNumberRangeFormatter(LocalizedNumberRangeFormatter&& src) noexcept;
    529 
    530    /**
    531     * Copy assignment operator.
    532     * @stable ICU 63
    533     */
    534    U_I18N_API LocalizedNumberRangeFormatter& operator=(const LocalizedNumberRangeFormatter& other);
    535 
    536    /**
    537     * Move assignment operator:
    538     * The source LocalizedNumberRangeFormatter will be left in a valid but undefined state.
    539     * @stable ICU 63
    540     */
    541    U_I18N_API LocalizedNumberRangeFormatter& operator=(LocalizedNumberRangeFormatter&& src) noexcept;
    542 
    543 #ifndef U_HIDE_INTERNAL_API
    544 
    545    /**
    546     * @param results
    547     *            The results object. This method will mutate it to save the results.
    548     * @param equalBeforeRounding
    549     *            Whether the number was equal before copying it into a DecimalQuantity.
    550     *            Used for determining the identity fallback behavior.
    551     * @param status
    552     *            Set if an error occurs while formatting.
    553     * @internal
    554     */
    555    U_I18N_API void formatImpl(impl::UFormattedNumberRangeData &results, bool equalBeforeRounding,
    556                               UErrorCode &status) const;
    557 
    558 #endif  /* U_HIDE_INTERNAL_API */
    559 
    560    /**
    561     * Destruct this LocalizedNumberRangeFormatter, cleaning up any memory it might own.
    562     * @stable ICU 63
    563     */
    564    U_I18N_API ~LocalizedNumberRangeFormatter();
    565 
    566  private:
    567 #ifndef __wasi__
    568    std::atomic<impl::NumberRangeFormatterImpl*> fAtomicFormatter = {};
    569 #else
    570    impl::NumberRangeFormatterImpl* fAtomicFormatter = nullptr;
    571 #endif
    572 
    573    const impl::NumberRangeFormatterImpl* getFormatter(UErrorCode& stauts) const;
    574 
    575    explicit LocalizedNumberRangeFormatter(
    576        const NumberRangeFormatterSettings<LocalizedNumberRangeFormatter>& other);
    577 
    578    explicit LocalizedNumberRangeFormatter(
    579        NumberRangeFormatterSettings<LocalizedNumberRangeFormatter>&& src) noexcept;
    580 
    581    LocalizedNumberRangeFormatter(const impl::RangeMacroProps &macros, const Locale &locale);
    582 
    583    LocalizedNumberRangeFormatter(impl::RangeMacroProps &&macros, const Locale &locale);
    584 
    585    // To give the fluent setters access to this class's constructor:
    586    friend class NumberRangeFormatterSettings<UnlocalizedNumberRangeFormatter>;
    587    friend class NumberRangeFormatterSettings<LocalizedNumberRangeFormatter>;
    588 
    589    // To give UnlocalizedNumberRangeFormatter::locale() access to this class's constructor:
    590    friend class UnlocalizedNumberRangeFormatter;
    591 };
    592 
    593 /**
    594 * The result of a number range formatting operation. This class allows the result to be exported in several data types,
    595 * including a UnicodeString and a FieldPositionIterator.
    596 *
    597 * Instances of this class are immutable and thread-safe.
    598 *
    599 * @stable ICU 63
    600 */
    601 class U_I18N_API FormattedNumberRange : public UMemory, public FormattedValue {
    602  public:
    603    // Copybrief: this method is older than the parent method
    604    /**
    605     * @copybrief FormattedValue::toString()
    606     *
    607     * For more information, see FormattedValue::toString()
    608     *
    609     * @stable ICU 63
    610     */
    611    UnicodeString toString(UErrorCode& status) const override;
    612 
    613    // Copydoc: this method is new in ICU 64
    614    /** @copydoc FormattedValue::toTempString() */
    615    UnicodeString toTempString(UErrorCode& status) const override;
    616 
    617    // Copybrief: this method is older than the parent method
    618    /**
    619     * @copybrief FormattedValue::appendTo()
    620     *
    621     * For more information, see FormattedValue::appendTo()
    622     *
    623     * @stable ICU 63
    624     */
    625    Appendable &appendTo(Appendable &appendable, UErrorCode& status) const override;
    626 
    627    // Copydoc: this method is new in ICU 64
    628    /** @copydoc FormattedValue::nextPosition() */
    629    UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const override;
    630 
    631    /**
    632     * Extracts the formatted range as a pair of decimal numbers. This endpoint
    633     * is useful for obtaining the exact number being printed after scaling
    634     * and rounding have been applied by the number range formatting pipeline.
    635     * 
    636     * The syntax of the unformatted numbers is a "numeric string"
    637     * as defined in the Decimal Arithmetic Specification, available at
    638     * http://speleotrove.com/decimal
    639     *
    640     * Example C++17 call site:
    641     *
    642     *     auto [ first, second ] = range.getDecimalNumbers<std::string>(status);
    643     *
    644     * @tparam StringClass A string class compatible with StringByteSink;
    645     *         for example, std::string.
    646     * @param status Set if an error occurs.
    647     * @return A pair of StringClasses containing the numeric strings.
    648     * @stable ICU 68
    649     */
    650    template<typename StringClass>
    651    inline std::pair<StringClass, StringClass> getDecimalNumbers(UErrorCode& status) const;
    652 
    653    /**
    654     * Returns whether the pair of numbers was successfully formatted as a range or whether an identity fallback was
    655     * used. For example, if the first and second number were the same either before or after rounding occurred, an
    656     * identity fallback was used.
    657     *
    658     * @return An indication the resulting identity situation in the formatted number range.
    659     * @stable ICU 63
    660     * @see UNumberRangeIdentityFallback
    661     */
    662    UNumberRangeIdentityResult getIdentityResult(UErrorCode& status) const;
    663 
    664    /**
    665     * Default constructor; makes an empty FormattedNumberRange.
    666     * @stable ICU 70
    667     */
    668    FormattedNumberRange()
    669        : fData(nullptr), fErrorCode(U_INVALID_STATE_ERROR) {}
    670 
    671    /**
    672     * Copying not supported; use move constructor instead.
    673     */
    674    FormattedNumberRange(const FormattedNumberRange&) = delete;
    675 
    676    /**
    677     * Copying not supported; use move assignment instead.
    678     */
    679    FormattedNumberRange& operator=(const FormattedNumberRange&) = delete;
    680 
    681    /**
    682     * Move constructor:
    683     * Leaves the source FormattedNumberRange in an undefined state.
    684     * @stable ICU 63
    685     */
    686    FormattedNumberRange(FormattedNumberRange&& src) noexcept;
    687 
    688    /**
    689     * Move assignment:
    690     * Leaves the source FormattedNumberRange in an undefined state.
    691     * @stable ICU 63
    692     */
    693    FormattedNumberRange& operator=(FormattedNumberRange&& src) noexcept;
    694 
    695    /**
    696     * Destruct an instance of FormattedNumberRange, cleaning up any memory it might own.
    697     * @stable ICU 63
    698     */
    699    ~FormattedNumberRange();
    700 
    701  private:
    702    // Can't use LocalPointer because UFormattedNumberRangeData is forward-declared
    703    const impl::UFormattedNumberRangeData *fData;
    704 
    705    // Error code for the terminal methods
    706    UErrorCode fErrorCode;
    707 
    708    /**
    709     * Internal constructor from data type. Adopts the data pointer.
    710     */
    711    explicit FormattedNumberRange(impl::UFormattedNumberRangeData *results)
    712        : fData(results), fErrorCode(U_ZERO_ERROR) {}
    713 
    714    explicit FormattedNumberRange(UErrorCode errorCode)
    715        : fData(nullptr), fErrorCode(errorCode) {}
    716 
    717    void getDecimalNumbers(ByteSink& sink1, ByteSink& sink2, UErrorCode& status) const;
    718 
    719    const impl::UFormattedNumberRangeData* getData(UErrorCode& status) const;
    720 
    721    // To allow PluralRules to access the underlying data
    722    friend class ::icu::PluralRules;
    723 
    724    // To give LocalizedNumberRangeFormatter format methods access to this class's constructor:
    725    friend class LocalizedNumberRangeFormatter;
    726 
    727    // To give C API access to internals
    728    friend struct impl::UFormattedNumberRangeImpl;
    729 };
    730 
    731 // inline impl of @stable ICU 68 method
    732 template<typename StringClass>
    733 std::pair<StringClass, StringClass> FormattedNumberRange::getDecimalNumbers(UErrorCode& status) const {
    734    StringClass str1;
    735    StringClass str2;
    736    StringByteSink<StringClass> sink1(&str1);
    737    StringByteSink<StringClass> sink2(&str2);
    738    getDecimalNumbers(sink1, sink2, status);
    739    return std::make_pair(str1, str2);
    740 }
    741 
    742 /**
    743 * See the main description in numberrangeformatter.h for documentation and examples.
    744 *
    745 * @stable ICU 63
    746 */
    747 class U_I18N_API NumberRangeFormatter final {
    748  public:
    749    /**
    750     * Call this method at the beginning of a NumberRangeFormatter fluent chain in which the locale is not currently
    751     * known at the call site.
    752     *
    753     * @return An {@link UnlocalizedNumberRangeFormatter}, to be used for chaining.
    754     * @stable ICU 63
    755     */
    756    static UnlocalizedNumberRangeFormatter with();
    757 
    758    /**
    759     * Call this method at the beginning of a NumberRangeFormatter fluent chain in which the locale is known at the call
    760     * site.
    761     *
    762     * @param locale
    763     *            The locale from which to load formats and symbols for number range formatting.
    764     * @return A {@link LocalizedNumberRangeFormatter}, to be used for chaining.
    765     * @stable ICU 63
    766     */
    767    static LocalizedNumberRangeFormatter withLocale(const Locale &locale);
    768 
    769    /**
    770     * Use factory methods instead of the constructor to create a NumberFormatter.
    771     */
    772    NumberRangeFormatter() = delete;
    773 };
    774 
    775 }  // namespace number
    776 U_NAMESPACE_END
    777 
    778 #endif /* #if !UCONFIG_NO_FORMATTING */
    779 
    780 #endif /* U_SHOW_CPLUSPLUS_API */
    781 
    782 #endif // __NUMBERRANGEFORMATTER_H__