mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-08 23:10:40 +00:00
ICU-11276 Adding C++ base implementation of NumberRangeFormatter, including unit test.
This commit is contained in:
parent
7d34740002
commit
9109a388f4
14 changed files with 580 additions and 16 deletions
|
@ -111,9 +111,9 @@ double-conversion-fast-dtoa.o double-conversion-strtod.o \
|
|||
numparse_stringsegment.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 \
|
||||
numrange_fluent.o numrange_impl.o \
|
||||
erarules.o
|
||||
|
||||
|
||||
## Header files to install
|
||||
HEADERS = $(srcdir)/unicode/*.h
|
||||
|
||||
|
|
|
@ -289,6 +289,8 @@
|
|||
<ClCompile Include="numparse_affixes.cpp" />
|
||||
<ClCompile Include="numparse_compositions.cpp" />
|
||||
<ClCompile Include="numparse_validators.cpp" />
|
||||
<ClCompile Include="numrange_fluent.cpp" />
|
||||
<ClCompile Include="numrange_impl.cpp" />
|
||||
<ClCompile Include="numfmt.cpp" />
|
||||
<ClCompile Include="numsys.cpp" />
|
||||
<ClCompile Include="olsontz.cpp" />
|
||||
|
@ -552,6 +554,7 @@
|
|||
<ClInclude Include="numparse_validators.h" />
|
||||
<ClInclude Include="numparse_types.h" />
|
||||
<ClInclude Include="numparse_utils.h" />
|
||||
<ClInclude Include="numrange_types.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="i18n.rc" />
|
||||
|
|
|
@ -624,6 +624,12 @@
|
|||
<ClCompile Include="numparse_validators.cpp">
|
||||
<Filter>formatting</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="numrange_fluent.cpp">
|
||||
<Filter>formatting</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="numrange_impl.cpp">
|
||||
<Filter>formatting</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="dayperiodrules.cpp">
|
||||
<Filter>formatting</Filter>
|
||||
</ClCompile>
|
||||
|
@ -914,6 +920,9 @@
|
|||
<ClInclude Include="numparse_utils.h">
|
||||
<Filter>formatting</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="numrange_types.h">
|
||||
<Filter>formatting</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="olsontz.h">
|
||||
<Filter>formatting</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
@ -396,6 +396,8 @@
|
|||
<ClCompile Include="numparse_affixes.cpp" />
|
||||
<ClCompile Include="numparse_compositions.cpp" />
|
||||
<ClCompile Include="numparse_validators.cpp" />
|
||||
<ClCompile Include="numrange_fluent.cpp" />
|
||||
<ClCompile Include="numrange_impl.cpp" />
|
||||
<ClCompile Include="numfmt.cpp" />
|
||||
<ClCompile Include="numsys.cpp" />
|
||||
<ClCompile Include="olsontz.cpp" />
|
||||
|
@ -657,6 +659,7 @@
|
|||
<ClInclude Include="numparse_validators.h" />
|
||||
<ClInclude Include="numparse_types.h" />
|
||||
<ClInclude Include="numparse_utils.h" />
|
||||
<ClInclude Include="numrange_types.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="i18n.rc" />
|
||||
|
|
381
icu4c/source/i18n/numrange_fluent.cpp
Normal file
381
icu4c/source/i18n/numrange_fluent.cpp
Normal file
|
@ -0,0 +1,381 @@
|
|||
// © 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 "numrange_types.h"
|
||||
#include "util.h"
|
||||
#include "number_utypes.h"
|
||||
|
||||
using namespace icu;
|
||||
using namespace icu::number;
|
||||
using namespace icu::number::impl;
|
||||
|
||||
|
||||
template<typename Derived>
|
||||
Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(const UnlocalizedNumberFormatter& formatter) const& {
|
||||
Derived copy(*this);
|
||||
copy.fMacros.formatter1 = formatter;
|
||||
copy.fMacros.formatter2 = formatter;
|
||||
return copy;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(const UnlocalizedNumberFormatter& formatter) && {
|
||||
Derived move(std::move(*this));
|
||||
move.fMacros.formatter1 = formatter;
|
||||
move.fMacros.formatter2 = formatter;
|
||||
return move;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(UnlocalizedNumberFormatter&& formatter) const& {
|
||||
Derived copy(*this);
|
||||
copy.fMacros.formatter1 = formatter;
|
||||
copy.fMacros.formatter2 = std::move(formatter);
|
||||
return copy;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(UnlocalizedNumberFormatter&& formatter) && {
|
||||
Derived move(std::move(*this));
|
||||
move.fMacros.formatter1 = formatter;
|
||||
move.fMacros.formatter2 = std::move(formatter);
|
||||
return move;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(const UnlocalizedNumberFormatter& formatter) const& {
|
||||
Derived copy(*this);
|
||||
copy.fMacros.formatter1 = formatter;
|
||||
return copy;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(const UnlocalizedNumberFormatter& formatter) && {
|
||||
Derived move(std::move(*this));
|
||||
move.fMacros.formatter1 = formatter;
|
||||
return move;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(UnlocalizedNumberFormatter&& formatter) const& {
|
||||
Derived copy(*this);
|
||||
copy.fMacros.formatter1 = std::move(formatter);
|
||||
return copy;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(UnlocalizedNumberFormatter&& formatter) && {
|
||||
Derived move(std::move(*this));
|
||||
move.fMacros.formatter1 = std::move(formatter);
|
||||
return move;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(const UnlocalizedNumberFormatter& formatter) const& {
|
||||
Derived copy(*this);
|
||||
copy.fMacros.formatter2 = formatter;
|
||||
return copy;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(const UnlocalizedNumberFormatter& formatter) && {
|
||||
Derived move(std::move(*this));
|
||||
move.fMacros.formatter2 = formatter;
|
||||
return move;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(UnlocalizedNumberFormatter&& formatter) const& {
|
||||
Derived copy(*this);
|
||||
copy.fMacros.formatter2 = std::move(formatter);
|
||||
return copy;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(UnlocalizedNumberFormatter&& formatter) && {
|
||||
Derived move(std::move(*this));
|
||||
move.fMacros.formatter2 = std::move(formatter);
|
||||
return move;
|
||||
}
|
||||
|
||||
// Declare all classes that implement NumberRangeFormatterSettings
|
||||
// See https://stackoverflow.com/a/495056/1407170
|
||||
template
|
||||
class icu::number::NumberRangeFormatterSettings<icu::number::UnlocalizedNumberRangeFormatter>;
|
||||
template
|
||||
class icu::number::NumberRangeFormatterSettings<icu::number::LocalizedNumberRangeFormatter>;
|
||||
|
||||
|
||||
UnlocalizedNumberRangeFormatter NumberRangeFormatter::with() {
|
||||
UnlocalizedNumberRangeFormatter result;
|
||||
return result;
|
||||
}
|
||||
|
||||
LocalizedNumberRangeFormatter NumberRangeFormatter::withLocale(const Locale& locale) {
|
||||
return with().locale(locale);
|
||||
}
|
||||
|
||||
|
||||
template<typename T> using NFS = NumberRangeFormatterSettings<T>;
|
||||
using LNF = LocalizedNumberRangeFormatter;
|
||||
using UNF = UnlocalizedNumberRangeFormatter;
|
||||
|
||||
UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(const UNF& other)
|
||||
: UNF(static_cast<const NFS<UNF>&>(other)) {}
|
||||
|
||||
UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(const NFS<UNF>& other)
|
||||
: NFS<UNF>(other) {
|
||||
// No additional fields to assign
|
||||
}
|
||||
|
||||
UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(UNF&& src) U_NOEXCEPT
|
||||
: UNF(static_cast<NFS<UNF>&&>(src)) {}
|
||||
|
||||
UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(NFS<UNF>&& src) U_NOEXCEPT
|
||||
: NFS<UNF>(std::move(src)) {
|
||||
// No additional fields to assign
|
||||
}
|
||||
|
||||
UnlocalizedNumberRangeFormatter& UnlocalizedNumberRangeFormatter::operator=(const UNF& other) {
|
||||
NFS<UNF>::operator=(static_cast<const NFS<UNF>&>(other));
|
||||
// No additional fields to assign
|
||||
return *this;
|
||||
}
|
||||
|
||||
UnlocalizedNumberRangeFormatter& UnlocalizedNumberRangeFormatter::operator=(UNF&& src) U_NOEXCEPT {
|
||||
NFS<UNF>::operator=(static_cast<NFS<UNF>&&>(src));
|
||||
// No additional fields to assign
|
||||
return *this;
|
||||
}
|
||||
|
||||
LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const LNF& other)
|
||||
: LNF(static_cast<const NFS<LNF>&>(other)) {}
|
||||
|
||||
LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const NFS<LNF>& other)
|
||||
: NFS<LNF>(other) {
|
||||
// No additional fields to assign
|
||||
}
|
||||
|
||||
LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(LocalizedNumberRangeFormatter&& src) U_NOEXCEPT
|
||||
: LNF(static_cast<NFS<LNF>&&>(src)) {}
|
||||
|
||||
LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(NFS<LNF>&& src) U_NOEXCEPT
|
||||
: NFS<LNF>(std::move(src)) {
|
||||
// No additional fields to assign
|
||||
}
|
||||
|
||||
LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(const LNF& other) {
|
||||
NFS<LNF>::operator=(static_cast<const NFS<LNF>&>(other));
|
||||
// No additional fields to assign
|
||||
return *this;
|
||||
}
|
||||
|
||||
LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(LNF&& src) U_NOEXCEPT {
|
||||
NFS<LNF>::operator=(static_cast<NFS<LNF>&&>(src));
|
||||
// No additional fields to assign
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
LocalizedNumberRangeFormatter::~LocalizedNumberRangeFormatter() = default;
|
||||
|
||||
LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const RangeMacroProps& macros, const Locale& locale) {
|
||||
fMacros = macros;
|
||||
fMacros.locale = locale;
|
||||
}
|
||||
|
||||
LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(RangeMacroProps&& macros, const Locale& locale) {
|
||||
fMacros = std::move(macros);
|
||||
fMacros.locale = locale;
|
||||
}
|
||||
|
||||
LocalizedNumberRangeFormatter UnlocalizedNumberRangeFormatter::locale(const Locale& locale) const& {
|
||||
return LocalizedNumberRangeFormatter(fMacros, locale);
|
||||
}
|
||||
|
||||
LocalizedNumberRangeFormatter UnlocalizedNumberRangeFormatter::locale(const Locale& locale)&& {
|
||||
return LocalizedNumberRangeFormatter(std::move(fMacros), locale);
|
||||
}
|
||||
|
||||
|
||||
FormattedNumberRange LocalizedNumberRangeFormatter::formatFormattableRange(
|
||||
const Formattable& first, const Formattable& second, UErrorCode& status) const {
|
||||
if (U_FAILURE(status)) {
|
||||
return FormattedNumberRange(U_ILLEGAL_ARGUMENT_ERROR);
|
||||
}
|
||||
|
||||
auto results = new UFormattedNumberRangeData();
|
||||
if (results == nullptr) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return FormattedNumberRange(status);
|
||||
}
|
||||
|
||||
first.populateDecimalQuantity(results->quantity1, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return FormattedNumberRange(status);
|
||||
}
|
||||
|
||||
second.populateDecimalQuantity(results->quantity2, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return FormattedNumberRange(status);
|
||||
}
|
||||
|
||||
formatImpl(results, status);
|
||||
|
||||
// Do not save the results object if we encountered a failure.
|
||||
if (U_SUCCESS(status)) {
|
||||
return FormattedNumberRange(results);
|
||||
} else {
|
||||
delete results;
|
||||
return FormattedNumberRange(status);
|
||||
}
|
||||
}
|
||||
|
||||
void LocalizedNumberRangeFormatter::formatImpl(
|
||||
UFormattedNumberRangeData* results, UErrorCode& status) const {
|
||||
// TODO: This is a placeholder implementation.
|
||||
|
||||
UFormattedNumberData r1;
|
||||
r1.quantity = results->quantity1;
|
||||
fMacros.formatter1.locale(fMacros.locale).formatImpl(&r1, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
results->quantity1 = r1.quantity;
|
||||
|
||||
UFormattedNumberData r2;
|
||||
r2.quantity = results->quantity2;
|
||||
fMacros.formatter2.locale(fMacros.locale).formatImpl(&r2, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
results->quantity2 = r2.quantity;
|
||||
|
||||
results->string.append(r1.string, status);
|
||||
results->string.append(u" --- ", UNUM_FIELD_COUNT, status);
|
||||
results->string.append(r2.string, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
results->identityType = UNUM_IDENTITY_TYPE_NOT_EQUAL;
|
||||
}
|
||||
|
||||
|
||||
FormattedNumberRange::FormattedNumberRange(FormattedNumberRange&& src) U_NOEXCEPT
|
||||
: fResults(src.fResults), fErrorCode(src.fErrorCode) {
|
||||
// Disown src.fResults to prevent double-deletion
|
||||
src.fResults = nullptr;
|
||||
src.fErrorCode = U_INVALID_STATE_ERROR;
|
||||
}
|
||||
|
||||
FormattedNumberRange& FormattedNumberRange::operator=(FormattedNumberRange&& src) U_NOEXCEPT {
|
||||
delete fResults;
|
||||
fResults = src.fResults;
|
||||
fErrorCode = src.fErrorCode;
|
||||
// Disown src.fResults to prevent double-deletion
|
||||
src.fResults = nullptr;
|
||||
src.fErrorCode = U_INVALID_STATE_ERROR;
|
||||
return *this;
|
||||
}
|
||||
|
||||
UnicodeString FormattedNumberRange::toString(UErrorCode& status) const {
|
||||
if (U_FAILURE(status)) {
|
||||
return ICU_Utility::makeBogusString();
|
||||
}
|
||||
if (fResults == nullptr) {
|
||||
status = fErrorCode;
|
||||
return ICU_Utility::makeBogusString();
|
||||
}
|
||||
return fResults->string.toUnicodeString();
|
||||
}
|
||||
|
||||
Appendable& FormattedNumberRange::appendTo(Appendable& appendable, UErrorCode& status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return appendable;
|
||||
}
|
||||
if (fResults == nullptr) {
|
||||
status = fErrorCode;
|
||||
return appendable;
|
||||
}
|
||||
appendable.appendString(fResults->string.chars(), fResults->string.length());
|
||||
return appendable;
|
||||
}
|
||||
|
||||
UBool FormattedNumberRange::nextFieldPosition(FieldPosition& fieldPosition, UErrorCode& status) const {
|
||||
if (U_FAILURE(status)) {
|
||||
return FALSE;
|
||||
}
|
||||
if (fResults == nullptr) {
|
||||
status = fErrorCode;
|
||||
return FALSE;
|
||||
}
|
||||
// NOTE: MSVC sometimes complains when implicitly converting between bool and UBool
|
||||
return fResults->string.nextFieldPosition(fieldPosition, status) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
void FormattedNumberRange::getAllFieldPositions(FieldPositionIterator& iterator, UErrorCode& status) const {
|
||||
FieldPositionIteratorHandler fpih(&iterator, status);
|
||||
getAllFieldPositionsImpl(fpih, status);
|
||||
}
|
||||
|
||||
void FormattedNumberRange::getAllFieldPositionsImpl(
|
||||
FieldPositionIteratorHandler& fpih, UErrorCode& status) const {
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
if (fResults == nullptr) {
|
||||
status = fErrorCode;
|
||||
return;
|
||||
}
|
||||
fResults->string.getAllFieldPositions(fpih, status);
|
||||
}
|
||||
|
||||
UnicodeString FormattedNumberRange::getFirstDecimal(UErrorCode& status) const {
|
||||
if (U_FAILURE(status)) {
|
||||
return ICU_Utility::makeBogusString();
|
||||
}
|
||||
if (fResults == nullptr) {
|
||||
status = fErrorCode;
|
||||
return ICU_Utility::makeBogusString();
|
||||
}
|
||||
return fResults->quantity1.toScientificString();
|
||||
}
|
||||
|
||||
UnicodeString FormattedNumberRange::getSecondDecimal(UErrorCode& status) const {
|
||||
if (U_FAILURE(status)) {
|
||||
return ICU_Utility::makeBogusString();
|
||||
}
|
||||
if (fResults == nullptr) {
|
||||
status = fErrorCode;
|
||||
return ICU_Utility::makeBogusString();
|
||||
}
|
||||
return fResults->quantity2.toScientificString();
|
||||
}
|
||||
|
||||
UNumberRangeIdentityType FormattedNumberRange::getIdentityType(UErrorCode& status) const {
|
||||
if (U_FAILURE(status)) {
|
||||
return UNUM_IDENTITY_TYPE_NOT_EQUAL;
|
||||
}
|
||||
if (fResults == nullptr) {
|
||||
status = fErrorCode;
|
||||
return UNUM_IDENTITY_TYPE_NOT_EQUAL;
|
||||
}
|
||||
return fResults->identityType;
|
||||
}
|
||||
|
||||
FormattedNumberRange::~FormattedNumberRange() {
|
||||
delete fResults;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
23
icu4c/source/i18n/numrange_impl.cpp
Normal file
23
icu4c/source/i18n/numrange_impl.cpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
// © 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 "numrange_types.h"
|
||||
|
||||
using namespace icu;
|
||||
using namespace icu::number;
|
||||
using namespace icu::number::impl;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
|
@ -36,7 +36,7 @@ struct UFormattedNumberRangeData : public UMemory {
|
|||
DecimalQuantity quantity1;
|
||||
DecimalQuantity quantity2;
|
||||
NumberStringBuilder string;
|
||||
UNumberRangeIdentityType identityType;
|
||||
UNumberRangeIdentityType identityType = UNUM_IDENTITY_TYPE_EQUAL_BEFORE_ROUNDING;
|
||||
|
||||
// No C conversion methods (no C API yet)
|
||||
};
|
||||
|
|
|
@ -162,6 +162,22 @@ 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;
|
||||
|
||||
} // namespace impl
|
||||
|
||||
// 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
|
||||
|
@ -177,7 +193,7 @@ struct U_I18N_API RangeMacroProps : public UMemory {
|
|||
UNumberRangeCollapse collapse = UNUM_RANGE_COLLAPSE_AUTO;
|
||||
|
||||
/** @internal */
|
||||
UNumberIdentityFallback identityFallback = UNUM_IDENTITY_APPROXIMATELY;
|
||||
UNumberIdentityFallback identityFallback = UNUM_IDENTITY_FALLBACK_APPROXIMATELY;
|
||||
|
||||
/** @internal */
|
||||
Locale locale;
|
||||
|
@ -532,7 +548,7 @@ class U_I18N_API LocalizedNumberRangeFormatter
|
|||
* @draft ICU 63
|
||||
*/
|
||||
FormattedNumberRange formatFormattableRange(
|
||||
const Formattable& first, const Formattable& second) const;
|
||||
const Formattable& first, const Formattable& second, UErrorCode& status) const;
|
||||
|
||||
/**
|
||||
* Default constructor: puts the formatter into a valid but undefined state.
|
||||
|
@ -586,10 +602,6 @@ class U_I18N_API LocalizedNumberRangeFormatter
|
|||
~LocalizedNumberRangeFormatter();
|
||||
|
||||
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 LocalizedNumberRangeFormatter(
|
||||
const NumberRangeFormatterSettings<LocalizedNumberRangeFormatter>& other);
|
||||
|
@ -701,7 +713,7 @@ class U_I18N_API FormattedNumberRange : public UMemory {
|
|||
* @see NumberRangeFormatter
|
||||
* @see #getSecondDecimal
|
||||
*/
|
||||
UnicodeString getFirstDecimal() const;
|
||||
UnicodeString getFirstDecimal(UErrorCode& status) const;
|
||||
|
||||
/**
|
||||
* Export the second formatted number as a decimal number. This endpoint
|
||||
|
@ -718,7 +730,7 @@ class U_I18N_API FormattedNumberRange : public UMemory {
|
|||
* @see NumberRangeFormatter
|
||||
* @see #getFirstDecimal
|
||||
*/
|
||||
UnicodeString getSecondDecimal() const;
|
||||
UnicodeString getSecondDecimal(UErrorCode& status) const;
|
||||
|
||||
/**
|
||||
* Returns whether the pair of numbers was successfully formatted as a range or whether an identity fallback was
|
||||
|
@ -730,7 +742,7 @@ class U_I18N_API FormattedNumberRange : public UMemory {
|
|||
* @provisional This API might change or be removed in a future release.
|
||||
* @see UNumberRangeIdentityFallback
|
||||
*/
|
||||
UNumberRangeIdentityType getIdentityType() const;
|
||||
UNumberRangeIdentityType getIdentityType(UErrorCode& status) const;
|
||||
|
||||
/**
|
||||
* Copying not supported; use move constructor instead.
|
||||
|
@ -779,6 +791,8 @@ class U_I18N_API FormattedNumberRange : public UMemory {
|
|||
explicit FormattedNumberRange(UErrorCode errorCode)
|
||||
: fResults(nullptr), fErrorCode(errorCode) {};
|
||||
|
||||
void getAllFieldPositionsImpl(FieldPositionIteratorHandler& fpih, UErrorCode& status) const;
|
||||
|
||||
// To give LocalizedNumberRangeFormatter format methods access to this class's constructor:
|
||||
friend class LocalizedNumberRangeFormatter;
|
||||
};
|
||||
|
@ -797,7 +811,7 @@ class U_I18N_API NumberRangeFormatter final {
|
|||
* @return An {@link UnlocalizedNumberRangeFormatter}, to be used for chaining.
|
||||
* @draft ICU 63
|
||||
*/
|
||||
static UnlocalizedNumberFormatter with();
|
||||
static UnlocalizedNumberRangeFormatter with();
|
||||
|
||||
/**
|
||||
* Call this method at the beginning of a NumberRangeFormatter fluent chain in which the locale is known at the call
|
||||
|
@ -808,7 +822,7 @@ class U_I18N_API NumberRangeFormatter final {
|
|||
* @return A {@link LocalizedNumberRangeFormatter}, to be used for chaining.
|
||||
* @draft ICU 63
|
||||
*/
|
||||
static LocalizedNumberFormatter withLocale(const Locale &locale);
|
||||
static LocalizedNumberRangeFormatter withLocale(const Locale &locale);
|
||||
|
||||
/**
|
||||
* Use factory methods instead of the constructor to create a NumberFormatter.
|
||||
|
|
|
@ -66,7 +66,7 @@ numbertest_affixutils.o numbertest_api.o numbertest_decimalquantity.o \
|
|||
numbertest_modifiers.o numbertest_patternmodifier.o numbertest_patternstring.o \
|
||||
numbertest_stringbuilder.o numbertest_stringsegment.o \
|
||||
numbertest_parse.o numbertest_doubleconversion.o numbertest_skeletons.o \
|
||||
static_unisets_test.o numfmtdatadriventest.o erarulestest.o
|
||||
static_unisets_test.o numfmtdatadriventest.o numbertest_range.o erarulestest.o
|
||||
|
||||
DEPS = $(OBJECTS:.o=.d)
|
||||
|
||||
|
|
|
@ -256,6 +256,7 @@
|
|||
<ClCompile Include="numbertest_parse.cpp" />
|
||||
<ClCompile Include="numbertest_doubleconversion.cpp" />
|
||||
<ClCompile Include="numbertest_skeletons.cpp" />
|
||||
<ClCompile Include="numbertest_range.cpp" />
|
||||
<ClCompile Include="numfmtst.cpp" />
|
||||
<ClCompile Include="numfmtdatadriventest.cpp" />
|
||||
<ClCompile Include="numrgts.cpp" />
|
||||
|
|
|
@ -289,6 +289,9 @@
|
|||
<ClCompile Include="numbertest_skeletons.cpp">
|
||||
<Filter>formatting</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="numbertest_range.cpp">
|
||||
<Filter>formatting</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="numfmtst.cpp">
|
||||
<Filter>formatting</Filter>
|
||||
</ClCompile>
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include "number_affixutils.h"
|
||||
#include "numparse_stringsegment.h"
|
||||
#include "unicode/locid.h"
|
||||
#include "unicode/numberformatter.h"
|
||||
#include "unicode/numberrangeformatter.h"
|
||||
|
||||
using namespace icu::number;
|
||||
using namespace icu::number::impl;
|
||||
|
@ -244,6 +246,37 @@ class NumberSkeletonTest : public IntlTest {
|
|||
void expectedErrorSkeleton(const char16_t** cases, int32_t casesLen);
|
||||
};
|
||||
|
||||
class NumberRangeFormatterTest : public IntlTest {
|
||||
public:
|
||||
void testSanity();
|
||||
void testBasic();
|
||||
|
||||
void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par = 0);
|
||||
|
||||
private:
|
||||
void assertFormatRange(
|
||||
const char16_t* message,
|
||||
const UnlocalizedNumberRangeFormatter& f,
|
||||
Locale locale,
|
||||
const char16_t* expected_10_50,
|
||||
const char16_t* expected_49_51,
|
||||
const char16_t* expected_50_50,
|
||||
const char16_t* expected_00_30,
|
||||
const char16_t* expected_00_00,
|
||||
const char16_t* expected_30_3K,
|
||||
const char16_t* expected_30K_50K,
|
||||
const char16_t* expected_49K_51K,
|
||||
const char16_t* expected_50K_50K,
|
||||
const char16_t* expected_50K_50M);
|
||||
|
||||
void assertFormattedRangeEquals(
|
||||
const char16_t* message,
|
||||
const LocalizedNumberRangeFormatter& l,
|
||||
double first,
|
||||
double second,
|
||||
const char16_t* expected);
|
||||
};
|
||||
|
||||
|
||||
// NOTE: This macro is identical to the one in itformat.cpp
|
||||
#define TESTCLASS(id, TestClass) \
|
||||
|
@ -276,6 +309,7 @@ class NumberTest : public IntlTest {
|
|||
TESTCLASS(8, StringSegmentTest);
|
||||
TESTCLASS(9, NumberParserTest);
|
||||
TESTCLASS(10, NumberSkeletonTest);
|
||||
TESTCLASS(11, NumberRangeFormatterTest);
|
||||
default: name = ""; break; // needed to end loop
|
||||
}
|
||||
}
|
||||
|
|
93
icu4c/source/test/intltest/numbertest_range.cpp
Normal file
93
icu4c/source/test/intltest/numbertest_range.cpp
Normal file
|
@ -0,0 +1,93 @@
|
|||
// © 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
|
||||
|
||||
#include "numbertest.h"
|
||||
#include "unicode/numberrangeformatter.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <numparse_affixes.h>
|
||||
|
||||
using icu::unisets::get;
|
||||
|
||||
void NumberRangeFormatterTest::runIndexedTest(int32_t index, UBool exec, const char*& name, char*) {
|
||||
if (exec) {
|
||||
logln("TestSuite NumberRangeFormatterTest: ");
|
||||
}
|
||||
TESTCASE_AUTO_BEGIN;
|
||||
TESTCASE_AUTO(testSanity);
|
||||
TESTCASE_AUTO(testBasic);
|
||||
TESTCASE_AUTO_END;
|
||||
}
|
||||
|
||||
void NumberRangeFormatterTest::testSanity() {
|
||||
IcuTestErrorCode status(*this, "testSanity");
|
||||
LocalizedNumberRangeFormatter lnrf1 = NumberRangeFormatter::withLocale("en-us");
|
||||
LocalizedNumberRangeFormatter lnrf2 = NumberRangeFormatter::with().locale("en-us");
|
||||
assertEquals("Formatters should have same behavior 1",
|
||||
lnrf1.formatFormattableRange(4, 6, status).toString(status),
|
||||
lnrf2.formatFormattableRange(4, 6, status).toString(status));
|
||||
}
|
||||
|
||||
void NumberRangeFormatterTest::testBasic() {
|
||||
assertFormatRange(
|
||||
u"Basic",
|
||||
NumberRangeFormatter::with(),
|
||||
Locale("en-us"),
|
||||
u"1 --- 5",
|
||||
u"5 --- 5",
|
||||
u"5 --- 5",
|
||||
u"0 --- 3",
|
||||
u"0 --- 0",
|
||||
u"3 --- 3,000",
|
||||
u"3,000 --- 5,000",
|
||||
u"4,999 --- 5,001",
|
||||
u"5,000 --- 5,000",
|
||||
u"5,000 --- 5,000,000");
|
||||
}
|
||||
|
||||
void NumberRangeFormatterTest::assertFormatRange(
|
||||
const char16_t* message,
|
||||
const UnlocalizedNumberRangeFormatter& f,
|
||||
Locale locale,
|
||||
const char16_t* expected_10_50,
|
||||
const char16_t* expected_49_51,
|
||||
const char16_t* expected_50_50,
|
||||
const char16_t* expected_00_30,
|
||||
const char16_t* expected_00_00,
|
||||
const char16_t* expected_30_3K,
|
||||
const char16_t* expected_30K_50K,
|
||||
const char16_t* expected_49K_51K,
|
||||
const char16_t* expected_50K_50K,
|
||||
const char16_t* expected_50K_50M) {
|
||||
LocalizedNumberRangeFormatter l = f.locale(locale);
|
||||
assertFormattedRangeEquals(message, l, 1, 5, expected_10_50);
|
||||
assertFormattedRangeEquals(message, l, 4.9999999, 5.0000001, expected_49_51);
|
||||
assertFormattedRangeEquals(message, l, 5, 5, expected_50_50);
|
||||
assertFormattedRangeEquals(message, l, 0, 3, expected_00_30);
|
||||
assertFormattedRangeEquals(message, l, 0, 0, expected_00_00);
|
||||
assertFormattedRangeEquals(message, l, 3, 3000, expected_30_3K);
|
||||
assertFormattedRangeEquals(message, l, 3000, 5000, expected_30K_50K);
|
||||
assertFormattedRangeEquals(message, l, 4999, 5001, expected_49K_51K);
|
||||
assertFormattedRangeEquals(message, l, 5000, 5000, expected_50K_50K);
|
||||
assertFormattedRangeEquals(message, l, 5e3, 5e6, expected_50K_50M);
|
||||
}
|
||||
|
||||
void NumberRangeFormatterTest::assertFormattedRangeEquals(
|
||||
const char16_t* message,
|
||||
const LocalizedNumberRangeFormatter& l,
|
||||
double first,
|
||||
double second,
|
||||
const char16_t* expected) {
|
||||
IcuTestErrorCode status(*this, "assertFormattedRangeEquals");
|
||||
UnicodeString fullMessage = UnicodeString(message) + u": " + DoubleToUnicodeString(first) + u", " + DoubleToUnicodeString(second);
|
||||
status.setScope(fullMessage);
|
||||
UnicodeString actual = l.formatFormattableRange(first, second, status).toString(status);
|
||||
assertEquals(fullMessage, expected, actual);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -153,8 +153,8 @@ public class NumberRangeFormatterTest {
|
|||
|
||||
private static void assertFormattedRangeEquals(String message, LocalizedNumberRangeFormatter l, Number first,
|
||||
Number second, String expected) {
|
||||
String actual1 = l.formatRange(first, second).toString();
|
||||
assertEquals(message + ": " + first + ", " + second, expected, actual1);
|
||||
String actual = l.formatRange(first, second).toString();
|
||||
assertEquals(message + ": " + first + ", " + second, expected, actual);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue