diff --git a/icu4c/source/i18n/Makefile.in b/icu4c/source/i18n/Makefile.in index 0e11817b1a..95ec314cdf 100644 --- a/icu4c/source/i18n/Makefile.in +++ b/icu4c/source/i18n/Makefile.in @@ -108,7 +108,7 @@ double-conversion-cached-powers.o double-conversion-diy-fp.o double-conversion-f numparse_stringsegment.o numparse_unisets.o numparse_parsednumber.o \ numparse_impl.o numparse_symbols.o numparse_decimal.o numparse_scientific.o \ numparse_currency.o numparse_affixes.o numparse_compositions.o numparse_validators.o \ -number_mapper.o number_multiplier.o number_currencysymbols.o number_skeletons.o +number_mapper.o number_multiplier.o number_currencysymbols.o number_skeletons.o number_capi.o \ ## Header files to install diff --git a/icu4c/source/i18n/number_capi.cpp b/icu4c/source/i18n/number_capi.cpp new file mode 100644 index 0000000000..bb2d47b48f --- /dev/null +++ b/icu4c/source/i18n/number_capi.cpp @@ -0,0 +1,197 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT + +// Allow implicit conversion from char16_t* to UnicodeString for this file: +// Helpful in toString methods and elsewhere. +#define UNISTR_FROM_STRING_EXPLICIT + +#include "numparse_types.h" +#include "number_utypes.h" +#include "unicode/numberformatter.h" +#include "unicode/unumberformatter.h" + +using namespace icu; +using namespace icu::number; +using namespace icu::number::impl; + + +////////////////////////////////// +/// C API CONVERSION FUNCTIONS /// +////////////////////////////////// + +UNumberFormatterData* UNumberFormatterData::validate(UNumberFormatter* input, UErrorCode& status) { + auto* constInput = static_cast(input); + auto* validated = validate(constInput, status); + return const_cast(validated); +} + +const UNumberFormatterData* +UNumberFormatterData::validate(const UNumberFormatter* input, UErrorCode& status) { + if (U_FAILURE(status)) { + return nullptr; + } + if (input == nullptr) { + status = U_ILLEGAL_ARGUMENT_ERROR; + return nullptr; + } + auto* impl = reinterpret_cast(input); + if (impl->fMagic != UNumberFormatterData::kMagic) { + status = U_INVALID_FORMAT_ERROR; + return nullptr; + } + return impl; +} + +UNumberFormatter* UNumberFormatterData::exportForC() { + return reinterpret_cast(this); +} + +UFormattedNumberData* UFormattedNumberData::validate(UFormattedNumber* input, UErrorCode& status) { + auto* constInput = static_cast(input); + auto* validated = validate(constInput, status); + return const_cast(validated); +} + +const UFormattedNumberData* +UFormattedNumberData::validate(const UFormattedNumber* input, UErrorCode& status) { + if (U_FAILURE(status)) { + return nullptr; + } + if (input == nullptr) { + status = U_ILLEGAL_ARGUMENT_ERROR; + return nullptr; + } + auto* impl = reinterpret_cast(input); + if (impl->fMagic != UFormattedNumberData::kMagic) { + status = U_INVALID_FORMAT_ERROR; + return nullptr; + } + return impl; +} + +UFormattedNumber* UFormattedNumberData::exportForC() { + return reinterpret_cast(this); +} + +///////////////////////////////////// +/// END CAPI CONVERSION FUNCTIONS /// +///////////////////////////////////// + + +U_CAPI UNumberFormatter* U_EXPORT2 +unumf_openFromSkeletonAndLocale(const UChar* skeleton, int32_t skeletonLen, const char* locale, + UErrorCode* ec) { + auto* impl = new UNumberFormatterData(); + if (impl == nullptr) { + *ec = U_MEMORY_ALLOCATION_ERROR; + return nullptr; + } + // Readonly-alias constructor (first argument is whether we are NUL-terminated) + UnicodeString skeletonString(skeletonLen == -1, skeleton, skeletonLen); + impl->fFormatter = NumberFormatter::fromSkeleton(skeletonString, *ec).locale(locale); + return impl->exportForC(); +} + +U_CAPI UFormattedNumber* U_EXPORT2 +unumf_openResult(UErrorCode* ec) { + auto* impl = new UFormattedNumberData(); + if (impl == nullptr) { + *ec = U_MEMORY_ALLOCATION_ERROR; + return nullptr; + } + return impl->exportForC(); +} + +U_CAPI void U_EXPORT2 +unumf_formatInt(const UNumberFormatter* uformatter, int64_t value, UFormattedNumber* uresult, + UErrorCode* ec) { + const UNumberFormatterData* formatter = UNumberFormatterData::validate(uformatter, *ec); + UFormattedNumberData* result = UFormattedNumberData::validate(uresult, *ec); + if (U_FAILURE(*ec)) { return; } + + result->string.clear(); + result->quantity.setToLong(value); + formatter->fFormatter.formatImpl(result, *ec); +} + +U_CAPI void U_EXPORT2 +unumf_formatDouble(const UNumberFormatter* uformatter, double value, UFormattedNumber* uresult, + UErrorCode* ec) { + const UNumberFormatterData* formatter = UNumberFormatterData::validate(uformatter, *ec); + UFormattedNumberData* result = UFormattedNumberData::validate(uresult, *ec); + if (U_FAILURE(*ec)) { return; } + + result->string.clear(); + result->quantity.setToDouble(value); + formatter->fFormatter.formatImpl(result, *ec); +} + +U_CAPI void U_EXPORT2 +unumf_formatDecimal(const UNumberFormatter* uformatter, const char* value, int32_t valueLen, + UFormattedNumber* uresult, UErrorCode* ec) { + const UNumberFormatterData* formatter = UNumberFormatterData::validate(uformatter, *ec); + UFormattedNumberData* result = UFormattedNumberData::validate(uresult, *ec); + if (U_FAILURE(*ec)) { return; } + + result->string.clear(); + result->quantity.setToDecNumber({value, valueLen}, *ec); + if (U_FAILURE(*ec)) { return; } + formatter->fFormatter.formatImpl(result, *ec); +} + +U_CAPI int32_t U_EXPORT2 +unumf_resultToString(const UFormattedNumber* uresult, UChar* buffer, int32_t bufferCapacity, + UErrorCode* ec) { + const UFormattedNumberData* result = UFormattedNumberData::validate(uresult, *ec); + if (U_FAILURE(*ec)) { return 0; } + + return result->string.toUnicodeString().extract(buffer, bufferCapacity, *ec); +} + +U_CAPI void U_EXPORT2 +unumf_closeResult(const UFormattedNumber* uresult, UErrorCode* ec) { + const UFormattedNumberData* impl = UFormattedNumberData::validate(uresult, *ec); + if (U_FAILURE(*ec)) { return; } + delete impl; +} + +U_CAPI void U_EXPORT2 +unumf_close(UNumberFormatter* f, UErrorCode* ec) { + const UNumberFormatterData* impl = UNumberFormatterData::validate(f, *ec); + if (U_FAILURE(*ec)) { return; } + delete impl; +} + + +#endif /* #if !UCONFIG_NO_FORMATTING */ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/icu4c/source/i18n/number_fluent.cpp b/icu4c/source/i18n/number_fluent.cpp index e0ba258e3c..c5feb5e438 100644 --- a/icu4c/source/i18n/number_fluent.cpp +++ b/icu4c/source/i18n/number_fluent.cpp @@ -12,13 +12,14 @@ #include "number_formatimpl.h" #include "umutex.h" #include "number_skeletons.h" +#include "number_utypes.h" using namespace icu; using namespace icu::number; using namespace icu::number::impl; template -Derived NumberFormatterSettings::notation(const Notation& notation) const & { +Derived NumberFormatterSettings::notation(const Notation& notation) const& { Derived copy(*this); // NOTE: Slicing is OK. copy.fMacros.notation = notation; @@ -26,7 +27,7 @@ Derived NumberFormatterSettings::notation(const Notation& notation) con } template -Derived NumberFormatterSettings::notation(const Notation& notation) && { +Derived NumberFormatterSettings::notation(const Notation& notation)&& { Derived move(std::move(*this)); // NOTE: Slicing is OK. move.fMacros.notation = notation; @@ -34,7 +35,7 @@ Derived NumberFormatterSettings::notation(const Notation& notation) && } template -Derived NumberFormatterSettings::unit(const icu::MeasureUnit& unit) const & { +Derived NumberFormatterSettings::unit(const icu::MeasureUnit& unit) const& { Derived copy(*this); // NOTE: Slicing occurs here. However, CurrencyUnit can be restored from MeasureUnit. // TimeUnit may be affected, but TimeUnit is not as relevant to number formatting. @@ -43,7 +44,7 @@ Derived NumberFormatterSettings::unit(const icu::MeasureUnit& unit) con } template -Derived NumberFormatterSettings::unit(const icu::MeasureUnit& unit) && { +Derived NumberFormatterSettings::unit(const icu::MeasureUnit& unit)&& { Derived move(std::move(*this)); // See comments above about slicing. move.fMacros.unit = unit; @@ -51,7 +52,7 @@ Derived NumberFormatterSettings::unit(const icu::MeasureUnit& unit) && } template -Derived NumberFormatterSettings::adoptUnit(icu::MeasureUnit* unit) const & { +Derived NumberFormatterSettings::adoptUnit(icu::MeasureUnit* unit) const& { Derived copy(*this); // Just move the unit into the MacroProps by value, and delete it since we have ownership. // NOTE: Slicing occurs here. However, CurrencyUnit can be restored from MeasureUnit. @@ -65,7 +66,7 @@ Derived NumberFormatterSettings::adoptUnit(icu::MeasureUnit* unit) cons } template -Derived NumberFormatterSettings::adoptUnit(icu::MeasureUnit* unit) && { +Derived NumberFormatterSettings::adoptUnit(icu::MeasureUnit* unit)&& { Derived move(std::move(*this)); // See comments above about slicing and ownership. if (unit != nullptr) { @@ -77,7 +78,7 @@ Derived NumberFormatterSettings::adoptUnit(icu::MeasureUnit* unit) && { } template -Derived NumberFormatterSettings::perUnit(const icu::MeasureUnit& perUnit) const & { +Derived NumberFormatterSettings::perUnit(const icu::MeasureUnit& perUnit) const& { Derived copy(*this); // See comments above about slicing. copy.fMacros.perUnit = perUnit; @@ -85,7 +86,7 @@ Derived NumberFormatterSettings::perUnit(const icu::MeasureUnit& perUni } template -Derived NumberFormatterSettings::perUnit(const icu::MeasureUnit& perUnit) && { +Derived NumberFormatterSettings::perUnit(const icu::MeasureUnit& perUnit)&& { Derived copy(*this); // See comments above about slicing. copy.fMacros.perUnit = perUnit; @@ -93,7 +94,7 @@ Derived NumberFormatterSettings::perUnit(const icu::MeasureUnit& perUni } template -Derived NumberFormatterSettings::adoptPerUnit(icu::MeasureUnit* perUnit) const & { +Derived NumberFormatterSettings::adoptPerUnit(icu::MeasureUnit* perUnit) const& { Derived move(std::move(*this)); // See comments above about slicing and ownership. if (perUnit != nullptr) { @@ -105,7 +106,7 @@ Derived NumberFormatterSettings::adoptPerUnit(icu::MeasureUnit* perUnit } template -Derived NumberFormatterSettings::adoptPerUnit(icu::MeasureUnit* perUnit) && { +Derived NumberFormatterSettings::adoptPerUnit(icu::MeasureUnit* perUnit)&& { Derived copy(*this); // See comments above about slicing and ownership. if (perUnit != nullptr) { @@ -117,7 +118,7 @@ Derived NumberFormatterSettings::adoptPerUnit(icu::MeasureUnit* perUnit } template -Derived NumberFormatterSettings::rounding(const Rounder& rounder) const & { +Derived NumberFormatterSettings::rounding(const Rounder& rounder) const& { Derived copy(*this); // NOTE: Slicing is OK. copy.fMacros.rounder = rounder; @@ -125,7 +126,7 @@ Derived NumberFormatterSettings::rounding(const Rounder& rounder) const } template -Derived NumberFormatterSettings::rounding(const Rounder& rounder) && { +Derived NumberFormatterSettings::rounding(const Rounder& rounder)&& { Derived move(std::move(*this)); // NOTE: Slicing is OK. move.fMacros.rounder = rounder; @@ -133,7 +134,7 @@ Derived NumberFormatterSettings::rounding(const Rounder& rounder) && { } template -Derived NumberFormatterSettings::grouping(const UGroupingStrategy& strategy) const & { +Derived NumberFormatterSettings::grouping(const UGroupingStrategy& strategy) const& { Derived copy(*this); // NOTE: This is slightly different than how the setting is stored in Java // because we want to put it on the stack. @@ -142,147 +143,147 @@ Derived NumberFormatterSettings::grouping(const UGroupingStrategy& stra } template -Derived NumberFormatterSettings::grouping(const UGroupingStrategy& strategy) && { +Derived NumberFormatterSettings::grouping(const UGroupingStrategy& strategy)&& { Derived move(std::move(*this)); move.fMacros.grouper = Grouper::forStrategy(strategy); return move; } template -Derived NumberFormatterSettings::integerWidth(const IntegerWidth& style) const & { +Derived NumberFormatterSettings::integerWidth(const IntegerWidth& style) const& { Derived copy(*this); copy.fMacros.integerWidth = style; return copy; } template -Derived NumberFormatterSettings::integerWidth(const IntegerWidth& style) && { +Derived NumberFormatterSettings::integerWidth(const IntegerWidth& style)&& { Derived move(std::move(*this)); move.fMacros.integerWidth = style; return move; } template -Derived NumberFormatterSettings::symbols(const DecimalFormatSymbols& symbols) const & { +Derived NumberFormatterSettings::symbols(const DecimalFormatSymbols& symbols) const& { Derived copy(*this); copy.fMacros.symbols.setTo(symbols); return copy; } template -Derived NumberFormatterSettings::symbols(const DecimalFormatSymbols& symbols) && { +Derived NumberFormatterSettings::symbols(const DecimalFormatSymbols& symbols)&& { Derived move(std::move(*this)); move.fMacros.symbols.setTo(symbols); return move; } template -Derived NumberFormatterSettings::adoptSymbols(NumberingSystem* ns) const & { +Derived NumberFormatterSettings::adoptSymbols(NumberingSystem* ns) const& { Derived copy(*this); copy.fMacros.symbols.setTo(ns); return copy; } template -Derived NumberFormatterSettings::adoptSymbols(NumberingSystem* ns) && { +Derived NumberFormatterSettings::adoptSymbols(NumberingSystem* ns)&& { Derived move(std::move(*this)); move.fMacros.symbols.setTo(ns); return move; } template -Derived NumberFormatterSettings::unitWidth(const UNumberUnitWidth& width) const & { +Derived NumberFormatterSettings::unitWidth(const UNumberUnitWidth& width) const& { Derived copy(*this); copy.fMacros.unitWidth = width; return copy; } template -Derived NumberFormatterSettings::unitWidth(const UNumberUnitWidth& width) && { +Derived NumberFormatterSettings::unitWidth(const UNumberUnitWidth& width)&& { Derived move(std::move(*this)); move.fMacros.unitWidth = width; return move; } template -Derived NumberFormatterSettings::sign(const UNumberSignDisplay& style) const & { +Derived NumberFormatterSettings::sign(const UNumberSignDisplay& style) const& { Derived copy(*this); copy.fMacros.sign = style; return copy; } template -Derived NumberFormatterSettings::sign(const UNumberSignDisplay& style) && { +Derived NumberFormatterSettings::sign(const UNumberSignDisplay& style)&& { Derived move(std::move(*this)); move.fMacros.sign = style; return move; } template -Derived NumberFormatterSettings::decimal(const UNumberDecimalSeparatorDisplay& style) const & { +Derived NumberFormatterSettings::decimal(const UNumberDecimalSeparatorDisplay& style) const& { Derived copy(*this); copy.fMacros.decimal = style; return copy; } template -Derived NumberFormatterSettings::decimal(const UNumberDecimalSeparatorDisplay& style) && { +Derived NumberFormatterSettings::decimal(const UNumberDecimalSeparatorDisplay& style)&& { Derived move(std::move(*this)); move.fMacros.decimal = style; return move; } template -Derived NumberFormatterSettings::padding(const Padder& padder) const & { +Derived NumberFormatterSettings::padding(const Padder& padder) const& { Derived copy(*this); copy.fMacros.padder = padder; return copy; } template -Derived NumberFormatterSettings::padding(const Padder& padder) && { +Derived NumberFormatterSettings::padding(const Padder& padder)&& { Derived move(std::move(*this)); move.fMacros.padder = padder; return move; } template -Derived NumberFormatterSettings::threshold(int32_t threshold) const & { +Derived NumberFormatterSettings::threshold(int32_t threshold) const& { Derived copy(*this); copy.fMacros.threshold = threshold; return copy; } template -Derived NumberFormatterSettings::threshold(int32_t threshold) && { +Derived NumberFormatterSettings::threshold(int32_t threshold)&& { Derived move(std::move(*this)); move.fMacros.threshold = threshold; return move; } template -Derived NumberFormatterSettings::macros(const impl::MacroProps& macros) const & { +Derived NumberFormatterSettings::macros(const impl::MacroProps& macros) const& { Derived copy(*this); copy.fMacros = macros; return copy; } template -Derived NumberFormatterSettings::macros(const impl::MacroProps& macros) && { +Derived NumberFormatterSettings::macros(const impl::MacroProps& macros)&& { Derived move(std::move(*this)); move.fMacros = macros; return move; } template -Derived NumberFormatterSettings::macros(impl::MacroProps&& macros) const & { +Derived NumberFormatterSettings::macros(impl::MacroProps&& macros) const& { Derived copy(*this); copy.fMacros = std::move(macros); return copy; } template -Derived NumberFormatterSettings::macros(impl::MacroProps&& macros) && { +Derived NumberFormatterSettings::macros(impl::MacroProps&& macros)&& { Derived move(std::move(*this)); move.fMacros = std::move(macros); return move; @@ -316,8 +317,7 @@ NumberFormatter::fromSkeleton(const UnicodeString& skeleton, UErrorCode& status) } -template -using NFS = NumberFormatterSettings; +template using NFS = NumberFormatterSettings; using LNF = LocalizedNumberFormatter; using UNF = UnlocalizedNumberFormatter; @@ -403,11 +403,11 @@ LocalizedNumberFormatter::LocalizedNumberFormatter(MacroProps&& macros, const Lo fMacros.locale = locale; } -LocalizedNumberFormatter UnlocalizedNumberFormatter::locale(const Locale& locale) const & { +LocalizedNumberFormatter UnlocalizedNumberFormatter::locale(const Locale& locale) const& { return LocalizedNumberFormatter(fMacros, locale); } -LocalizedNumberFormatter UnlocalizedNumberFormatter::locale(const Locale& locale) && { +LocalizedNumberFormatter UnlocalizedNumberFormatter::locale(const Locale& locale)&& { return LocalizedNumberFormatter(std::move(fMacros), locale); } @@ -547,51 +547,82 @@ FormattedNumber& FormattedNumber::operator=(FormattedNumber&& src) U_NOEXCEPT { FormattedNumber LocalizedNumberFormatter::formatInt(int64_t value, UErrorCode& status) const { if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); } - auto results = new NumberFormatterResults(); + auto results = new UFormattedNumberData(); if (results == nullptr) { status = U_MEMORY_ALLOCATION_ERROR; return FormattedNumber(status); } results->quantity.setToLong(value); - return formatImpl(results, status); + formatImpl(results, status); + + // Do not save the results object if we encountered a failure. + if (U_SUCCESS(status)) { + return FormattedNumber(results); + } else { + delete results; + return FormattedNumber(status); + } } FormattedNumber LocalizedNumberFormatter::formatDouble(double value, UErrorCode& status) const { if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); } - auto results = new NumberFormatterResults(); + auto results = new UFormattedNumberData(); if (results == nullptr) { status = U_MEMORY_ALLOCATION_ERROR; return FormattedNumber(status); } results->quantity.setToDouble(value); - return formatImpl(results, status); + formatImpl(results, status); + + // Do not save the results object if we encountered a failure. + if (U_SUCCESS(status)) { + return FormattedNumber(results); + } else { + delete results; + return FormattedNumber(status); + } } FormattedNumber LocalizedNumberFormatter::formatDecimal(StringPiece value, UErrorCode& status) const { if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); } - auto results = new NumberFormatterResults(); + auto results = new UFormattedNumberData(); if (results == nullptr) { status = U_MEMORY_ALLOCATION_ERROR; return FormattedNumber(status); } results->quantity.setToDecNumber(value, status); - return formatImpl(results, status); + formatImpl(results, status); + + // Do not save the results object if we encountered a failure. + if (U_SUCCESS(status)) { + return FormattedNumber(results); + } else { + delete results; + return FormattedNumber(status); + } } FormattedNumber LocalizedNumberFormatter::formatDecimalQuantity(const DecimalQuantity& dq, UErrorCode& status) const { if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); } - auto results = new NumberFormatterResults(); + auto results = new UFormattedNumberData(); if (results == nullptr) { status = U_MEMORY_ALLOCATION_ERROR; return FormattedNumber(status); } results->quantity = dq; - return formatImpl(results, status); + formatImpl(results, status); + + // Do not save the results object if we encountered a failure. + if (U_SUCCESS(status)) { + return FormattedNumber(results); + } else { + delete results; + return FormattedNumber(status); + } } -FormattedNumber -LocalizedNumberFormatter::formatImpl(impl::NumberFormatterResults* results, UErrorCode& status) const { +void LocalizedNumberFormatter::formatImpl(impl::UFormattedNumberData* results, UErrorCode& status) const { // fUnsafeCallCount contains memory to be interpreted as an atomic int, most commonly // std::atomic. Since the type of atomic int is platform-dependent, we cast the // bytes in fUnsafeCallCount to u_atomic_int32_t, a typedef for the platform-dependent @@ -627,14 +658,6 @@ LocalizedNumberFormatter::formatImpl(impl::NumberFormatterResults* results, UErr // Format the number without building the data structure (slow path). NumberFormatterImpl::applyStatic(fMacros, results->quantity, results->string, status); } - - // Do not save the results object if we encountered a failure. - if (U_SUCCESS(status)) { - return FormattedNumber(results); - } else { - delete results; - return FormattedNumber(status); - } } const impl::NumberFormatterImpl* LocalizedNumberFormatter::getCompiled() const { diff --git a/icu4c/source/i18n/number_stringbuilder.cpp b/icu4c/source/i18n/number_stringbuilder.cpp index 37159d7e53..2759ed4568 100644 --- a/icu4c/source/i18n/number_stringbuilder.cpp +++ b/icu4c/source/i18n/number_stringbuilder.cpp @@ -334,7 +334,8 @@ int32_t NumberStringBuilder::remove(int32_t index, int32_t count) { } UnicodeString NumberStringBuilder::toUnicodeString() const { - return UnicodeString(getCharPtr() + fZero, fLength); + // Readonly-alias constructor: + return UnicodeString(FALSE, getCharPtr() + fZero, fLength); } UnicodeString NumberStringBuilder::toDebugString() const { diff --git a/icu4c/source/i18n/number_utils.h b/icu4c/source/i18n/number_utils.h index 6ca205dc2b..60879db085 100644 --- a/icu4c/source/i18n/number_utils.h +++ b/icu4c/source/i18n/number_utils.h @@ -102,17 +102,6 @@ struct MicroProps : public MicroPropsGenerator { bool exhausted = false; }; -/** - * This struct provides the result of the number formatting pipeline to FormattedNumber. - * - * The DecimalQuantity is not currently being used by FormattedNumber, but at some point it could be used - * to add a toDecNumber() or similar method. - */ -struct NumberFormatterResults : public UMemory { - DecimalQuantity quantity; - NumberStringBuilder string; -}; - inline int32_t insertDigitFromSymbols(NumberStringBuilder& output, int32_t index, int8_t digit, const DecimalFormatSymbols& symbols, Field field, UErrorCode& status) { diff --git a/icu4c/source/i18n/number_utypes.h b/icu4c/source/i18n/number_utypes.h new file mode 100644 index 0000000000..bff097eff1 --- /dev/null +++ b/icu4c/source/i18n/number_utypes.h @@ -0,0 +1,79 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#ifndef __SOURCE_NUMBER_UTYPES_H__ +#define __SOURCE_NUMBER_UTYPES_H__ + +#include "unicode/numberformatter.h" +#include "number_types.h" +#include "number_decimalquantity.h" +#include "number_stringbuilder.h" + +U_NAMESPACE_BEGIN namespace number { +namespace impl { + + +/** + * Implementation class for UNumberFormatter with a magic number for safety. + * + * Wraps a LocalizedNumberFormatter by value. + */ +struct UNumberFormatterData : public UMemory { + // The magic number to identify incoming objects. + // Reads in ASCII as "NFR" (NumberFormatteR with room at the end) + static constexpr int32_t kMagic = 0x4E465200; + + // Data members: + int32_t fMagic = kMagic; + LocalizedNumberFormatter fFormatter; + + /** Convert from UNumberFormatter -> UNumberFormatterData. */ + static UNumberFormatterData* validate(UNumberFormatter* input, UErrorCode& status); + + /** Convert from UNumberFormatter -> UNumberFormatterData (const version). */ + static const UNumberFormatterData* validate(const UNumberFormatter* input, UErrorCode& status); + + /** Convert from UNumberFormatterData -> UNumberFormatter. */ + UNumberFormatter* exportForC(); +}; + + +/** + * Implementation class for UFormattedNumber with magic number for safety. + * + * This struct is also held internally by the C++ version FormattedNumber since the member types are not + * declared in the public header file. + * + * The DecimalQuantity is not currently being used by FormattedNumber, but at some point it could be used + * to add a toDecNumber() or similar method. + */ +struct UFormattedNumberData : public UMemory { + // The magic number to identify incoming objects. + // Reads in ASCII as "FDN" (FormatteDNumber with room at the end) + static constexpr int32_t kMagic = 0x46444E00; + + // Data members: + int32_t fMagic = kMagic; + DecimalQuantity quantity; + NumberStringBuilder string; + + /** Convert from UFormattedNumber -> UFormattedNumberData. */ + static UFormattedNumberData* validate(UFormattedNumber* input, UErrorCode& status); + + /** Convert from UFormattedNumber -> UFormattedNumberData (const version). */ + static const UFormattedNumberData* validate(const UFormattedNumber* input, UErrorCode& status); + + /** Convert from UFormattedNumberData -> UFormattedNumber. */ + UFormattedNumber* exportForC(); +}; + + +} // namespace impl +} // namespace number +U_NAMESPACE_END + +#endif //__SOURCE_NUMBER_UTYPES_H__ +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/icu4c/source/i18n/unicode/numberformatter.h b/icu4c/source/i18n/unicode/numberformatter.h index c0131eaa71..f1bb5316f1 100644 --- a/icu4c/source/i18n/unicode/numberformatter.h +++ b/icu4c/source/i18n/unicode/numberformatter.h @@ -13,6 +13,7 @@ #include "unicode/fieldpos.h" #include "unicode/fpositer.h" #include "unicode/measunit.h" +#include "unicode/unumberformatter.h" #include "unicode/nounit.h" #include "unicode/plurrule.h" #include "unicode/ucurr.h" @@ -75,319 +76,6 @@ * @author Shane Carr */ -/** - * An enum declaring how to render units, including currencies. Example outputs when formatting 123 USD and 123 - * meters in en-CA: - * - *

