jpayne@69: // © 2018 and later: Unicode, Inc. and others. jpayne@69: // License & terms of use: http://www.unicode.org/copyright.html jpayne@69: jpayne@69: #ifndef __NUMBERRANGEFORMATTER_H__ jpayne@69: #define __NUMBERRANGEFORMATTER_H__ jpayne@69: jpayne@69: #include "unicode/utypes.h" jpayne@69: jpayne@69: #if U_SHOW_CPLUSPLUS_API jpayne@69: jpayne@69: #if !UCONFIG_NO_FORMATTING jpayne@69: jpayne@69: #include jpayne@69: #include "unicode/appendable.h" jpayne@69: #include "unicode/fieldpos.h" jpayne@69: #include "unicode/formattedvalue.h" jpayne@69: #include "unicode/fpositer.h" jpayne@69: #include "unicode/numberformatter.h" jpayne@69: jpayne@69: /** jpayne@69: * \file jpayne@69: * \brief C++ API: Library for localized formatting of number, currency, and unit ranges. jpayne@69: * jpayne@69: * The main entrypoint to the formatting of ranges of numbers, including currencies and other units of measurement. jpayne@69: *

jpayne@69: * Usage example: jpayne@69: *

jpayne@69: *

jpayne@69:  * NumberRangeFormatter::with()
jpayne@69:  *     .identityFallback(UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE)
jpayne@69:  *     .numberFormatterFirst(NumberFormatter::with().adoptUnit(MeasureUnit::createMeter()))
jpayne@69:  *     .numberFormatterSecond(NumberFormatter::with().adoptUnit(MeasureUnit::createKilometer()))
jpayne@69:  *     .locale("en-GB")
jpayne@69:  *     .formatRange(750, 1.2, status)
jpayne@69:  *     .toString(status);
jpayne@69:  * // => "750 m - 1.2 km"
jpayne@69:  * 
jpayne@69: *

