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

* Usage example: *

*

* NumberRangeFormatter::with()
*     .identityFallback(UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE)
*     .locale("en-GB")
*     .formatRange(750, 1.2, status)
*     .toString(status);
* // => "750 m - 1.2 km"
*
*

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

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

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

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

*

*
• ALL: "3-5K miles"
• *
• UNIT: "3K - 5K miles"
• *
• NONE: "3K miles - 5K miles"
• *
• AUTO: usually UNIT or NONE, depending on the locale and formatter settings
• *
*

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

*

*
• SINGLE_VALUE: "5 miles"
• *
• APPROXIMATELY_OR_SINGLE_VALUE: "~5 miles" or "5 miles", depending on whether the number was the same before * rounding was applied
• *
• APPROXIMATELY: "~5 miles"
• *
• RANGE: "5-5 miles" (with collapse=UNIT)
• *
*