- *

    - *
  • NARROW*: "$123.00" and "123 m" - *
  • SHORT: "US$ 123.00" and "123 m" - *
  • FULL_NAME: "123.00 US dollars" and "123 meters" - *
  • ISO_CODE: "USD 123.00" and undefined behavior - *
  • HIDDEN: "123.00" and "123" - *
- * - *

- * This enum is similar to {@link com.ibm.icu.text.MeasureFormat.FormatWidth}. - * - * @draft ICU 60 - */ -typedef enum UNumberUnitWidth { - /** - * Print an abbreviated version of the unit name. Similar to SHORT, but always use the shortest available - * abbreviation or symbol. This option can be used when the context hints at the identity of the unit. For more - * information on the difference between NARROW and SHORT, see SHORT. - * - *

- * In CLDR, this option corresponds to the "Narrow" format for measure units and the "¤¤¤¤¤" placeholder for - * currencies. - * - * @draft ICU 60 - */ - UNUM_UNIT_WIDTH_NARROW, - - /** - * Print an abbreviated version of the unit name. Similar to NARROW, but use a slightly wider abbreviation or - * symbol when there may be ambiguity. This is the default behavior. - * - *

- * For example, in es-US, the SHORT form for Fahrenheit is "{0} °F", but the NARROW form is "{0}°", - * since Fahrenheit is the customary unit for temperature in that locale. - * - *

- * In CLDR, this option corresponds to the "Short" format for measure units and the "¤" placeholder for - * currencies. - * - * @draft ICU 60 - */ - UNUM_UNIT_WIDTH_SHORT, - - /** - * Print the full name of the unit, without any abbreviations. - * - *

- * In CLDR, this option corresponds to the default format for measure units and the "¤¤¤" placeholder for - * currencies. - * - * @draft ICU 60 - */ - UNUM_UNIT_WIDTH_FULL_NAME, - - /** - * Use the three-digit ISO XXX code in place of the symbol for displaying currencies. The behavior of this - * option is currently undefined for use with measure units. - * - *

- * In CLDR, this option corresponds to the "¤¤" placeholder for currencies. - * - * @draft ICU 60 - */ - UNUM_UNIT_WIDTH_ISO_CODE, - - /** - * Format the number according to the specified unit, but do not display the unit. For currencies, apply - * monetary symbols and formats as with SHORT, but omit the currency symbol. For measure units, the behavior is - * equivalent to not specifying the unit at all. - * - * @draft ICU 60 - */ - UNUM_UNIT_WIDTH_HIDDEN, - - /** - * One more than the highest UNumberUnitWidth value. - * - * @internal ICU 60: The numeric value may change over time; see ICU ticket #12420. - */ - UNUM_UNIT_WIDTH_COUNT -} UNumberUnitWidth; - -/** - * An enum declaring the strategy for when and how to display grouping separators (i.e., the - * separator, often a comma or period, after every 2-3 powers of ten). The choices are several - * pre-built strategies for different use cases that employ locale data whenever possible. Example - * outputs for 1234 and 1234567 in en-IN: - * - *

    - *
  • OFF: 1234 and 12345 - *
  • MIN2: 1234 and 12,34,567 - *
  • AUTO: 1,234 and 12,34,567 - *
  • ON_ALIGNED: 1,234 and 12,34,567 - *
  • THOUSANDS: 1,234 and 1,234,567 - *
- * - *

- * The default is AUTO, which displays grouping separators unless the locale data says that grouping - * is not customary. To force grouping for all numbers greater than 1000 consistently across locales, - * use ON_ALIGNED. On the other hand, to display grouping less frequently than the default, use MIN2 - * or OFF. See the docs of each option for details. - * - *

- * Note: This enum specifies the strategy for grouping sizes. To set which character to use as the - * grouping separator, use the "symbols" setter. - * - * @draft ICU 61 -- TODO: This should be renamed to UNumberGroupingStrategy before promoting to stable, - * for consistency with the other enums. - */ -typedef enum UGroupingStrategy { - /** - * Do not display grouping separators in any locale. - * - * @draft ICU 61 - */ - UNUM_GROUPING_OFF, - - /** - * Display grouping using locale defaults, except do not show grouping on values smaller than - * 10000 (such that there is a minimum of two digits before the first separator). - * - *

- * Note that locales may restrict grouping separators to be displayed only on 1 million or - * greater (for example, ee and hu) or disable grouping altogether (for example, bg currency). - * - *

- * Locale data is used to determine whether to separate larger numbers into groups of 2 - * (customary in South Asia) or groups of 3 (customary in Europe and the Americas). - * - * @draft ICU 61 - */ - UNUM_GROUPING_MIN2, - - /** - * Display grouping using the default strategy for all locales. This is the default behavior. - * - *

- * Note that locales may restrict grouping separators to be displayed only on 1 million or - * greater (for example, ee and hu) or disable grouping altogether (for example, bg currency). - * - *

- * Locale data is used to determine whether to separate larger numbers into groups of 2 - * (customary in South Asia) or groups of 3 (customary in Europe and the Americas). - * - * @draft ICU 61 - */ - UNUM_GROUPING_AUTO, - - /** - * Always display the grouping separator on values of at least 1000. - * - *

- * This option ignores the locale data that restricts or disables grouping, described in MIN2 and - * AUTO. This option may be useful to normalize the alignment of numbers, such as in a - * spreadsheet. - * - *

- * Locale data is used to determine whether to separate larger numbers into groups of 2 - * (customary in South Asia) or groups of 3 (customary in Europe and the Americas). - * - * @draft ICU 61 - */ - UNUM_GROUPING_ON_ALIGNED, - - /** - * Use the Western defaults: groups of 3 and enabled for all numbers 1000 or greater. Do not use - * locale data for determining the grouping strategy. - * - * @draft ICU 61 - */ - UNUM_GROUPING_THOUSANDS, - - /** - * One more than the highest UNumberSignDisplay value. - * - * @internal ICU 62: The numeric value may change over time; see ICU ticket #12420. - */ - UNUM_GROUPING_COUNT - -} UGroupingStrategy; - -/** - * An enum declaring how to denote positive and negative numbers. Example outputs when formatting - * 123, 0, and -123 in en-US: - * - *

    - *
  • AUTO: "123", "0", and "-123" - *
  • ALWAYS: "+123", "+0", and "-123" - *
  • NEVER: "123", "0", and "123" - *
  • ACCOUNTING: "$123", "$0", and "($123)" - *
  • ACCOUNTING_ALWAYS: "+$123", "+$0", and "($123)" - *
  • EXCEPT_ZERO: "+123", "0", and "-123" - *
  • ACCOUNTING_EXCEPT_ZERO: "+$123", "$0", and "($123)" - *
- * - *

- * The exact format, including the position and the code point of the sign, differ by locale. - * - * @draft ICU 60 - */ -typedef enum UNumberSignDisplay { - /** - * Show the minus sign on negative numbers, and do not show the sign on positive numbers. This is the default - * behavior. - * - * @draft ICU 60 - */ - UNUM_SIGN_AUTO, - - /** - * Show the minus sign on negative numbers and the plus sign on positive numbers, including zero. - * To hide the sign on zero, see {@link UNUM_SIGN_EXCEPT_ZERO}. - * - * @draft ICU 60 - */ - UNUM_SIGN_ALWAYS, - - /** - * Do not show the sign on positive or negative numbers. - * - * @draft ICU 60 - */ - UNUM_SIGN_NEVER, - - /** - * Use the locale-dependent accounting format on negative numbers, and do not show the sign on positive numbers. - * - *

- * The accounting format is defined in CLDR and varies by locale; in many Western locales, the format is a pair - * of parentheses around the number. - * - *

- * Note: Since CLDR defines the accounting format in the monetary context only, this option falls back to the - * AUTO sign display strategy when formatting without a currency unit. This limitation may be lifted in the - * future. - * - * @draft ICU 60 - */ - UNUM_SIGN_ACCOUNTING, - - /** - * Use the locale-dependent accounting format on negative numbers, and show the plus sign on - * positive numbers, including zero. For more information on the accounting format, see the - * ACCOUNTING sign display strategy. To hide the sign on zero, see - * {@link UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO}. - * - * @draft ICU 60 - */ - UNUM_SIGN_ACCOUNTING_ALWAYS, - - /** - * Show the minus sign on negative numbers and the plus sign on positive numbers. Do not show a - * sign on zero. - * - * @draft ICU 61 - */ - UNUM_SIGN_EXCEPT_ZERO, - - /** - * Use the locale-dependent accounting format on negative numbers, and show the plus sign on - * positive numbers. Do not show a sign on zero. For more information on the accounting format, - * see the ACCOUNTING sign display strategy. - * - * @draft ICU 61 - */ - UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO, - - /** - * One more than the highest UNumberSignDisplay value. - * - * @internal ICU 60: The numeric value may change over time; see ICU ticket #12420. - */ - UNUM_SIGN_COUNT -} UNumberSignDisplay; - -/** - * An enum declaring how to render the decimal separator. - * - *

- *

    - *
  • UNUM_DECIMAL_SEPARATOR_AUTO: "1", "1.1" - *
  • UNUM_DECIMAL_SEPARATOR_ALWAYS: "1.", "1.1" - *
- */ -typedef enum UNumberDecimalSeparatorDisplay { - /** - * Show the decimal separator when there are one or more digits to display after the separator, and do not show - * it otherwise. This is the default behavior. - * - * @draft ICU 60 - */ - UNUM_DECIMAL_SEPARATOR_AUTO, - - /** - * Always show the decimal separator, even if there are no digits to display after the separator. - * - * @draft ICU 60 - */ - UNUM_DECIMAL_SEPARATOR_ALWAYS, - - /** - * One more than the highest UNumberDecimalSeparatorDisplay value. - * - * @internal ICU 60: The numeric value may change over time; see ICU ticket #12420. - */ - UNUM_DECIMAL_SEPARATOR_COUNT -} UNumberDecimalSeparatorDisplay; - U_NAMESPACE_BEGIN // Forward declarations: @@ -438,7 +126,7 @@ class Padder; struct MacroProps; struct MicroProps; class DecimalQuantity; -struct NumberFormatterResults; +struct UFormattedNumberData; class NumberFormatterImpl; struct ParsedPatternInfo; class ScientificModifier; @@ -635,15 +323,18 @@ class U_I18N_API Notation : public UMemory { typedef NotationUnion::ScientificSettings ScientificSettings; - Notation(const NotationType &type, const NotationUnion &union_) : fType(type), fUnion(union_) {} + Notation(const NotationType& type, const NotationUnion& union_) + : fType(type), fUnion(union_) {} - Notation(UErrorCode errorCode) : fType(NTN_ERROR) { + Notation(UErrorCode errorCode) + : fType(NTN_ERROR) { fUnion.errorCode = errorCode; } - Notation() : fType(NTN_SIMPLE), fUnion() {} + Notation() + : fType(NTN_SIMPLE), fUnion() {} - UBool copyErrorTo(UErrorCode &status) const { + UBool copyErrorTo(UErrorCode& status) const { if (fType == NTN_ERROR) { status = fUnion.errorCode; return TRUE; @@ -966,20 +657,22 @@ class U_I18N_API Rounder : public UMemory { UNumberFormatRoundingMode fRoundingMode; - Rounder(const RounderType &type, const RounderUnion &union_, UNumberFormatRoundingMode roundingMode) + Rounder(const RounderType& type, const RounderUnion& union_, UNumberFormatRoundingMode roundingMode) : fType(type), fUnion(union_), fRoundingMode(roundingMode) {} - Rounder(UErrorCode errorCode) : fType(RND_ERROR) { + Rounder(UErrorCode errorCode) + : fType(RND_ERROR) { fUnion.errorCode = errorCode; } - Rounder() : fType(RND_BOGUS) {} + Rounder() + : fType(RND_BOGUS) {} bool isBogus() const { return fType == RND_BOGUS; } - UBool copyErrorTo(UErrorCode &status) const { + UBool copyErrorTo(UErrorCode& status) const { if (fType == RND_ERROR) { status = fUnion.errorCode; return TRUE; @@ -988,15 +681,15 @@ class U_I18N_API Rounder : public UMemory { } // On the parent type so that this method can be called internally on Rounder instances. - Rounder withCurrency(const CurrencyUnit ¤cy, UErrorCode &status) const; + Rounder withCurrency(const CurrencyUnit& currency, UErrorCode& status) const; /** NON-CONST: mutates the current instance. */ - void setLocaleData(const CurrencyUnit ¤cy, UErrorCode &status); + void setLocaleData(const CurrencyUnit& currency, UErrorCode& status); - void apply(impl::DecimalQuantity &value, UErrorCode &status) const; + void apply(impl::DecimalQuantity& value, UErrorCode& status) const; /** Version of {@link #apply} that obeys minInt constraints. Used for scientific notation compatibility mode. */ - void apply(impl::DecimalQuantity &value, int32_t minInt, UErrorCode status); + void apply(impl::DecimalQuantity& value, int32_t minInt, UErrorCode status); /** * Rounding endpoint used by Engineering and Compact notation. Chooses the most appropriate multiplier (magnitude @@ -1012,16 +705,15 @@ class U_I18N_API Rounder : public UMemory { * @param producer Function to call to return a multiplier based on a magnitude. * @return The number of orders of magnitude the input was adjusted by this method. */ - int32_t - chooseMultiplierAndApply(impl::DecimalQuantity &input, const impl::MultiplierProducer &producer, - UErrorCode &status); + int32_t chooseMultiplierAndApply(impl::DecimalQuantity& input, + const impl::MultiplierProducer& producer, UErrorCode& status); static FractionRounder constructFraction(int32_t minFrac, int32_t maxFrac); static Rounder constructSignificant(int32_t minSig, int32_t maxSig); - static Rounder - constructFractionSignificant(const FractionRounder &base, int32_t minSig, int32_t maxSig); + static Rounder constructFractionSignificant(const FractionRounder& base, int32_t minSig, + int32_t maxSig); static IncrementRounder constructIncrement(double increment, int32_t minFrac); @@ -1138,7 +830,7 @@ class U_I18N_API CurrencyRounder : public Rounder { * @return A Rounder for chaining or passing to the NumberFormatter rounding() setter. * @draft ICU 60 */ - Rounder withCurrency(const CurrencyUnit ¤cy) const; + Rounder withCurrency(const CurrencyUnit& currency) const; private: // Inherit constructor @@ -1253,7 +945,7 @@ class U_I18N_API IntegerWidth : public UMemory { return !fHasError && fUnion.minMaxInt.fMinInt == -1; } - UBool copyErrorTo(UErrorCode &status) const { + UBool copyErrorTo(UErrorCode& status) const { if (fHasError) { status = fUnion.errorCode; return TRUE; @@ -1261,7 +953,7 @@ class U_I18N_API IntegerWidth : public UMemory { return FALSE; } - void apply(impl::DecimalQuantity &quantity, UErrorCode &status) const; + void apply(impl::DecimalQuantity& quantity, UErrorCode& status) const; bool operator==(const IntegerWidth& other) const; @@ -1282,10 +974,11 @@ namespace impl { class U_I18N_API SymbolsWrapper : public UMemory { public: /** @internal */ - SymbolsWrapper() : fType(SYMPTR_NONE), fPtr{nullptr} {} + SymbolsWrapper() + : fType(SYMPTR_NONE), fPtr{nullptr} {} /** @internal */ - SymbolsWrapper(const SymbolsWrapper &other); + SymbolsWrapper(const SymbolsWrapper& other); /** @internal */ SymbolsWrapper(SymbolsWrapper&& src) U_NOEXCEPT; @@ -1294,22 +987,22 @@ class U_I18N_API SymbolsWrapper : public UMemory { ~SymbolsWrapper(); /** @internal */ - SymbolsWrapper &operator=(const SymbolsWrapper &other); + SymbolsWrapper& operator=(const SymbolsWrapper& other); /** @internal */ - SymbolsWrapper &operator=(SymbolsWrapper&& src) U_NOEXCEPT; + SymbolsWrapper& operator=(SymbolsWrapper&& src) U_NOEXCEPT; /** * The provided object is copied, but we do not adopt it. * @internal */ - void setTo(const DecimalFormatSymbols &dfs); + void setTo(const DecimalFormatSymbols& dfs); /** * Adopt the provided object. * @internal */ - void setTo(const NumberingSystem *ns); + void setTo(const NumberingSystem* ns); /** * Whether the object is currently holding a DecimalFormatSymbols. @@ -1327,16 +1020,16 @@ class U_I18N_API SymbolsWrapper : public UMemory { * Get the DecimalFormatSymbols pointer. No ownership change. * @internal */ - const DecimalFormatSymbols *getDecimalFormatSymbols() const; + const DecimalFormatSymbols* getDecimalFormatSymbols() const; /** * Get the NumberingSystem pointer. No ownership change. * @internal */ - const NumberingSystem *getNumberingSystem() const; + const NumberingSystem* getNumberingSystem() const; /** @internal */ - UBool copyErrorTo(UErrorCode &status) const { + UBool copyErrorTo(UErrorCode& status) const { if (fType == SYMPTR_DFS && fPtr.dfs == nullptr) { status = U_MEMORY_ALLOCATION_ERROR; return TRUE; @@ -1353,11 +1046,11 @@ class U_I18N_API SymbolsWrapper : public UMemory { } fType; union { - const DecimalFormatSymbols *dfs; - const NumberingSystem *ns; + const DecimalFormatSymbols* dfs; + const NumberingSystem* ns; } fPtr; - void doCopyFrom(const SymbolsWrapper &other); + void doCopyFrom(const SymbolsWrapper& other); void doMoveFrom(SymbolsWrapper&& src); @@ -1418,16 +1111,17 @@ class U_I18N_API Grouper : public UMemory { */ UGroupingStrategy fStrategy; - Grouper() : fGrouping1(-3) {}; + Grouper() + : fGrouping1(-3) {}; bool isBogus() const { return fGrouping1 == -3; } /** NON-CONST: mutates the current instance. */ - void setLocaleData(const impl::ParsedPatternInfo &patternInfo, const Locale& locale); + void setLocaleData(const impl::ParsedPatternInfo& patternInfo, const Locale& locale); - bool groupAtPosition(int32_t position, const impl::DecimalQuantity &value) const; + bool groupAtPosition(int32_t position, const impl::DecimalQuantity& value) const; // To allow MacroProps/MicroProps to initialize empty instances: friend struct MacroProps; @@ -1469,17 +1163,19 @@ class U_I18N_API Padder : public UMemory { Padder(int32_t width); - Padder(UErrorCode errorCode) : fWidth(-3) { // NOLINT + Padder(UErrorCode errorCode) + : fWidth(-3) { // NOLINT fUnion.errorCode = errorCode; } - Padder() : fWidth(-2) {} // NOLINT + Padder() + : fWidth(-2) {} // NOLINT bool isBogus() const { return fWidth == -2; } - UBool copyErrorTo(UErrorCode &status) const { + UBool copyErrorTo(UErrorCode& status) const { if (fWidth == -3) { status = fUnion.errorCode; return TRUE; @@ -1491,9 +1187,9 @@ class U_I18N_API Padder : public UMemory { return fWidth > 0; } - int32_t padAndApply(const impl::Modifier &mod1, const impl::Modifier &mod2, - impl::NumberStringBuilder &string, int32_t leftIndex, int32_t rightIndex, - UErrorCode &status) const; + int32_t padAndApply(const impl::Modifier& mod1, const impl::Modifier& mod2, + impl::NumberStringBuilder& string, int32_t leftIndex, int32_t rightIndex, + UErrorCode& status) const; // To allow MacroProps/MicroProps to initialize empty instances: friend struct MacroProps; @@ -1521,7 +1217,8 @@ class U_I18N_API Multiplier : public UMemory { Multiplier(int32_t magnitudeMultiplier, int32_t multiplier); - Multiplier() : magnitudeMultiplier(0), multiplier(1) {} + Multiplier() + : magnitudeMultiplier(0), multiplier(1) {} bool isValid() const { return magnitudeMultiplier != 0 || multiplier != 1; @@ -1583,10 +1280,10 @@ struct U_I18N_API MacroProps : public UMemory { AffixPatternProvider* affixProvider = nullptr; // no ownership /** @internal */ - PluralRules *rules = nullptr; // no ownership + PluralRules* rules = nullptr; // no ownership /** @internal */ - CurrencySymbols *currencySymbols = nullptr; // no ownership + CurrencySymbols* currencySymbols = nullptr; // no ownership /** @internal */ int32_t threshold = DEFAULT_THRESHOLD; @@ -1600,10 +1297,9 @@ struct U_I18N_API MacroProps : public UMemory { * Check all members for errors. * @internal */ - bool copyErrorTo(UErrorCode &status) const { - return notation.copyErrorTo(status) || rounder.copyErrorTo(status) || - padder.copyErrorTo(status) || integerWidth.copyErrorTo(status) || - symbols.copyErrorTo(status); + bool copyErrorTo(UErrorCode& status) const { + return notation.copyErrorTo(status) || rounder.copyErrorTo(status) || padder.copyErrorTo(status) || + integerWidth.copyErrorTo(status) || symbols.copyErrorTo(status); } }; @@ -1644,7 +1340,7 @@ class U_I18N_API NumberFormatterSettings { * @see Notation * @draft ICU 60 */ - Derived notation(const Notation ¬ation) const &; + Derived notation(const Notation& notation) const& ; /** * Overload of notation() for use on an rvalue reference. @@ -1655,7 +1351,7 @@ class U_I18N_API NumberFormatterSettings { * @see #notation * @draft ICU 62 */ - Derived notation(const Notation ¬ation) &&; + Derived notation(const Notation& notation)&& ; /** * Specifies the unit (unit of measure, currency, or percent) to associate with rendered numbers. @@ -1701,7 +1397,7 @@ class U_I18N_API NumberFormatterSettings { * @see #perUnit * @draft ICU 60 */ - Derived unit(const icu::MeasureUnit &unit) const &; + Derived unit(const icu::MeasureUnit& unit) const& ; /** * Overload of unit() for use on an rvalue reference. @@ -1712,7 +1408,7 @@ class U_I18N_API NumberFormatterSettings { * @see #unit * @draft ICU 62 */ - Derived unit(const icu::MeasureUnit &unit) &&; + Derived unit(const icu::MeasureUnit& unit)&& ; /** * Like unit(), but takes ownership of a pointer. Convenient for use with the MeasureFormat factory @@ -1729,7 +1425,7 @@ class U_I18N_API NumberFormatterSettings { * @see MeasureUnit * @draft ICU 60 */ - Derived adoptUnit(icu::MeasureUnit *unit) const &; + Derived adoptUnit(icu::MeasureUnit* unit) const& ; /** * Overload of adoptUnit() for use on an rvalue reference. @@ -1740,7 +1436,7 @@ class U_I18N_API NumberFormatterSettings { * @see #adoptUnit * @draft ICU 62 */ - Derived adoptUnit(icu::MeasureUnit *unit) &&; + Derived adoptUnit(icu::MeasureUnit* unit)&& ; /** * Sets a unit to be used in the denominator. For example, to format "3 m/s", pass METER to the unit and SECOND to @@ -1759,7 +1455,7 @@ class U_I18N_API NumberFormatterSettings { * @see #unit * @draft ICU 61 */ - Derived perUnit(const icu::MeasureUnit &perUnit) const &; + Derived perUnit(const icu::MeasureUnit& perUnit) const& ; /** * Overload of perUnit() for use on an rvalue reference. @@ -1770,7 +1466,7 @@ class U_I18N_API NumberFormatterSettings { * @see #perUnit * @draft ICU 62 */ - Derived perUnit(const icu::MeasureUnit &perUnit) &&; + Derived perUnit(const icu::MeasureUnit& perUnit)&& ; /** * Like perUnit(), but takes ownership of a pointer. Convenient for use with the MeasureFormat factory @@ -1789,7 +1485,7 @@ class U_I18N_API NumberFormatterSettings { * @see MeasureUnit * @draft ICU 61 */ - Derived adoptPerUnit(icu::MeasureUnit *perUnit) const &; + Derived adoptPerUnit(icu::MeasureUnit* perUnit) const& ; /** * Overload of adoptPerUnit() for use on an rvalue reference. @@ -1800,7 +1496,7 @@ class U_I18N_API NumberFormatterSettings { * @see #adoptPerUnit * @draft ICU 62 */ - Derived adoptPerUnit(icu::MeasureUnit *perUnit) &&; + Derived adoptPerUnit(icu::MeasureUnit* perUnit)&& ; /** * Specifies the rounding strategy to use when formatting numbers. @@ -1832,7 +1528,7 @@ class U_I18N_API NumberFormatterSettings { * @see Rounder * @draft ICU 60 */ - Derived rounding(const Rounder &rounder) const &; + Derived rounding(const Rounder& rounder) const& ; /** * Overload of rounding() for use on an rvalue reference. @@ -1843,7 +1539,7 @@ class U_I18N_API NumberFormatterSettings { * @see #rounding * @draft ICU 62 */ - Derived rounding(const Rounder& rounder) &&; + Derived rounding(const Rounder& rounder)&& ; /** * Specifies the grouping strategy to use when formatting numbers. @@ -1872,7 +1568,7 @@ class U_I18N_API NumberFormatterSettings { * @return The fluent chain. * @draft ICU 61 */ - Derived grouping(const UGroupingStrategy &strategy) const &; + Derived grouping(const UGroupingStrategy& strategy) const& ; /** * Overload of grouping() for use on an rvalue reference. @@ -1884,7 +1580,7 @@ class U_I18N_API NumberFormatterSettings { * @provisional This API might change or be removed in a future release. * @draft ICU 62 */ - Derived grouping(const UGroupingStrategy& rounder) &&; + Derived grouping(const UGroupingStrategy& rounder)&& ; /** * Specifies the minimum and maximum number of digits to render before the decimal mark. @@ -1910,7 +1606,7 @@ class U_I18N_API NumberFormatterSettings { * @see IntegerWidth * @draft ICU 60 */ - Derived integerWidth(const IntegerWidth &style) const &; + Derived integerWidth(const IntegerWidth& style) const& ; /** * Overload of integerWidth() for use on an rvalue reference. @@ -1921,7 +1617,7 @@ class U_I18N_API NumberFormatterSettings { * @see #integerWidth * @draft ICU 62 */ - Derived integerWidth(const IntegerWidth &style) &&; + Derived integerWidth(const IntegerWidth& style)&& ; /** * Specifies the symbols (decimal separator, grouping separator, percent sign, numerals, etc.) to use when rendering @@ -1963,7 +1659,7 @@ class U_I18N_API NumberFormatterSettings { * @see DecimalFormatSymbols * @draft ICU 60 */ - Derived symbols(const DecimalFormatSymbols &symbols) const &; + Derived symbols(const DecimalFormatSymbols& symbols) const& ; /** * Overload of symbols() for use on an rvalue reference. @@ -1974,7 +1670,7 @@ class U_I18N_API NumberFormatterSettings { * @see #symbols * @draft ICU 62 */ - Derived symbols(const DecimalFormatSymbols &symbols) &&; + Derived symbols(const DecimalFormatSymbols& symbols)&& ; /** * Specifies that the given numbering system should be used when fetching symbols. @@ -2009,7 +1705,7 @@ class U_I18N_API NumberFormatterSettings { * @see NumberingSystem * @draft ICU 60 */ - Derived adoptSymbols(NumberingSystem *symbols) const &; + Derived adoptSymbols(NumberingSystem* symbols) const& ; /** * Overload of adoptSymbols() for use on an rvalue reference. @@ -2020,7 +1716,7 @@ class U_I18N_API NumberFormatterSettings { * @see #adoptSymbols * @draft ICU 62 */ - Derived adoptSymbols(NumberingSystem *symbols) &&; + Derived adoptSymbols(NumberingSystem* symbols)&& ; /** * Sets the width of the unit (measure unit or currency). Most common values: @@ -2047,7 +1743,7 @@ class U_I18N_API NumberFormatterSettings { * @see UNumberUnitWidth * @draft ICU 60 */ - Derived unitWidth(const UNumberUnitWidth &width) const &; + Derived unitWidth(const UNumberUnitWidth& width) const& ; /** * Overload of unitWidth() for use on an rvalue reference. @@ -2058,7 +1754,7 @@ class U_I18N_API NumberFormatterSettings { * @see #unitWidth * @draft ICU 62 */ - Derived unitWidth(const UNumberUnitWidth &width) &&; + Derived unitWidth(const UNumberUnitWidth& width)&& ; /** * Sets the plus/minus sign display strategy. Most common values: @@ -2086,7 +1782,7 @@ class U_I18N_API NumberFormatterSettings { * @provisional This API might change or be removed in a future release. * @draft ICU 60 */ - Derived sign(const UNumberSignDisplay &style) const &; + Derived sign(const UNumberSignDisplay& style) const& ; /** * Overload of sign() for use on an rvalue reference. @@ -2097,7 +1793,7 @@ class U_I18N_API NumberFormatterSettings { * @see #sign * @draft ICU 62 */ - Derived sign(const UNumberSignDisplay &style) &&; + Derived sign(const UNumberSignDisplay& style)&& ; /** * Sets the decimal separator display strategy. This affects integer numbers with no fraction part. Most common @@ -2125,7 +1821,7 @@ class U_I18N_API NumberFormatterSettings { * @provisional This API might change or be removed in a future release. * @draft ICU 60 */ - Derived decimal(const UNumberDecimalSeparatorDisplay &style) const &; + Derived decimal(const UNumberDecimalSeparatorDisplay& style) const& ; /** * Overload of decimal() for use on an rvalue reference. @@ -2136,7 +1832,7 @@ class U_I18N_API NumberFormatterSettings { * @see #sign * @draft ICU 62 */ - Derived decimal(const UNumberDecimalSeparatorDisplay &style) &&; + Derived decimal(const UNumberDecimalSeparatorDisplay& style)&& ; #ifndef U_HIDE_INTERNAL_API @@ -2145,10 +1841,10 @@ class U_I18N_API NumberFormatterSettings { * * @internal ICU 60: This API is ICU internal only. */ - Derived padding(const impl::Padder &padder) const &; + Derived padding(const impl::Padder& padder) const& ; /** @internal */ - Derived padding(const impl::Padder &padder) &&; + Derived padding(const impl::Padder& padder)&& ; /** * Internal fluent setter to support a custom regulation threshold. A threshold of 1 causes the data structures to @@ -2156,26 +1852,26 @@ class U_I18N_API NumberFormatterSettings { * * @internal ICU 60: This API is ICU internal only. */ - Derived threshold(int32_t threshold) const &; + Derived threshold(int32_t threshold) const& ; /** @internal */ - Derived threshold(int32_t threshold) &&; + Derived threshold(int32_t threshold)&& ; /** * Internal fluent setter to overwrite the entire macros object. * * @internal ICU 60: This API is ICU internal only. */ - Derived macros(const impl::MacroProps& macros) const &; + Derived macros(const impl::MacroProps& macros) const& ; /** @internal */ - Derived macros(const impl::MacroProps& macros) &&; + Derived macros(const impl::MacroProps& macros)&& ; /** @internal */ - Derived macros(impl::MacroProps&& macros) const &; + Derived macros(impl::MacroProps&& macros) const& ; /** @internal */ - Derived macros(impl::MacroProps&& macros) &&; + Derived macros(impl::MacroProps&& macros)&& ; #endif /* U_HIDE_INTERNAL_API */ @@ -2204,7 +1900,7 @@ class U_I18N_API NumberFormatterSettings { * @return TRUE if U_FAILURE(outErrorCode) * @draft ICU 60 */ - UBool copyErrorTo(UErrorCode &outErrorCode) const { + UBool copyErrorTo(UErrorCode& outErrorCode) const { if (U_FAILURE(outErrorCode)) { // Do not overwrite the older error code return TRUE; @@ -2252,7 +1948,7 @@ class U_I18N_API UnlocalizedNumberFormatter * @return The fluent chain. * @draft ICU 60 */ - LocalizedNumberFormatter locale(const icu::Locale &locale) const &; + LocalizedNumberFormatter locale(const icu::Locale& locale) const& ; /** * Overload of locale() for use on an rvalue reference. @@ -2263,7 +1959,7 @@ class U_I18N_API UnlocalizedNumberFormatter * @see #locale * @draft ICU 62 */ - LocalizedNumberFormatter locale(const icu::Locale &locale) &&; + LocalizedNumberFormatter locale(const icu::Locale& locale)&& ; /** * Default constructor: puts the formatter into a valid but undefined state. @@ -2277,7 +1973,7 @@ class U_I18N_API UnlocalizedNumberFormatter * Returns a copy of this UnlocalizedNumberFormatter. * @draft ICU 60 */ - UnlocalizedNumberFormatter(const UnlocalizedNumberFormatter &other); + UnlocalizedNumberFormatter(const UnlocalizedNumberFormatter& other); /** * Move constructor: @@ -2332,7 +2028,7 @@ class U_I18N_API LocalizedNumberFormatter * @return A FormattedNumber object; call .toString() to get the string. * @draft ICU 60 */ - FormattedNumber formatInt(int64_t value, UErrorCode &status) const; + FormattedNumber formatInt(int64_t value, UErrorCode& status) const; /** * Format the given float or double to a string using the settings specified in the NumberFormatter fluent setting @@ -2345,7 +2041,7 @@ class U_I18N_API LocalizedNumberFormatter * @return A FormattedNumber object; call .toString() to get the string. * @draft ICU 60 */ - FormattedNumber formatDouble(double value, UErrorCode &status) const; + FormattedNumber formatDouble(double value, UErrorCode& status) const; /** * Format the given decimal number to a string using the settings @@ -2396,7 +2092,7 @@ class U_I18N_API LocalizedNumberFormatter * Returns a copy of this LocalizedNumberFormatter. * @draft ICU 60 */ - LocalizedNumberFormatter(const LocalizedNumberFormatter &other); + LocalizedNumberFormatter(const LocalizedNumberFormatter& other); /** * Move constructor: @@ -2418,25 +2114,7 @@ class U_I18N_API LocalizedNumberFormatter */ LocalizedNumberFormatter& operator=(LocalizedNumberFormatter&& src) U_NOEXCEPT; - /** - * Destruct this LocalizedNumberFormatter, cleaning up any memory it might own. - * @draft ICU 60 - */ - ~LocalizedNumberFormatter(); - - private: - // Note: fCompiled can't be a LocalPointer because impl::NumberFormatterImpl is defined in an internal - // header, and LocalPointer needs the full class definition in order to delete the instance. - const impl::NumberFormatterImpl* fCompiled {nullptr}; - char fUnsafeCallCount[8] {}; // internally cast to u_atomic_int32_t - - explicit LocalizedNumberFormatter(const NumberFormatterSettings& other); - - explicit LocalizedNumberFormatter(NumberFormatterSettings&& src) U_NOEXCEPT; - - LocalizedNumberFormatter(const impl::MacroProps ¯os, const Locale &locale); - - LocalizedNumberFormatter(impl::MacroProps &¯os, const Locale &locale); +#ifndef U_HIDE_INTERNAL_API /** * This is the core entrypoint to the number formatting pipeline. It performs self-regulation: a static code path @@ -2446,10 +2124,31 @@ class U_I18N_API LocalizedNumberFormatter * This function is very hot, being called in every call to the number formatting pipeline. * * @param results - * The results object. This method takes ownership. - * @return The formatted number result. + * The results object. This method will mutate it to save the results. */ - FormattedNumber formatImpl(impl::NumberFormatterResults *results, UErrorCode &status) const; + void formatImpl(impl::UFormattedNumberData* results, UErrorCode& status) const; + +#endif + + /** + * Destruct this LocalizedNumberFormatter, cleaning up any memory it might own. + * @draft ICU 60 + */ + ~LocalizedNumberFormatter(); + + private: + // Note: fCompiled can't be a LocalPointer because impl::NumberFormatterImpl is defined in an internal + // header, and LocalPointer needs the full class definition in order to delete the instance. + const impl::NumberFormatterImpl* fCompiled{nullptr}; + char fUnsafeCallCount[8]{}; // internally cast to u_atomic_int32_t + + explicit LocalizedNumberFormatter(const NumberFormatterSettings& other); + + explicit LocalizedNumberFormatter(NumberFormatterSettings&& src) U_NOEXCEPT; + + LocalizedNumberFormatter(const impl::MacroProps& macros, const Locale& locale); + + LocalizedNumberFormatter(impl::MacroProps&& macros, const Locale& locale); // To give the fluent setters access to this class's constructor: friend class NumberFormatterSettings; @@ -2484,7 +2183,7 @@ class U_I18N_API FormattedNumber : public UMemory { * @draft ICU 60 * @see Appendable */ - Appendable &appendTo(Appendable &appendable); + Appendable& appendTo(Appendable& appendable); /** * Determine the start and end indices of the first occurrence of the given field in the output string. @@ -2505,7 +2204,7 @@ class U_I18N_API FormattedNumber : public UMemory { * @draft ICU 60 * @see UNumberFormatFields */ - void populateFieldPosition(FieldPosition &fieldPosition, UErrorCode &status); + void populateFieldPosition(FieldPosition& fieldPosition, UErrorCode& status); /** * Export the formatted number to a FieldPositionIterator. This allows you to determine which characters in @@ -2521,7 +2220,7 @@ class U_I18N_API FormattedNumber : public UMemory { * @draft ICU 60 * @see UNumberFormatFields */ - void populateFieldPositionIterator(FieldPositionIterator &iterator, UErrorCode &status); + void populateFieldPositionIterator(FieldPositionIterator& iterator, UErrorCode& status); #ifndef U_HIDE_INTERNAL_API @@ -2541,6 +2240,7 @@ class U_I18N_API FormattedNumber : public UMemory { // Don't allow copying of FormattedNumber, but moving is okay. FormattedNumber(const FormattedNumber&) = delete; + FormattedNumber& operator=(const FormattedNumber&) = delete; /** @@ -2564,17 +2264,21 @@ class U_I18N_API FormattedNumber : public UMemory { ~FormattedNumber(); private: - // Can't use LocalPointer because NumberFormatterResults is forward-declared - const impl::NumberFormatterResults *fResults; + // Can't use LocalPointer because UFormattedNumberData is forward-declared + const impl::UFormattedNumberData* fResults; // Error code for the terminal methods UErrorCode fErrorCode; - explicit FormattedNumber(impl::NumberFormatterResults *results) - : fResults(results), fErrorCode(U_ZERO_ERROR) {}; + /** + * Internal constructor from data type. Adopts the data pointer. + * @internal + */ + explicit FormattedNumber(const impl::UFormattedNumberData* results) + : fResults(results), fErrorCode(U_ZERO_ERROR) {}; explicit FormattedNumber(UErrorCode errorCode) - : fResults(nullptr), fErrorCode(errorCode) {}; + : fResults(nullptr), fErrorCode(errorCode) {}; // To give LocalizedNumberFormatter format methods access to this class's constructor: friend class LocalizedNumberFormatter; @@ -2605,7 +2309,7 @@ class U_I18N_API NumberFormatter final { * @return A {@link LocalizedNumberFormatter}, to be used for chaining. * @draft ICU 60 */ - static LocalizedNumberFormatter withLocale(const Locale &locale); + static LocalizedNumberFormatter withLocale(const Locale& locale); /** * Call this method at the beginning of a NumberFormatter fluent chain to create an instance based diff --git a/icu4c/source/i18n/unicode/unumberformatter.h b/icu4c/source/i18n/unicode/unumberformatter.h new file mode 100644 index 0000000000..ce46fb34da --- /dev/null +++ b/icu4c/source/i18n/unicode/unumberformatter.h @@ -0,0 +1,517 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT +#ifndef __UNUMBERFORMATTER_H__ +#define __UNUMBERFORMATTER_H__ + + +/** + * \file + * \brief C-compatible API for localized number formatting; not recommended for C++. + * + * This is the C-compatible version of the NumberFormatter API introduced in ICU 60. C++ users should + * include unicode/numberformatter.h and use the proper C++ APIs. + */ + + +/** + * An enum declaring how to render units, including currencies. Example outputs when formatting 123 USD and 123 + * meters in en-CA: + * + *

+ *

    + *
  • NARROW*: "$123.00" and "123 m" + *
  • SHORT: "US$ 123.00" and "123 m" + *
  • FULL_NAME: "123.00 US dollars" and "123 meters" + *
  • ISO_CODE: "USD 123.00" and undefined behavior + *
  • HIDDEN: "123.00" and "123" + *
+ * + *

+ * This enum is similar to {@link com.ibm.icu.text.MeasureFormat.FormatWidth}. + * + * @draft ICU 60 + */ +typedef enum UNumberUnitWidth { + /** + * Print an abbreviated version of the unit name. Similar to SHORT, but always use the shortest available + * abbreviation or symbol. This option can be used when the context hints at the identity of the unit. For more + * information on the difference between NARROW and SHORT, see SHORT. + * + *

+ * In CLDR, this option corresponds to the "Narrow" format for measure units and the "¤¤¤¤¤" placeholder for + * currencies. + * + * @draft ICU 60 + */ + UNUM_UNIT_WIDTH_NARROW, + + /** + * Print an abbreviated version of the unit name. Similar to NARROW, but use a slightly wider abbreviation or + * symbol when there may be ambiguity. This is the default behavior. + * + *

+ * For example, in es-US, the SHORT form for Fahrenheit is "{0} °F", but the NARROW form is "{0}°", + * since Fahrenheit is the customary unit for temperature in that locale. + * + *

+ * In CLDR, this option corresponds to the "Short" format for measure units and the "¤" placeholder for + * currencies. + * + * @draft ICU 60 + */ + UNUM_UNIT_WIDTH_SHORT, + + /** + * Print the full name of the unit, without any abbreviations. + * + *

+ * In CLDR, this option corresponds to the default format for measure units and the "¤¤¤" placeholder for + * currencies. + * + * @draft ICU 60 + */ + UNUM_UNIT_WIDTH_FULL_NAME, + + /** + * Use the three-digit ISO XXX code in place of the symbol for displaying currencies. The behavior of this + * option is currently undefined for use with measure units. + * + *

+ * In CLDR, this option corresponds to the "¤¤" placeholder for currencies. + * + * @draft ICU 60 + */ + UNUM_UNIT_WIDTH_ISO_CODE, + + /** + * Format the number according to the specified unit, but do not display the unit. For currencies, apply + * monetary symbols and formats as with SHORT, but omit the currency symbol. For measure units, the behavior is + * equivalent to not specifying the unit at all. + * + * @draft ICU 60 + */ + UNUM_UNIT_WIDTH_HIDDEN, + + /** + * One more than the highest UNumberUnitWidth value. + * + * @internal ICU 60: The numeric value may change over time; see ICU ticket #12420. + */ + UNUM_UNIT_WIDTH_COUNT +} UNumberUnitWidth; + +/** + * An enum declaring the strategy for when and how to display grouping separators (i.e., the + * separator, often a comma or period, after every 2-3 powers of ten). The choices are several + * pre-built strategies for different use cases that employ locale data whenever possible. Example + * outputs for 1234 and 1234567 in en-IN: + * + *

    + *
  • OFF: 1234 and 12345 + *
  • MIN2: 1234 and 12,34,567 + *
  • AUTO: 1,234 and 12,34,567 + *
  • ON_ALIGNED: 1,234 and 12,34,567 + *
  • THOUSANDS: 1,234 and 1,234,567 + *
+ * + *

+ * The default is AUTO, which displays grouping separators unless the locale data says that grouping + * is not customary. To force grouping for all numbers greater than 1000 consistently across locales, + * use ON_ALIGNED. On the other hand, to display grouping less frequently than the default, use MIN2 + * or OFF. See the docs of each option for details. + * + *

+ * Note: This enum specifies the strategy for grouping sizes. To set which character to use as the + * grouping separator, use the "symbols" setter. + * + * @draft ICU 61 -- TODO: This should be renamed to UNumberGroupingStrategy before promoting to stable, + * for consistency with the other enums. + */ +typedef enum UGroupingStrategy { + /** + * Do not display grouping separators in any locale. + * + * @draft ICU 61 + */ + UNUM_GROUPING_OFF, + + /** + * Display grouping using locale defaults, except do not show grouping on values smaller than + * 10000 (such that there is a minimum of two digits before the first separator). + * + *

+ * Note that locales may restrict grouping separators to be displayed only on 1 million or + * greater (for example, ee and hu) or disable grouping altogether (for example, bg currency). + * + *

+ * Locale data is used to determine whether to separate larger numbers into groups of 2 + * (customary in South Asia) or groups of 3 (customary in Europe and the Americas). + * + * @draft ICU 61 + */ + UNUM_GROUPING_MIN2, + + /** + * Display grouping using the default strategy for all locales. This is the default behavior. + * + *

+ * Note that locales may restrict grouping separators to be displayed only on 1 million or + * greater (for example, ee and hu) or disable grouping altogether (for example, bg currency). + * + *

+ * Locale data is used to determine whether to separate larger numbers into groups of 2 + * (customary in South Asia) or groups of 3 (customary in Europe and the Americas). + * + * @draft ICU 61 + */ + UNUM_GROUPING_AUTO, + + /** + * Always display the grouping separator on values of at least 1000. + * + *

+ * This option ignores the locale data that restricts or disables grouping, described in MIN2 and + * AUTO. This option may be useful to normalize the alignment of numbers, such as in a + * spreadsheet. + * + *

+ * Locale data is used to determine whether to separate larger numbers into groups of 2 + * (customary in South Asia) or groups of 3 (customary in Europe and the Americas). + * + * @draft ICU 61 + */ + UNUM_GROUPING_ON_ALIGNED, + + /** + * Use the Western defaults: groups of 3 and enabled for all numbers 1000 or greater. Do not use + * locale data for determining the grouping strategy. + * + * @draft ICU 61 + */ + UNUM_GROUPING_THOUSANDS, + + /** + * One more than the highest UNumberSignDisplay value. + * + * @internal ICU 62: The numeric value may change over time; see ICU ticket #12420. + */ + UNUM_GROUPING_COUNT + +} UGroupingStrategy; + +/** + * An enum declaring how to denote positive and negative numbers. Example outputs when formatting + * 123, 0, and -123 in en-US: + * + *

    + *
  • AUTO: "123", "0", and "-123" + *
  • ALWAYS: "+123", "+0", and "-123" + *
  • NEVER: "123", "0", and "123" + *
  • ACCOUNTING: "$123", "$0", and "($123)" + *
  • ACCOUNTING_ALWAYS: "+$123", "+$0", and "($123)" + *
  • EXCEPT_ZERO: "+123", "0", and "-123" + *
  • ACCOUNTING_EXCEPT_ZERO: "+$123", "$0", and "($123)" + *
+ * + *

+ * The exact format, including the position and the code point of the sign, differ by locale. + * + * @draft ICU 60 + */ +typedef enum UNumberSignDisplay { + /** + * Show the minus sign on negative numbers, and do not show the sign on positive numbers. This is the default + * behavior. + * + * @draft ICU 60 + */ + UNUM_SIGN_AUTO, + + /** + * Show the minus sign on negative numbers and the plus sign on positive numbers, including zero. + * To hide the sign on zero, see {@link UNUM_SIGN_EXCEPT_ZERO}. + * + * @draft ICU 60 + */ + UNUM_SIGN_ALWAYS, + + /** + * Do not show the sign on positive or negative numbers. + * + * @draft ICU 60 + */ + UNUM_SIGN_NEVER, + + /** + * Use the locale-dependent accounting format on negative numbers, and do not show the sign on positive numbers. + * + *

+ * The accounting format is defined in CLDR and varies by locale; in many Western locales, the format is a pair + * of parentheses around the number. + * + *

+ * Note: Since CLDR defines the accounting format in the monetary context only, this option falls back to the + * AUTO sign display strategy when formatting without a currency unit. This limitation may be lifted in the + * future. + * + * @draft ICU 60 + */ + UNUM_SIGN_ACCOUNTING, + + /** + * Use the locale-dependent accounting format on negative numbers, and show the plus sign on + * positive numbers, including zero. For more information on the accounting format, see the + * ACCOUNTING sign display strategy. To hide the sign on zero, see + * {@link UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO}. + * + * @draft ICU 60 + */ + UNUM_SIGN_ACCOUNTING_ALWAYS, + + /** + * Show the minus sign on negative numbers and the plus sign on positive numbers. Do not show a + * sign on zero. + * + * @draft ICU 61 + */ + UNUM_SIGN_EXCEPT_ZERO, + + /** + * Use the locale-dependent accounting format on negative numbers, and show the plus sign on + * positive numbers. Do not show a sign on zero. For more information on the accounting format, + * see the ACCOUNTING sign display strategy. + * + * @draft ICU 61 + */ + UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO, + + /** + * One more than the highest UNumberSignDisplay value. + * + * @internal ICU 60: The numeric value may change over time; see ICU ticket #12420. + */ + UNUM_SIGN_COUNT +} UNumberSignDisplay; + +/** + * An enum declaring how to render the decimal separator. + * + *

+ *

    + *
  • UNUM_DECIMAL_SEPARATOR_AUTO: "1", "1.1" + *
  • UNUM_DECIMAL_SEPARATOR_ALWAYS: "1.", "1.1" + *
+ */ +typedef enum UNumberDecimalSeparatorDisplay { + /** + * Show the decimal separator when there are one or more digits to display after the separator, and do not show + * it otherwise. This is the default behavior. + * + * @draft ICU 60 + */ + UNUM_DECIMAL_SEPARATOR_AUTO, + + /** + * Always show the decimal separator, even if there are no digits to display after the separator. + * + * @draft ICU 60 + */ + UNUM_DECIMAL_SEPARATOR_ALWAYS, + + /** + * One more than the highest UNumberDecimalSeparatorDisplay value. + * + * @internal ICU 60: The numeric value may change over time; see ICU ticket #12420. + */ + UNUM_DECIMAL_SEPARATOR_COUNT +} UNumberDecimalSeparatorDisplay; + + +/** + * C-compatible version of icu::number::LocalizedNumberFormatter. + * + * NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead. + * + * @draft ICU 62 + */ +typedef struct UNumberFormatter UNumberFormatter; + + +/** + * C-compatible version of icu::number::FormattedNumber. + * + * NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead. + * + * @draft ICU 62 + */ +typedef struct UFormattedNumber UFormattedNumber; + + +/** + * Creates a new UNumberFormatter from the given skeleton string and locale. + * + * For more details on skeleton strings, see the documentation in numberformatter.h. For more details on + * the usage of this API, see the documentation at the top of unumberformatter.h. + * + * NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead. + * + * @draft ICU 62 + */ +U_DRAFT UNumberFormatter* U_EXPORT2 +unumf_openFromSkeletonAndLocale(const UChar* skeleton, int32_t skeletonLen, const char* locale, + UErrorCode* ec); + + +/** + * Creates a new UFormattedNumber for holding the result of a number formatting operation. + * + * NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead. + * + * @draft ICU 62 + */ +U_DRAFT UFormattedNumber* U_EXPORT2 +unumf_openResult(UErrorCode* ec); + + +/** + * Uses a UNumberFormatter to format a double to a UFormattedNumber. A string, field position, and other + * information can be retrieved from the UFormattedNumber. + * + * NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead. + * + * @draft ICU 62 + */ +U_DRAFT void U_EXPORT2 +unumf_formatInt(const UNumberFormatter* uformatter, int64_t value, UFormattedNumber* uresult, + UErrorCode* ec); + + +/** + * Uses a UNumberFormatter to format a double to a UFormattedNumber. A string, field position, and other + * information can be retrieved from the UFormattedNumber. + * + * NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead. + * + * @draft ICU 62 + */ +U_DRAFT void U_EXPORT2 +unumf_formatDouble(const UNumberFormatter* uformatter, double value, UFormattedNumber* uresult, + UErrorCode* ec); + + +/** + * Uses a UNumberFormatter to format a decimal number to a UFormattedNumber. A string, field position, and + * other information can be retrieved from the UFormattedNumber. + * + * The syntax of the unformatted number is a "numeric string" as defined in the Decimal Arithmetic + * Specification, available at http://speleotrove.com/decimal + * + * NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead. + * + * @draft ICU 62 + */ +U_DRAFT void U_EXPORT2 +unumf_formatDecimal(const UNumberFormatter* uformatter, const char* value, int32_t valueLen, + UFormattedNumber* uresult, UErrorCode* ec); + + +/** + * Extracts the result number string out of a UFormattedNumber to a UChar buffer. The usual ICU pattern + * is used for writing to the buffer: + * + * - If the string is shorter than the buffer, it will be written to the buffer and will be NUL-terminated. + * - If the string is exactly the length of the buffer, it will be written to the buffer, but it will not + * be NUL-terminated, and a warning will be set. + * - If the string is longer than the buffer, nothing will be written to the buffer, and an error will be + * set. + * + * In all cases, the actual length of the string is returned, whether or not it was written to the buffer. + * + * NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead. + * + * @draft ICU 62 + */ +U_DRAFT int32_t U_EXPORT2 +unumf_resultToString(const UFormattedNumber* uresult, UChar* buffer, int32_t bufferCapacity, + UErrorCode* ec); + + +/** + * Releases the UFormattedNumber returned by unumf_formatDouble and friends. + * + * NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead. + * + * @draft ICU 62 + */ +U_DRAFT void U_EXPORT2 +unumf_closeResult(const UFormattedNumber* uresult, UErrorCode* ec); + + +/** + * Releases the UNumberFormatter created by unumf_openFromSkeletonAndLocale. + * + * NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead. + * + * @draft ICU 62 + */ +U_DRAFT void U_EXPORT2 +unumf_close(UNumberFormatter* uformatter, UErrorCode* ec); + + +#endif //__UNUMBERFORMATTER_H__ +#endif /* #if !UCONFIG_NO_FORMATTING */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/icu4c/source/test/cintltst/Makefile.in b/icu4c/source/test/cintltst/Makefile.in index f60bb66db8..e7bf69e18d 100644 --- a/icu4c/source/test/cintltst/Makefile.in +++ b/icu4c/source/test/cintltst/Makefile.in @@ -54,7 +54,8 @@ idnatest.o nfsprep.o spreptst.o sprpdata.o \ hpmufn.o tracetst.o reapits.o uregiontest.o ulistfmttest.o\ utexttst.o ucsdetst.o spooftest.o \ cbiditransformtst.o \ -cgendtst.o +cgendtst.o \ +unumberformattertst.o DEPS = $(OBJECTS:.o=.d) diff --git a/icu4c/source/test/cintltst/calltest.c b/icu4c/source/test/cintltst/calltest.c index 6c5af0614c..96ea400a4e 100644 --- a/icu4c/source/test/cintltst/calltest.c +++ b/icu4c/source/test/cintltst/calltest.c @@ -45,6 +45,7 @@ void addUSpoofTest(TestNode** root); #if !UCONFIG_NO_FORMATTING void addGendInfoForTest(TestNode** root); #endif +void addUNumberFormatterTest(TestNode** root); void addAllTests(TestNode** root) { @@ -88,5 +89,6 @@ void addAllTests(TestNode** root) addPUtilTest(root); #if !UCONFIG_NO_FORMATTING addGendInfoForTest(root); + addUNumberFormatterTest(root); #endif } diff --git a/icu4c/source/test/cintltst/cintltst.c b/icu4c/source/test/cintltst/cintltst.c index 40a0b94672..2df1053733 100644 --- a/icu4c/source/test/cintltst/cintltst.c +++ b/icu4c/source/test/cintltst/cintltst.c @@ -709,4 +709,24 @@ U_CFUNC UBool assertEquals(const char* message, const char* expected, return TRUE; } +U_CFUNC UBool assertUEquals(const char* message, const UChar* expected, + const UChar* actual) { + for (int32_t i=0;; i++) { + if (expected[i] != actual[i]) { + log_err("FAIL: %s; got \"%s\"; expected \"%s\"\n", + message, actual, expected); + return FALSE; + } + UChar curr = expected[i]; + U_ASSERT(curr == actual[i]); + if (curr == 0) { + break; + } + } +#ifdef VERBOSE_ASSERTIONS + log_verbose("Ok: %s; got \"%s\"\n", message, actual); +#endif + return TRUE; +} + #endif diff --git a/icu4c/source/test/cintltst/cintltst.h b/icu4c/source/test/cintltst/cintltst.h index d038f36308..7540aa1bc0 100644 --- a/icu4c/source/test/cintltst/cintltst.h +++ b/icu4c/source/test/cintltst/cintltst.h @@ -135,6 +135,13 @@ U_CFUNC UBool assertTrue(const char* msg, int condition); U_CFUNC UBool assertEquals(const char* msg, const char* expectedString, const char* actualString); +/** + * Assert that the actualString equals the expectedString, and return + * TRUE if it does. + */ +U_CFUNC UBool assertUEquals(const char* msg, const UChar* expectedString, + const UChar* actualString); + /* * note - isICUVersionBefore and isICUVersionAtLeast have been removed. * use log_knownIssue() instead. diff --git a/icu4c/source/test/cintltst/unumberformattertst.c b/icu4c/source/test/cintltst/unumberformattertst.c new file mode 100644 index 0000000000..03be113b56 --- /dev/null +++ b/icu4c/source/test/cintltst/unumberformattertst.c @@ -0,0 +1,65 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT + +// Allow implicit conversion from char16_t* to UnicodeString for this file: +// Helpful in toString methods and elsewhere. +#define UNISTR_FROM_STRING_EXPLICIT + +#include "unicode/unumberformatter.h" +#include "cintltst.h" + +static void TestSkeletonFormatToString(); + +void addUNumberFormatterTest(TestNode** root); + +void addUNumberFormatterTest(TestNode** root) { + addTest(root, &TestSkeletonFormatToString, "unumberformatter/TestSkeletonFormatToString"); +} + + +static void TestSkeletonFormatToString() { + UErrorCode ec = U_ZERO_ERROR; + static const int32_t CAPACITY = 30; + UChar buffer[CAPACITY]; + + // SETUP: + UNumberFormatter* f = unumf_openFromSkeletonAndLocale( + u"round-integer currency/USD sign-accounting", -1, "en", &ec); + assertSuccess("Should create without error", &ec); + UFormattedNumber* result = unumf_openResult(&ec); + assertSuccess("Should create result without error", &ec); + + // INT TEST: + unumf_formatInt(f, -444444, result, &ec); + assertSuccess("Should format integer without error", &ec); + unumf_resultToString(result, buffer, CAPACITY, &ec); + assertSuccess("Should print string to buffer without error", &ec); + assertUEquals("Should produce expected string result", u"($444,444)", buffer); + + // DOUBLE TEST: + unumf_formatDouble(f, -5142.3, result, &ec); + assertSuccess("Should format double without error", &ec); + unumf_resultToString(result, buffer, CAPACITY, &ec); + assertSuccess("Should print string to buffer without error", &ec); + assertUEquals("Should produce expected string result", u"($5,142)", buffer); + + // DECIMAL TEST: + unumf_formatDecimal(f, "9.876E2", -1, result, &ec); + assertSuccess("Should format decimal without error", &ec); + unumf_resultToString(result, buffer, CAPACITY, &ec); + assertSuccess("Should print string to buffer without error", &ec); + assertUEquals("Should produce expected string result", u"$988", buffer); + + // CLEANUP: + unumf_closeResult(result, &ec); + assertSuccess("Should close without error", &ec); + unumf_close(f, &ec); + assertSuccess("Should close without error", &ec); +} + + +#endif /* #if !UCONFIG_NO_FORMATTING */