jpayne@69: * Like NumberFormatter, NumberRangeFormatter instances (i.e., LocalizedNumberRangeFormatter jpayne@69: * and UnlocalizedNumberRangeFormatter) are immutable and thread-safe. This API is based on the jpayne@69: * fluent design pattern popularized by libraries such as Google's Guava. jpayne@69: * jpayne@69: * @author Shane Carr jpayne@69: */ jpayne@69: jpayne@69: jpayne@69: /** jpayne@69: * Defines how to merge fields that are identical across the range sign. jpayne@69: * jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: typedef enum UNumberRangeCollapse { jpayne@69: /** jpayne@69: * Use locale data and heuristics to determine how much of the string to collapse. Could end up collapsing none, jpayne@69: * some, or all repeated pieces in a locale-sensitive way. jpayne@69: * jpayne@69: * The heuristics used for this option are subject to change over time. jpayne@69: * jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: UNUM_RANGE_COLLAPSE_AUTO, jpayne@69: jpayne@69: /** jpayne@69: * Do not collapse any part of the number. Example: "3.2 thousand kilograms – 5.3 thousand kilograms" jpayne@69: * jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: UNUM_RANGE_COLLAPSE_NONE, jpayne@69: jpayne@69: /** jpayne@69: * Collapse the unit part of the number, but not the notation, if present. Example: "3.2 thousand – 5.3 thousand jpayne@69: * kilograms" jpayne@69: * jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: UNUM_RANGE_COLLAPSE_UNIT, jpayne@69: jpayne@69: /** jpayne@69: * Collapse any field that is equal across the range sign. May introduce ambiguity on the magnitude of the jpayne@69: * number. Example: "3.2 – 5.3 thousand kilograms" jpayne@69: * jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: UNUM_RANGE_COLLAPSE_ALL jpayne@69: } UNumberRangeCollapse; jpayne@69: jpayne@69: /** jpayne@69: * Defines the behavior when the two numbers in the range are identical after rounding. To programmatically detect jpayne@69: * when the identity fallback is used, compare the lower and upper BigDecimals via FormattedNumber. jpayne@69: * jpayne@69: * @stable ICU 63 jpayne@69: * @see NumberRangeFormatter jpayne@69: */ jpayne@69: typedef enum UNumberRangeIdentityFallback { jpayne@69: /** jpayne@69: * Show the number as a single value rather than a range. Example: "$5" jpayne@69: * jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: UNUM_IDENTITY_FALLBACK_SINGLE_VALUE, jpayne@69: jpayne@69: /** jpayne@69: * Show the number using a locale-sensitive approximation pattern. If the numbers were the same before rounding, jpayne@69: * show the single value. Example: "~$5" or "$5" jpayne@69: * jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE, jpayne@69: jpayne@69: /** jpayne@69: * Show the number using a locale-sensitive approximation pattern. Use the range pattern always, even if the jpayne@69: * inputs are the same. Example: "~$5" jpayne@69: * jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: UNUM_IDENTITY_FALLBACK_APPROXIMATELY, jpayne@69: jpayne@69: /** jpayne@69: * Show the number as the range of two equal values. Use the range pattern always, even if the inputs are the jpayne@69: * same. Example (with RangeCollapse.NONE): "$5 – $5" jpayne@69: * jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: UNUM_IDENTITY_FALLBACK_RANGE jpayne@69: } UNumberRangeIdentityFallback; jpayne@69: jpayne@69: /** jpayne@69: * Used in the result class FormattedNumberRange to indicate to the user whether the numbers formatted in the range jpayne@69: * were equal or not, and whether or not the identity fallback was applied. jpayne@69: * jpayne@69: * @stable ICU 63 jpayne@69: * @see NumberRangeFormatter jpayne@69: */ jpayne@69: typedef enum UNumberRangeIdentityResult { jpayne@69: /** jpayne@69: * Used to indicate that the two numbers in the range were equal, even before any rounding rules were applied. jpayne@69: * jpayne@69: * @stable ICU 63 jpayne@69: * @see NumberRangeFormatter jpayne@69: */ jpayne@69: UNUM_IDENTITY_RESULT_EQUAL_BEFORE_ROUNDING, jpayne@69: jpayne@69: /** jpayne@69: * Used to indicate that the two numbers in the range were equal, but only after rounding rules were applied. jpayne@69: * jpayne@69: * @stable ICU 63 jpayne@69: * @see NumberRangeFormatter jpayne@69: */ jpayne@69: UNUM_IDENTITY_RESULT_EQUAL_AFTER_ROUNDING, jpayne@69: jpayne@69: /** jpayne@69: * Used to indicate that the two numbers in the range were not equal, even after rounding rules were applied. jpayne@69: * jpayne@69: * @stable ICU 63 jpayne@69: * @see NumberRangeFormatter jpayne@69: */ jpayne@69: UNUM_IDENTITY_RESULT_NOT_EQUAL, jpayne@69: jpayne@69: #ifndef U_HIDE_INTERNAL_API jpayne@69: /** jpayne@69: * The number of entries in this enum. jpayne@69: * @internal jpayne@69: */ jpayne@69: UNUM_IDENTITY_RESULT_COUNT jpayne@69: #endif jpayne@69: jpayne@69: } UNumberRangeIdentityResult; jpayne@69: jpayne@69: U_NAMESPACE_BEGIN jpayne@69: jpayne@69: namespace number { // icu::number jpayne@69: jpayne@69: // Forward declarations: jpayne@69: class UnlocalizedNumberRangeFormatter; jpayne@69: class LocalizedNumberRangeFormatter; jpayne@69: class FormattedNumberRange; jpayne@69: jpayne@69: namespace impl { jpayne@69: jpayne@69: // Forward declarations: jpayne@69: struct RangeMacroProps; jpayne@69: class DecimalQuantity; jpayne@69: class UFormattedNumberRangeData; jpayne@69: class NumberRangeFormatterImpl; jpayne@69: jpayne@69: } // namespace impl jpayne@69: jpayne@69: /** jpayne@69: * \cond jpayne@69: * Export an explicit template instantiation. See datefmt.h jpayne@69: * (When building DLLs for Windows this is required.) jpayne@69: */ jpayne@69: #if U_PLATFORM == U_PF_WINDOWS && !defined(U_IN_DOXYGEN) jpayne@69: } // namespace icu::number jpayne@69: U_NAMESPACE_END jpayne@69: jpayne@69: template struct U_I18N_API std::atomic< U_NAMESPACE_QUALIFIER number::impl::NumberRangeFormatterImpl*>; jpayne@69: jpayne@69: U_NAMESPACE_BEGIN jpayne@69: namespace number { // icu::number jpayne@69: #endif jpayne@69: /** \endcond */ jpayne@69: jpayne@69: // Other helper classes would go here, but there are none. jpayne@69: jpayne@69: namespace impl { // icu::number::impl jpayne@69: jpayne@69: // Do not enclose entire MacroProps with #ifndef U_HIDE_INTERNAL_API, needed for a protected field jpayne@69: /** @internal */ jpayne@69: struct U_I18N_API RangeMacroProps : public UMemory { jpayne@69: /** @internal */ jpayne@69: UnlocalizedNumberFormatter formatter1; // = NumberFormatter::with(); jpayne@69: jpayne@69: /** @internal */ jpayne@69: UnlocalizedNumberFormatter formatter2; // = NumberFormatter::with(); jpayne@69: jpayne@69: /** @internal */ jpayne@69: bool singleFormatter = true; jpayne@69: jpayne@69: /** @internal */ jpayne@69: UNumberRangeCollapse collapse = UNUM_RANGE_COLLAPSE_AUTO; jpayne@69: jpayne@69: /** @internal */ jpayne@69: UNumberRangeIdentityFallback identityFallback = UNUM_IDENTITY_FALLBACK_APPROXIMATELY; jpayne@69: jpayne@69: /** @internal */ jpayne@69: Locale locale; jpayne@69: jpayne@69: // NOTE: Uses default copy and move constructors. jpayne@69: jpayne@69: /** jpayne@69: * Check all members for errors. jpayne@69: * @internal jpayne@69: */ jpayne@69: bool copyErrorTo(UErrorCode &status) const { jpayne@69: return formatter1.copyErrorTo(status) || formatter2.copyErrorTo(status); jpayne@69: } jpayne@69: }; jpayne@69: jpayne@69: } // namespace impl jpayne@69: jpayne@69: /** jpayne@69: * An abstract base class for specifying settings related to number formatting. This class is implemented by jpayne@69: * {@link UnlocalizedNumberRangeFormatter} and {@link LocalizedNumberRangeFormatter}. This class is not intended for jpayne@69: * public subclassing. jpayne@69: */ jpayne@69: template jpayne@69: class U_I18N_API NumberRangeFormatterSettings { jpayne@69: public: jpayne@69: /** jpayne@69: * Sets the NumberFormatter instance to use for the numbers in the range. The same formatter is applied to both jpayne@69: * sides of the range. jpayne@69: *

jpayne@69: * The NumberFormatter instances must not have a locale applied yet; the locale specified on the jpayne@69: * NumberRangeFormatter will be used. jpayne@69: * jpayne@69: * @param formatter jpayne@69: * The formatter to use for both numbers in the range. jpayne@69: * @return The fluent chain. jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: Derived numberFormatterBoth(const UnlocalizedNumberFormatter &formatter) const &; jpayne@69: jpayne@69: /** jpayne@69: * Overload of numberFormatterBoth() for use on an rvalue reference. jpayne@69: * jpayne@69: * @param formatter jpayne@69: * The formatter to use for both numbers in the range. jpayne@69: * @return The fluent chain. jpayne@69: * @see #numberFormatterBoth jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: Derived numberFormatterBoth(const UnlocalizedNumberFormatter &formatter) &&; jpayne@69: jpayne@69: /** jpayne@69: * Overload of numberFormatterBoth() for use on an rvalue reference. jpayne@69: * jpayne@69: * @param formatter jpayne@69: * The formatter to use for both numbers in the range. jpayne@69: * @return The fluent chain. jpayne@69: * @see #numberFormatterBoth jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: Derived numberFormatterBoth(UnlocalizedNumberFormatter &&formatter) const &; jpayne@69: jpayne@69: /** jpayne@69: * Overload of numberFormatterBoth() for use on an rvalue reference. jpayne@69: * jpayne@69: * @param formatter jpayne@69: * The formatter to use for both numbers in the range. jpayne@69: * @return The fluent chain. jpayne@69: * @see #numberFormatterBoth jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: Derived numberFormatterBoth(UnlocalizedNumberFormatter &&formatter) &&; jpayne@69: jpayne@69: /** jpayne@69: * Sets the NumberFormatter instance to use for the first number in the range. jpayne@69: *

jpayne@69: * The NumberFormatter instances must not have a locale applied yet; the locale specified on the jpayne@69: * NumberRangeFormatter will be used. jpayne@69: * jpayne@69: * @param formatterFirst jpayne@69: * The formatter to use for the first number in the range. jpayne@69: * @return The fluent chain. jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: Derived numberFormatterFirst(const UnlocalizedNumberFormatter &formatterFirst) const &; jpayne@69: jpayne@69: /** jpayne@69: * Overload of numberFormatterFirst() for use on an rvalue reference. jpayne@69: * jpayne@69: * @param formatterFirst jpayne@69: * The formatter to use for the first number in the range. jpayne@69: * @return The fluent chain. jpayne@69: * @see #numberFormatterFirst jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: Derived numberFormatterFirst(const UnlocalizedNumberFormatter &formatterFirst) &&; jpayne@69: jpayne@69: /** jpayne@69: * Overload of numberFormatterFirst() for use on an rvalue reference. jpayne@69: * jpayne@69: * @param formatterFirst jpayne@69: * The formatter to use for the first number in the range. jpayne@69: * @return The fluent chain. jpayne@69: * @see #numberFormatterFirst jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: Derived numberFormatterFirst(UnlocalizedNumberFormatter &&formatterFirst) const &; jpayne@69: jpayne@69: /** jpayne@69: * Overload of numberFormatterFirst() for use on an rvalue reference. jpayne@69: * jpayne@69: * @param formatterFirst jpayne@69: * The formatter to use for the first number in the range. jpayne@69: * @return The fluent chain. jpayne@69: * @see #numberFormatterFirst jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: Derived numberFormatterFirst(UnlocalizedNumberFormatter &&formatterFirst) &&; jpayne@69: jpayne@69: /** jpayne@69: * Sets the NumberFormatter instance to use for the second number in the range. jpayne@69: *

jpayne@69: * The NumberFormatter instances must not have a locale applied yet; the locale specified on the jpayne@69: * NumberRangeFormatter will be used. jpayne@69: * jpayne@69: * @param formatterSecond jpayne@69: * The formatter to use for the second number in the range. jpayne@69: * @return The fluent chain. jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: Derived numberFormatterSecond(const UnlocalizedNumberFormatter &formatterSecond) const &; jpayne@69: jpayne@69: /** jpayne@69: * Overload of numberFormatterSecond() for use on an rvalue reference. jpayne@69: * jpayne@69: * @param formatterSecond jpayne@69: * The formatter to use for the second number in the range. jpayne@69: * @return The fluent chain. jpayne@69: * @see #numberFormatterSecond jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: Derived numberFormatterSecond(const UnlocalizedNumberFormatter &formatterSecond) &&; jpayne@69: jpayne@69: /** jpayne@69: * Overload of numberFormatterSecond() for use on an rvalue reference. jpayne@69: * jpayne@69: * @param formatterSecond jpayne@69: * The formatter to use for the second number in the range. jpayne@69: * @return The fluent chain. jpayne@69: * @see #numberFormatterSecond jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: Derived numberFormatterSecond(UnlocalizedNumberFormatter &&formatterSecond) const &; jpayne@69: jpayne@69: /** jpayne@69: * Overload of numberFormatterSecond() for use on an rvalue reference. jpayne@69: * jpayne@69: * @param formatterSecond jpayne@69: * The formatter to use for the second number in the range. jpayne@69: * @return The fluent chain. jpayne@69: * @see #numberFormatterSecond jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: Derived numberFormatterSecond(UnlocalizedNumberFormatter &&formatterSecond) &&; jpayne@69: jpayne@69: /** jpayne@69: * Sets the aggressiveness of "collapsing" fields across the range separator. Possible values: jpayne@69: *

jpayne@69: *

jpayne@69: *

jpayne@69: * The default value is AUTO. jpayne@69: * jpayne@69: * @param collapse jpayne@69: * The collapsing strategy to use for this range. jpayne@69: * @return The fluent chain. jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: Derived collapse(UNumberRangeCollapse collapse) const &; jpayne@69: jpayne@69: /** jpayne@69: * Overload of collapse() for use on an rvalue reference. jpayne@69: * jpayne@69: * @param collapse jpayne@69: * The collapsing strategy to use for this range. jpayne@69: * @return The fluent chain. jpayne@69: * @see #collapse jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: Derived collapse(UNumberRangeCollapse collapse) &&; jpayne@69: jpayne@69: /** jpayne@69: * Sets the behavior when the two sides of the range are the same. This could happen if the same two numbers are jpayne@69: * passed to the formatRange function, or if different numbers are passed to the function but they become the same jpayne@69: * after rounding rules are applied. Possible values: jpayne@69: *

jpayne@69: *

jpayne@69: *

jpayne@69: * The default value is APPROXIMATELY. jpayne@69: * jpayne@69: * @param identityFallback jpayne@69: * The strategy to use when formatting two numbers that end up being the same. jpayne@69: * @return The fluent chain. jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: Derived identityFallback(UNumberRangeIdentityFallback identityFallback) const &; jpayne@69: jpayne@69: /** jpayne@69: * Overload of identityFallback() for use on an rvalue reference. jpayne@69: * jpayne@69: * @param identityFallback jpayne@69: * The strategy to use when formatting two numbers that end up being the same. jpayne@69: * @return The fluent chain. jpayne@69: * @see #identityFallback jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: Derived identityFallback(UNumberRangeIdentityFallback identityFallback) &&; jpayne@69: jpayne@69: /** jpayne@69: * Returns the current (Un)LocalizedNumberRangeFormatter as a LocalPointer jpayne@69: * wrapping a heap-allocated copy of the current object. jpayne@69: * jpayne@69: * This is equivalent to new-ing the move constructor with a value object jpayne@69: * as the argument. jpayne@69: * jpayne@69: * @return A wrapped (Un)LocalizedNumberRangeFormatter pointer, or a wrapped jpayne@69: * nullptr on failure. jpayne@69: * @stable ICU 64 jpayne@69: */ jpayne@69: LocalPointer clone() const &; jpayne@69: jpayne@69: /** jpayne@69: * Overload of clone for use on an rvalue reference. jpayne@69: * jpayne@69: * @return A wrapped (Un)LocalizedNumberRangeFormatter pointer, or a wrapped jpayne@69: * nullptr on failure. jpayne@69: * @stable ICU 64 jpayne@69: */ jpayne@69: LocalPointer clone() &&; jpayne@69: jpayne@69: /** jpayne@69: * Sets the UErrorCode if an error occurred in the fluent chain. jpayne@69: * Preserves older error codes in the outErrorCode. jpayne@69: * @return TRUE if U_FAILURE(outErrorCode) jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: UBool copyErrorTo(UErrorCode &outErrorCode) const { jpayne@69: if (U_FAILURE(outErrorCode)) { jpayne@69: // Do not overwrite the older error code jpayne@69: return TRUE; jpayne@69: } jpayne@69: fMacros.copyErrorTo(outErrorCode); jpayne@69: return U_FAILURE(outErrorCode); jpayne@69: } jpayne@69: jpayne@69: // NOTE: Uses default copy and move constructors. jpayne@69: jpayne@69: private: jpayne@69: impl::RangeMacroProps fMacros; jpayne@69: jpayne@69: // Don't construct me directly! Use (Un)LocalizedNumberFormatter. jpayne@69: NumberRangeFormatterSettings() = default; jpayne@69: jpayne@69: friend class LocalizedNumberRangeFormatter; jpayne@69: friend class UnlocalizedNumberRangeFormatter; jpayne@69: }; jpayne@69: jpayne@69: /** jpayne@69: * A NumberRangeFormatter that does not yet have a locale. In order to format, a locale must be specified. jpayne@69: * jpayne@69: * Instances of this class are immutable and thread-safe. jpayne@69: * jpayne@69: * @see NumberRangeFormatter jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: class U_I18N_API UnlocalizedNumberRangeFormatter jpayne@69: : public NumberRangeFormatterSettings, public UMemory { jpayne@69: jpayne@69: public: jpayne@69: /** jpayne@69: * Associate the given locale with the number range formatter. The locale is used for picking the jpayne@69: * appropriate symbols, formats, and other data for number display. jpayne@69: * jpayne@69: * @param locale jpayne@69: * The locale to use when loading data for number formatting. jpayne@69: * @return The fluent chain. jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: LocalizedNumberRangeFormatter locale(const icu::Locale &locale) const &; jpayne@69: jpayne@69: /** jpayne@69: * Overload of locale() for use on an rvalue reference. jpayne@69: * jpayne@69: * @param locale jpayne@69: * The locale to use when loading data for number formatting. jpayne@69: * @return The fluent chain. jpayne@69: * @see #locale jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: LocalizedNumberRangeFormatter locale(const icu::Locale &locale) &&; jpayne@69: jpayne@69: /** jpayne@69: * Default constructor: puts the formatter into a valid but undefined state. jpayne@69: * jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: UnlocalizedNumberRangeFormatter() = default; jpayne@69: jpayne@69: /** jpayne@69: * Returns a copy of this UnlocalizedNumberRangeFormatter. jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: UnlocalizedNumberRangeFormatter(const UnlocalizedNumberRangeFormatter &other); jpayne@69: jpayne@69: /** jpayne@69: * Move constructor: jpayne@69: * The source UnlocalizedNumberRangeFormatter will be left in a valid but undefined state. jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: UnlocalizedNumberRangeFormatter(UnlocalizedNumberRangeFormatter&& src) U_NOEXCEPT; jpayne@69: jpayne@69: /** jpayne@69: * Copy assignment operator. jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: UnlocalizedNumberRangeFormatter& operator=(const UnlocalizedNumberRangeFormatter& other); jpayne@69: jpayne@69: /** jpayne@69: * Move assignment operator: jpayne@69: * The source UnlocalizedNumberRangeFormatter will be left in a valid but undefined state. jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: UnlocalizedNumberRangeFormatter& operator=(UnlocalizedNumberRangeFormatter&& src) U_NOEXCEPT; jpayne@69: jpayne@69: private: jpayne@69: explicit UnlocalizedNumberRangeFormatter( jpayne@69: const NumberRangeFormatterSettings& other); jpayne@69: jpayne@69: explicit UnlocalizedNumberRangeFormatter( jpayne@69: NumberRangeFormatterSettings&& src) U_NOEXCEPT; jpayne@69: jpayne@69: // To give the fluent setters access to this class's constructor: jpayne@69: friend class NumberRangeFormatterSettings; jpayne@69: jpayne@69: // To give NumberRangeFormatter::with() access to this class's constructor: jpayne@69: friend class NumberRangeFormatter; jpayne@69: }; jpayne@69: jpayne@69: /** jpayne@69: * A NumberRangeFormatter that has a locale associated with it; this means .formatRange() methods are available. jpayne@69: * jpayne@69: * Instances of this class are immutable and thread-safe. jpayne@69: * jpayne@69: * @see NumberFormatter jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: class U_I18N_API LocalizedNumberRangeFormatter jpayne@69: : public NumberRangeFormatterSettings, public UMemory { jpayne@69: public: jpayne@69: /** jpayne@69: * Format the given Formattables to a string using the settings specified in the NumberRangeFormatter fluent setting jpayne@69: * chain. jpayne@69: * jpayne@69: * @param first jpayne@69: * The first number in the range, usually to the left in LTR locales. jpayne@69: * @param second jpayne@69: * The second number in the range, usually to the right in LTR locales. jpayne@69: * @param status jpayne@69: * Set if an error occurs while formatting. jpayne@69: * @return A FormattedNumberRange object; call .toString() to get the string. jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: FormattedNumberRange formatFormattableRange( jpayne@69: const Formattable& first, const Formattable& second, UErrorCode& status) const; jpayne@69: jpayne@69: /** jpayne@69: * Default constructor: puts the formatter into a valid but undefined state. jpayne@69: * jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: LocalizedNumberRangeFormatter() = default; jpayne@69: jpayne@69: /** jpayne@69: * Returns a copy of this LocalizedNumberRangeFormatter. jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: LocalizedNumberRangeFormatter(const LocalizedNumberRangeFormatter &other); jpayne@69: jpayne@69: /** jpayne@69: * Move constructor: jpayne@69: * The source LocalizedNumberRangeFormatter will be left in a valid but undefined state. jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: LocalizedNumberRangeFormatter(LocalizedNumberRangeFormatter&& src) U_NOEXCEPT; jpayne@69: jpayne@69: /** jpayne@69: * Copy assignment operator. jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: LocalizedNumberRangeFormatter& operator=(const LocalizedNumberRangeFormatter& other); jpayne@69: jpayne@69: /** jpayne@69: * Move assignment operator: jpayne@69: * The source LocalizedNumberRangeFormatter will be left in a valid but undefined state. jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: LocalizedNumberRangeFormatter& operator=(LocalizedNumberRangeFormatter&& src) U_NOEXCEPT; jpayne@69: jpayne@69: #ifndef U_HIDE_INTERNAL_API jpayne@69: jpayne@69: /** jpayne@69: * @param results jpayne@69: * The results object. This method will mutate it to save the results. jpayne@69: * @param equalBeforeRounding jpayne@69: * Whether the number was equal before copying it into a DecimalQuantity. jpayne@69: * Used for determining the identity fallback behavior. jpayne@69: * @param status jpayne@69: * Set if an error occurs while formatting. jpayne@69: * @internal jpayne@69: */ jpayne@69: void formatImpl(impl::UFormattedNumberRangeData& results, bool equalBeforeRounding, jpayne@69: UErrorCode& status) const; jpayne@69: jpayne@69: #endif /* U_HIDE_INTERNAL_API */ jpayne@69: jpayne@69: /** jpayne@69: * Destruct this LocalizedNumberRangeFormatter, cleaning up any memory it might own. jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: ~LocalizedNumberRangeFormatter(); jpayne@69: jpayne@69: private: jpayne@69: std::atomic fAtomicFormatter = {}; jpayne@69: jpayne@69: const impl::NumberRangeFormatterImpl* getFormatter(UErrorCode& stauts) const; jpayne@69: jpayne@69: explicit LocalizedNumberRangeFormatter( jpayne@69: const NumberRangeFormatterSettings& other); jpayne@69: jpayne@69: explicit LocalizedNumberRangeFormatter( jpayne@69: NumberRangeFormatterSettings&& src) U_NOEXCEPT; jpayne@69: jpayne@69: LocalizedNumberRangeFormatter(const impl::RangeMacroProps ¯os, const Locale &locale); jpayne@69: jpayne@69: LocalizedNumberRangeFormatter(impl::RangeMacroProps &¯os, const Locale &locale); jpayne@69: jpayne@69: void clear(); jpayne@69: jpayne@69: // To give the fluent setters access to this class's constructor: jpayne@69: friend class NumberRangeFormatterSettings; jpayne@69: friend class NumberRangeFormatterSettings; jpayne@69: jpayne@69: // To give UnlocalizedNumberRangeFormatter::locale() access to this class's constructor: jpayne@69: friend class UnlocalizedNumberRangeFormatter; jpayne@69: }; jpayne@69: jpayne@69: /** jpayne@69: * The result of a number range formatting operation. This class allows the result to be exported in several data types, jpayne@69: * including a UnicodeString and a FieldPositionIterator. jpayne@69: * jpayne@69: * Instances of this class are immutable and thread-safe. jpayne@69: * jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: class U_I18N_API FormattedNumberRange : public UMemory, public FormattedValue { jpayne@69: public: jpayne@69: // Copybrief: this method is older than the parent method jpayne@69: /** jpayne@69: * @copybrief FormattedValue::toString() jpayne@69: * jpayne@69: * For more information, see FormattedValue::toString() jpayne@69: * jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: UnicodeString toString(UErrorCode& status) const U_OVERRIDE; jpayne@69: jpayne@69: // Copydoc: this method is new in ICU 64 jpayne@69: /** @copydoc FormattedValue::toTempString() */ jpayne@69: UnicodeString toTempString(UErrorCode& status) const U_OVERRIDE; jpayne@69: jpayne@69: // Copybrief: this method is older than the parent method jpayne@69: /** jpayne@69: * @copybrief FormattedValue::appendTo() jpayne@69: * jpayne@69: * For more information, see FormattedValue::appendTo() jpayne@69: * jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: Appendable &appendTo(Appendable &appendable, UErrorCode& status) const U_OVERRIDE; jpayne@69: jpayne@69: // Copydoc: this method is new in ICU 64 jpayne@69: /** @copydoc FormattedValue::nextPosition() */ jpayne@69: UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const U_OVERRIDE; jpayne@69: jpayne@69: #ifndef U_HIDE_DRAFT_API jpayne@69: /** jpayne@69: * Export the first formatted number as a decimal number. This endpoint jpayne@69: * is useful for obtaining the exact number being printed after scaling jpayne@69: * and rounding have been applied by the number range formatting pipeline. jpayne@69: * jpayne@69: * The syntax of the unformatted number is a "numeric string" jpayne@69: * as defined in the Decimal Arithmetic Specification, available at jpayne@69: * http://speleotrove.com/decimal jpayne@69: * jpayne@69: * @return A decimal representation of the first formatted number. jpayne@69: * @draft ICU 63 jpayne@69: * @see NumberRangeFormatter jpayne@69: * @see #getSecondDecimal jpayne@69: */ jpayne@69: UnicodeString getFirstDecimal(UErrorCode& status) const; jpayne@69: jpayne@69: /** jpayne@69: * Export the second formatted number as a decimal number. This endpoint jpayne@69: * is useful for obtaining the exact number being printed after scaling jpayne@69: * and rounding have been applied by the number range formatting pipeline. jpayne@69: * jpayne@69: * The syntax of the unformatted number is a "numeric string" jpayne@69: * as defined in the Decimal Arithmetic Specification, available at jpayne@69: * http://speleotrove.com/decimal jpayne@69: * jpayne@69: * @return A decimal representation of the second formatted number. jpayne@69: * @draft ICU 63 jpayne@69: * @see NumberRangeFormatter jpayne@69: * @see #getFirstDecimal jpayne@69: */ jpayne@69: UnicodeString getSecondDecimal(UErrorCode& status) const; jpayne@69: #endif // U_HIDE_DRAFT_API jpayne@69: jpayne@69: /** jpayne@69: * Returns whether the pair of numbers was successfully formatted as a range or whether an identity fallback was jpayne@69: * used. For example, if the first and second number were the same either before or after rounding occurred, an jpayne@69: * identity fallback was used. jpayne@69: * jpayne@69: * @return An indication the resulting identity situation in the formatted number range. jpayne@69: * @stable ICU 63 jpayne@69: * @see UNumberRangeIdentityFallback jpayne@69: */ jpayne@69: UNumberRangeIdentityResult getIdentityResult(UErrorCode& status) const; jpayne@69: jpayne@69: /** jpayne@69: * Copying not supported; use move constructor instead. jpayne@69: */ jpayne@69: FormattedNumberRange(const FormattedNumberRange&) = delete; jpayne@69: jpayne@69: /** jpayne@69: * Copying not supported; use move assignment instead. jpayne@69: */ jpayne@69: FormattedNumberRange& operator=(const FormattedNumberRange&) = delete; jpayne@69: jpayne@69: /** jpayne@69: * Move constructor: jpayne@69: * Leaves the source FormattedNumberRange in an undefined state. jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: FormattedNumberRange(FormattedNumberRange&& src) U_NOEXCEPT; jpayne@69: jpayne@69: /** jpayne@69: * Move assignment: jpayne@69: * Leaves the source FormattedNumberRange in an undefined state. jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: FormattedNumberRange& operator=(FormattedNumberRange&& src) U_NOEXCEPT; jpayne@69: jpayne@69: /** jpayne@69: * Destruct an instance of FormattedNumberRange, cleaning up any memory it might own. jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: ~FormattedNumberRange(); jpayne@69: jpayne@69: private: jpayne@69: // Can't use LocalPointer because UFormattedNumberRangeData is forward-declared jpayne@69: const impl::UFormattedNumberRangeData *fData; jpayne@69: jpayne@69: // Error code for the terminal methods jpayne@69: UErrorCode fErrorCode; jpayne@69: jpayne@69: /** jpayne@69: * Internal constructor from data type. Adopts the data pointer. jpayne@69: */ jpayne@69: explicit FormattedNumberRange(impl::UFormattedNumberRangeData *results) jpayne@69: : fData(results), fErrorCode(U_ZERO_ERROR) {} jpayne@69: jpayne@69: explicit FormattedNumberRange(UErrorCode errorCode) jpayne@69: : fData(nullptr), fErrorCode(errorCode) {} jpayne@69: jpayne@69: void getAllFieldPositionsImpl(FieldPositionIteratorHandler& fpih, UErrorCode& status) const; jpayne@69: jpayne@69: // To give LocalizedNumberRangeFormatter format methods access to this class's constructor: jpayne@69: friend class LocalizedNumberRangeFormatter; jpayne@69: }; jpayne@69: jpayne@69: /** jpayne@69: * See the main description in numberrangeformatter.h for documentation and examples. jpayne@69: * jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: class U_I18N_API NumberRangeFormatter final { jpayne@69: public: jpayne@69: /** jpayne@69: * Call this method at the beginning of a NumberRangeFormatter fluent chain in which the locale is not currently jpayne@69: * known at the call site. jpayne@69: * jpayne@69: * @return An {@link UnlocalizedNumberRangeFormatter}, to be used for chaining. jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: static UnlocalizedNumberRangeFormatter with(); jpayne@69: jpayne@69: /** jpayne@69: * Call this method at the beginning of a NumberRangeFormatter fluent chain in which the locale is known at the call jpayne@69: * site. jpayne@69: * jpayne@69: * @param locale jpayne@69: * The locale from which to load formats and symbols for number range formatting. jpayne@69: * @return A {@link LocalizedNumberRangeFormatter}, to be used for chaining. jpayne@69: * @stable ICU 63 jpayne@69: */ jpayne@69: static LocalizedNumberRangeFormatter withLocale(const Locale &locale); jpayne@69: jpayne@69: /** jpayne@69: * Use factory methods instead of the constructor to create a NumberFormatter. jpayne@69: */ jpayne@69: NumberRangeFormatter() = delete; jpayne@69: }; jpayne@69: jpayne@69: } // namespace number jpayne@69: U_NAMESPACE_END jpayne@69: jpayne@69: #endif /* #if !UCONFIG_NO_FORMATTING */ jpayne@69: jpayne@69: #endif /* U_SHOW_CPLUSPLUS_API */ jpayne@69: jpayne@69: #endif // __NUMBERRANGEFORMATTER_H__ jpayne@69: