ICU-13667 update/fix/improve dependencies; better layering formatting->numberparser->numberformatter->number_representation

X-SVN-Rev: 41461
This commit is contained in:
Markus Scherer 2018-05-25 17:57:30 +00:00
parent 87122b9084
commit d8f9a47637
29 changed files with 531 additions and 374 deletions

View file

@ -102,7 +102,7 @@ number_affixutils.o number_compact.o number_decimalquantity.o \
number_decimfmtprops.o number_fluent.o number_formatimpl.o number_grouping.o \
number_integerwidth.o number_longnames.o number_modifiers.o number_notation.o \
number_padding.o number_patternmodifier.o number_patternstring.o \
number_rounding.o number_scientific.o number_stringbuilder.o number_utils.o \
number_rounding.o number_scientific.o number_stringbuilder.o number_utils.o number_asformat.o \
number_mapper.o number_multiplier.o number_currencysymbols.o number_skeletons.o number_capi.o \
double-conversion.o double-conversion-bignum-dtoa.o double-conversion-bignum.o \
double-conversion-cached-powers.o double-conversion-diy-fp.o \

View file

@ -253,6 +253,7 @@
<ClCompile Include="nfsubs.cpp" />
<ClCompile Include="nounit.cpp" />
<ClCompile Include="number_affixutils.cpp" />
<ClCompile Include="number_asformat.cpp" />
<ClCompile Include="number_compact.cpp" />
<ClCompile Include="number_decimalquantity.cpp" />
<ClCompile Include="number_decimfmtprops.cpp" />
@ -515,11 +516,14 @@
<ClInclude Include="uspoof_conf.h" />
<ClInclude Include="uspoof_impl.h" />
<ClInclude Include="number_affixutils.h" />
<ClInclude Include="number_asformat.h" />
<ClInclude Include="number_compact.h" />
<ClInclude Include="number_decimalquantity.h" />
<ClInclude Include="number_decimfmtprops.h" />
<ClInclude Include="number_decnum.h" />
<ClInclude Include="number_formatimpl.h" />
<ClInclude Include="number_longnames.h" />
<ClInclude Include="number_microprops.h" />
<ClInclude Include="number_modifiers.h" />
<ClInclude Include="number_patternmodifier.h" />
<ClInclude Include="number_patternstring.h" />
@ -553,4 +557,4 @@
<Import Project="$(SolutionDir)\Windows.CopyUnicodeHeaderFiles.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View file

@ -519,6 +519,9 @@
<ClCompile Include="number_affixutils.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="number_asformat.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="number_compact.cpp">
<Filter>formatting</Filter>
</ClCompile>
@ -803,6 +806,9 @@
<ClInclude Include="number_affixutils.h">
<Filter>formatting</Filter>
</ClInclude>
<ClInclude Include="number_asformat.h">
<Filter>formatting</Filter>
</ClInclude>
<ClInclude Include="number_compact.h">
<Filter>formatting</Filter>
</ClInclude>
@ -812,12 +818,18 @@
<ClInclude Include="number_decimfmtprops.h">
<Filter>formatting</Filter>
</ClInclude>
<ClInclude Include="number_decnum.h">
<Filter>formatting</Filter>
</ClInclude>
<ClInclude Include="number_formatimpl.h">
<Filter>formatting</Filter>
</ClInclude>
<ClInclude Include="number_longnames.h">
<Filter>formatting</Filter>
</ClInclude>
<ClInclude Include="number_microprops.h">
<Filter>formatting</Filter>
</ClInclude>
<ClInclude Include="number_modifiers.h">
<Filter>formatting</Filter>
</ClInclude>
@ -1414,4 +1426,4 @@
<Filter>formatting</Filter>
</CustomBuild>
</ItemGroup>
</Project>
</Project>

View file

@ -360,6 +360,7 @@
<ClCompile Include="nfsubs.cpp" />
<ClCompile Include="nounit.cpp" />
<ClCompile Include="number_affixutils.cpp" />
<ClCompile Include="number_asformat.cpp" />
<ClCompile Include="number_compact.cpp" />
<ClCompile Include="number_decimalquantity.cpp" />
<ClCompile Include="number_decimfmtprops.cpp" />
@ -620,11 +621,14 @@
<ClInclude Include="uspoof_conf.h" />
<ClInclude Include="uspoof_impl.h" />
<ClInclude Include="number_affixutils.h" />
<ClInclude Include="number_asformat.h" />
<ClInclude Include="number_compact.h" />
<ClInclude Include="number_decimalquantity.h" />
<ClInclude Include="number_decimfmtprops.h" />
<ClInclude Include="number_decnum.h" />
<ClInclude Include="number_formatimpl.h" />
<ClInclude Include="number_longnames.h" />
<ClInclude Include="number_microprops.h" />
<ClInclude Include="number_modifiers.h" />
<ClInclude Include="number_patternmodifier.h" />
<ClInclude Include="number_patternstring.h" />
@ -656,4 +660,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View file

@ -0,0 +1,103 @@
// © 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
// Allow implicit conversion from char16_t* to UnicodeString for this file:
// Helpful in toString methods and elsewhere.
#define UNISTR_FROM_STRING_EXPLICIT
#include <stdlib.h>
#include <cmath>
#include "number_asformat.h"
#include "number_types.h"
#include "number_utils.h"
#include "fphdlimp.h"
#include "number_utypes.h"
using namespace icu;
using namespace icu::number;
using namespace icu::number::impl;
LocalizedNumberFormatterAsFormat::LocalizedNumberFormatterAsFormat(
const LocalizedNumberFormatter& formatter, const Locale& locale)
: fFormatter(formatter), fLocale(locale) {
const char* localeName = locale.getName();
setLocaleIDs(localeName, localeName);
}
LocalizedNumberFormatterAsFormat::~LocalizedNumberFormatterAsFormat() = default;
UBool LocalizedNumberFormatterAsFormat::operator==(const Format& other) const {
auto* _other = dynamic_cast<const LocalizedNumberFormatterAsFormat*>(&other);
if (_other == nullptr) {
return false;
}
// TODO: Change this to use LocalizedNumberFormatter::operator== if it is ever proposed.
// This implementation is fine, but not particularly efficient.
UErrorCode localStatus = U_ZERO_ERROR;
return fFormatter.toSkeleton(localStatus) == _other->fFormatter.toSkeleton(localStatus);
}
Format* LocalizedNumberFormatterAsFormat::clone() const {
return new LocalizedNumberFormatterAsFormat(*this);
}
UnicodeString& LocalizedNumberFormatterAsFormat::format(const Formattable& obj, UnicodeString& appendTo,
FieldPosition& pos, UErrorCode& status) const {
if (U_FAILURE(status)) { return appendTo; }
UFormattedNumberData data;
obj.populateDecimalQuantity(data.quantity, status);
if (U_FAILURE(status)) {
return appendTo;
}
fFormatter.formatImpl(&data, status);
if (U_FAILURE(status)) {
return appendTo;
}
// always return first occurrence:
pos.setBeginIndex(0);
pos.setEndIndex(0);
bool found = data.string.nextFieldPosition(pos, status);
if (found && appendTo.length() != 0) {
pos.setBeginIndex(pos.getBeginIndex() + appendTo.length());
pos.setEndIndex(pos.getEndIndex() + appendTo.length());
}
appendTo.append(data.string.toTempUnicodeString());
return appendTo;
}
UnicodeString& LocalizedNumberFormatterAsFormat::format(const Formattable& obj, UnicodeString& appendTo,
FieldPositionIterator* posIter,
UErrorCode& status) const {
if (U_FAILURE(status)) { return appendTo; }
UFormattedNumberData data;
obj.populateDecimalQuantity(data.quantity, status);
if (U_FAILURE(status)) {
return appendTo;
}
fFormatter.formatImpl(&data, status);
if (U_FAILURE(status)) {
return appendTo;
}
appendTo.append(data.string.toTempUnicodeString());
if (posIter != nullptr) {
FieldPositionIteratorHandler fpih(posIter, status);
data.string.getAllFieldPositions(fpih, status);
}
return appendTo;
}
void LocalizedNumberFormatterAsFormat::parseObject(const UnicodeString&, Formattable&,
ParsePosition& parse_pos) const {
// Not supported.
parse_pos.setErrorIndex(0);
}
const LocalizedNumberFormatter& LocalizedNumberFormatterAsFormat::getNumberFormatter() const {
return fFormatter;
}
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -0,0 +1,104 @@
// © 2017 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#ifndef __NUMBER_ASFORMAT_H__
#define __NUMBER_ASFORMAT_H__
#include "unicode/numberformatter.h"
#include "number_types.h"
#include "number_decimalquantity.h"
#include "number_scientific.h"
#include "number_patternstring.h"
#include "number_modifiers.h"
#include "number_multiplier.h"
#include "number_roundingutils.h"
#include "decNumber.h"
#include "charstr.h"
U_NAMESPACE_BEGIN namespace number {
namespace impl {
/**
* A wrapper around LocalizedNumberFormatter implementing the Format interface, enabling improved
* compatibility with other APIs.
*
* @draft ICU 62
* @see NumberFormatter
*/
class U_I18N_API LocalizedNumberFormatterAsFormat : public Format {
public:
LocalizedNumberFormatterAsFormat(const LocalizedNumberFormatter& formatter, const Locale& locale);
/**
* Destructor.
*/
~LocalizedNumberFormatterAsFormat() U_OVERRIDE;
/**
* Equals operator.
*/
UBool operator==(const Format& other) const U_OVERRIDE;
/**
* Creates a copy of this object.
*/
Format* clone() const U_OVERRIDE;
/**
* Formats a Number using the wrapped LocalizedNumberFormatter. The provided formattable must be a
* number type.
*/
UnicodeString& format(const Formattable& obj, UnicodeString& appendTo, FieldPosition& pos,
UErrorCode& status) const U_OVERRIDE;
/**
* Formats a Number using the wrapped LocalizedNumberFormatter. The provided formattable must be a
* number type.
*/
UnicodeString& format(const Formattable& obj, UnicodeString& appendTo, FieldPositionIterator* posIter,
UErrorCode& status) const U_OVERRIDE;
/**
* Not supported: sets an error index and returns.
*/
void parseObject(const UnicodeString& source, Formattable& result,
ParsePosition& parse_pos) const U_OVERRIDE;
/**
* Gets the LocalizedNumberFormatter that this wrapper class uses to format numbers.
*
* For maximum efficiency, this function returns by const reference. You must copy the return value
* into a local variable if you want to use it beyond the lifetime of the current object:
*
* <pre>
* LocalizedNumberFormatter localFormatter = fmt->getNumberFormatter();
* </pre>
*
* You can however use the return value directly when chaining:
*
* <pre>
* FormattedNumber result = fmt->getNumberFormatter().formatDouble(514.23, status);
* </pre>
*
* @return The unwrapped LocalizedNumberFormatter.
*/
const LocalizedNumberFormatter& getNumberFormatter() const;
private:
LocalizedNumberFormatter fFormatter;
// Even though the locale is inside the LocalizedNumberFormatter, we have to keep it here, too, because
// LocalizedNumberFormatter doesn't have a getLocale() method, and ICU-TC didn't want to add one.
Locale fLocale;
};
} // namespace impl
} // namespace number
U_NAMESPACE_END
#endif // __NUMBER_ASFORMAT_H__
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -5,12 +5,13 @@
#if !UCONFIG_NO_FORMATTING
#include "resource.h"
#include "number_compact.h"
#include "unicode/ustring.h"
#include "unicode/ures.h"
#include "cstring.h"
#include "charstr.h"
#include "resource.h"
#include "number_compact.h"
#include "number_microprops.h"
#include "uresimp.h"
using namespace icu;
@ -283,7 +284,7 @@ void CompactHandler::processQuantity(DecimalQuantity &quantity, MicroProps &micr
magnitude -= multiplier;
}
StandardPlural::Form plural = quantity.getStandardPlural(rules);
StandardPlural::Form plural = utils::getStandardPlural(rules, quantity);
const UChar *patternString = data.getPattern(magnitude, plural);
if (patternString == nullptr) {
// Use the default (non-compact) modifier.

View file

@ -12,6 +12,7 @@
#include "unicode/plurrule.h"
#include "cmemory.h"
#include "number_decnum.h"
#include "putilimp.h"
#include "number_decimalquantity.h"
#include "number_roundingutils.h"
@ -68,6 +69,7 @@ static double DOUBLE_MULTIPLIERS[] = {
} // namespace
icu::IFixedDecimal::~IFixedDecimal() = default;
DecimalQuantity::DecimalQuantity() {
setBcdToZero();
@ -236,16 +238,6 @@ bool DecimalQuantity::adjustMagnitude(int32_t delta) {
return false;
}
StandardPlural::Form DecimalQuantity::getStandardPlural(const PluralRules *rules) const {
if (rules == nullptr) {
// Fail gracefully if the user didn't provide a PluralRules
return StandardPlural::Form::OTHER;
} else {
UnicodeString ruleString = rules->select(*this);
return StandardPlural::orOtherFromString(ruleString);
}
}
double DecimalQuantity::getPluralOperand(PluralOperand operand) const {
// If this assertion fails, you need to call roundToInfinity() or some other rounding method.
// See the comment at the top of this file explaining the "isApproximate" field.

View file

@ -194,15 +194,6 @@ class U_I18N_API DecimalQuantity : public IFixedDecimal, public UMemory {
*/
void appendDigit(int8_t value, int32_t leadingZeros, bool appendAsInteger);
/**
* Computes the plural form for this number based on the specified set of rules.
*
* @param rules A {@link PluralRules} object representing the set of rules.
* @return The {@link StandardPlural} according to the PluralRules. If the plural form is not in
* the set of standard plurals, {@link StandardPlural#OTHER} is returned instead.
*/
StandardPlural::Form getStandardPlural(const PluralRules *rules) const;
double getPluralOperand(PluralOperand operand) const U_OVERRIDE;
bool hasIntegerValue() const U_OVERRIDE;

View file

@ -0,0 +1,77 @@
// © 2017 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#ifndef __NUMBER_DECNUM_H__
#define __NUMBER_DECNUM_H__
#include "decNumber.h"
#include "charstr.h"
U_NAMESPACE_BEGIN
#define DECNUM_INITIAL_CAPACITY 34
// Export an explicit template instantiation of the MaybeStackHeaderAndArray that is used as a data member of DecNum.
// When building DLLs for Windows this is required even though no direct access to the MaybeStackHeaderAndArray leaks out of the i18n library.
// (See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples.)
#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
template class U_I18N_API MaybeStackHeaderAndArray<decNumber, char, DECNUM_INITIAL_CAPACITY>;
#endif
namespace number {
namespace impl {
/** A very thin C++ wrapper around decNumber.h */
// Exported as U_I18N_API for tests
class U_I18N_API DecNum : public UMemory {
public:
DecNum(); // leaves object in valid but undefined state
// Copy-like constructor; use the default move operators.
DecNum(const DecNum& other, UErrorCode& status);
/** Sets the decNumber to the StringPiece. */
void setTo(StringPiece str, UErrorCode& status);
/** Sets the decNumber to the NUL-terminated char string. */
void setTo(const char* str, UErrorCode& status);
/** Uses double_conversion to set this decNumber to the given double. */
void setTo(double d, UErrorCode& status);
/** Sets the decNumber to the BCD representation. */
void setTo(const uint8_t* bcd, int32_t length, int32_t scale, bool isNegative, UErrorCode& status);
void normalize();
void multiplyBy(const DecNum& rhs, UErrorCode& status);
void divideBy(const DecNum& rhs, UErrorCode& status);
bool isNegative() const;
bool isZero() const;
inline const decNumber* getRawDecNumber() const {
return fData.getAlias();
}
private:
static constexpr int32_t kDefaultDigits = DECNUM_INITIAL_CAPACITY;
MaybeStackHeaderAndArray<decNumber, char, kDefaultDigits> fData;
decContext fContext;
void _setTo(const char* str, int32_t maxDigits, UErrorCode& status);
};
} // namespace impl
} // namespace number
U_NAMESPACE_END
#endif // __NUMBER_DECNUM_H__
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -10,6 +10,7 @@
#include "number_decimalquantity.h"
#include "number_formatimpl.h"
#include "umutex.h"
#include "number_asformat.h"
#include "number_skeletons.h"
#include "number_utils.h"
#include "number_utypes.h"

View file

@ -14,6 +14,7 @@
#include "number_patternmodifier.h"
#include "number_longnames.h"
#include "number_compact.h"
#include "number_microprops.h"
U_NAMESPACE_BEGIN namespace number {
namespace impl {

View file

@ -11,6 +11,7 @@
#include "charstr.h"
#include "uresimp.h"
#include "number_longnames.h"
#include "number_microprops.h"
#include <algorithm>
#include "cstring.h"
@ -261,7 +262,7 @@ void LongNameHandler::processQuantity(DecimalQuantity &quantity, MicroProps &mic
// TODO: Avoid the copy here?
DecimalQuantity copy(quantity);
micros.rounder.apply(copy, status);
micros.modOuter = &fModifiers[copy.getStandardPlural(rules)];
micros.modOuter = &fModifiers[utils::getStandardPlural(rules, copy)];
}
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -0,0 +1,82 @@
// © 2017 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#ifndef __NUMBER_MICROPROPS_H__
#define __NUMBER_MICROPROPS_H__
// TODO: minimize includes
#include "unicode/numberformatter.h"
#include "number_types.h"
#include "number_decimalquantity.h"
#include "number_scientific.h"
#include "number_patternstring.h"
#include "number_modifiers.h"
#include "number_multiplier.h"
#include "number_roundingutils.h"
#include "decNumber.h"
#include "charstr.h"
U_NAMESPACE_BEGIN namespace number {
namespace impl {
struct MicroProps : public MicroPropsGenerator {
// NOTE: All of these fields are properly initialized in NumberFormatterImpl.
RoundingImpl rounder;
Grouper grouping;
Padder padding;
IntegerWidth integerWidth;
UNumberSignDisplay sign;
UNumberDecimalSeparatorDisplay decimal;
bool useCurrency;
// Note: This struct has no direct ownership of the following pointers.
const DecimalFormatSymbols* symbols;
const Modifier* modOuter;
const Modifier* modMiddle;
const Modifier* modInner;
// The following "helper" fields may optionally be used during the MicroPropsGenerator.
// They live here to retain memory.
struct {
ScientificModifier scientificModifier;
EmptyModifier emptyWeakModifier{false};
EmptyModifier emptyStrongModifier{true};
MultiplierFormatHandler multiplier;
} helpers;
MicroProps() = default;
MicroProps(const MicroProps& other) = default;
MicroProps& operator=(const MicroProps& other) = default;
void processQuantity(DecimalQuantity&, MicroProps& micros, UErrorCode& status) const U_OVERRIDE {
(void) status;
if (this == &micros) {
// Unsafe path: no need to perform a copy.
U_ASSERT(!exhausted);
micros.exhausted = true;
U_ASSERT(exhausted);
} else {
// Safe path: copy self into the output micros.
micros = *this;
}
}
private:
// Internal fields:
bool exhausted = false;
};
} // namespace impl
} // namespace number
U_NAMESPACE_END
#endif // __NUMBER_MICROPROPS_H__
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -9,6 +9,7 @@
// Helpful in toString methods and elsewhere.
#define UNISTR_FROM_STRING_EXPLICIT
#include "number_decnum.h"
#include "number_types.h"
#include "number_multiplier.h"
#include "numparse_validators.h"
@ -152,21 +153,4 @@ void MultiplierFormatHandler::processQuantity(DecimalQuantity& quantity, MicroPr
multiplier.applyTo(quantity);
}
// NOTE: MultiplierParseHandler is declared in the header numparse_validators.h
MultiplierParseHandler::MultiplierParseHandler(::icu::number::Scale multiplier)
: fMultiplier(std::move(multiplier)) {}
void MultiplierParseHandler::postProcess(ParsedNumber& result) const {
if (!result.quantity.bogus) {
fMultiplier.applyReciprocalTo(result.quantity);
// NOTE: It is okay if the multiplier was negative.
}
}
UnicodeString MultiplierParseHandler::toString() const {
return u"<Scale>";
}
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -10,6 +10,7 @@
#include "unicode/dcfmtsym.h"
#include "unicode/ucurr.h"
#include "unicode/unistr.h"
#include "number_microprops.h"
using namespace icu;
using namespace icu::number;
@ -136,7 +137,7 @@ void ImmutablePatternModifier::applyToMicros(MicroProps& micros, DecimalQuantity
// TODO: Fix this. Avoid the copy.
DecimalQuantity copy(quantity);
copy.roundToInfinity();
StandardPlural::Form plural = copy.getStandardPlural(rules);
StandardPlural::Form plural = utils::getStandardPlural(rules, copy);
micros.modMiddle = pm->getModifier(quantity.signum(), plural);
}
}
@ -166,7 +167,7 @@ void MutablePatternModifier::processQuantity(DecimalQuantity& fq, MicroProps& mi
// TODO: Fix this. Avoid the copy.
DecimalQuantity copy(fq);
micros.rounder.apply(copy, status);
nonConstThis->setNumberProperties(fq.signum(), copy.getStandardPlural(rules));
nonConstThis->setNumberProperties(fq.signum(), utils::getStandardPlural(rules, copy));
} else {
nonConstThis->setNumberProperties(fq.signum(), StandardPlural::Form::COUNT);
}

View file

@ -10,6 +10,7 @@
#include "number_utils.h"
#include "number_stringbuilder.h"
#include "unicode/unum.h"
#include "number_microprops.h"
using namespace icu;
using namespace icu::number;

View file

@ -9,6 +9,7 @@
// Helpful in toString methods and elsewhere.
#define UNISTR_FROM_STRING_EXPLICIT
#include "number_decnum.h"
#include "number_skeletons.h"
#include "umutex.h"
#include "ucln_in.h"

View file

@ -11,6 +11,7 @@
#include <stdlib.h>
#include <cmath>
#include "number_decnum.h"
#include "number_types.h"
#include "number_utils.h"
#include "charstr.h"
@ -20,7 +21,6 @@
#include "fphdlimp.h"
#include "uresimp.h"
#include "ureslocs.h"
#include "number_utypes.h"
using namespace icu;
using namespace icu::number;
@ -49,86 +49,6 @@ doGetPattern(UResourceBundle* res, const char* nsName, const char* patternKey, U
}
LocalizedNumberFormatterAsFormat::LocalizedNumberFormatterAsFormat(
const LocalizedNumberFormatter& formatter, const Locale& locale)
: fFormatter(formatter), fLocale(locale) {
const char* localeName = locale.getName();
setLocaleIDs(localeName, localeName);
}
LocalizedNumberFormatterAsFormat::~LocalizedNumberFormatterAsFormat() = default;
UBool LocalizedNumberFormatterAsFormat::operator==(const Format& other) const {
auto* _other = dynamic_cast<const LocalizedNumberFormatterAsFormat*>(&other);
if (_other == nullptr) {
return false;
}
// TODO: Change this to use LocalizedNumberFormatter::operator== if it is ever proposed.
// This implementation is fine, but not particularly efficient.
UErrorCode localStatus = U_ZERO_ERROR;
return fFormatter.toSkeleton(localStatus) == _other->fFormatter.toSkeleton(localStatus);
}
Format* LocalizedNumberFormatterAsFormat::clone() const {
return new LocalizedNumberFormatterAsFormat(*this);
}
UnicodeString& LocalizedNumberFormatterAsFormat::format(const Formattable& obj, UnicodeString& appendTo,
FieldPosition& pos, UErrorCode& status) const {
if (U_FAILURE(status)) { return appendTo; }
UFormattedNumberData data;
obj.populateDecimalQuantity(data.quantity, status);
if (U_FAILURE(status)) {
return appendTo;
}
fFormatter.formatImpl(&data, status);
if (U_FAILURE(status)) {
return appendTo;
}
// always return first occurrence:
pos.setBeginIndex(0);
pos.setEndIndex(0);
bool found = data.string.nextFieldPosition(pos, status);
if (found && appendTo.length() != 0) {
pos.setBeginIndex(pos.getBeginIndex() + appendTo.length());
pos.setEndIndex(pos.getEndIndex() + appendTo.length());
}
appendTo.append(data.string.toTempUnicodeString());
return appendTo;
}
UnicodeString& LocalizedNumberFormatterAsFormat::format(const Formattable& obj, UnicodeString& appendTo,
FieldPositionIterator* posIter,
UErrorCode& status) const {
if (U_FAILURE(status)) { return appendTo; }
UFormattedNumberData data;
obj.populateDecimalQuantity(data.quantity, status);
if (U_FAILURE(status)) {
return appendTo;
}
fFormatter.formatImpl(&data, status);
if (U_FAILURE(status)) {
return appendTo;
}
appendTo.append(data.string.toTempUnicodeString());
if (posIter != nullptr) {
FieldPositionIteratorHandler fpih(posIter, status);
data.string.getAllFieldPositions(fpih, status);
}
return appendTo;
}
void LocalizedNumberFormatterAsFormat::parseObject(const UnicodeString&, Formattable&,
ParsePosition& parse_pos) const {
// Not supported.
parse_pos.setErrorIndex(0);
}
const LocalizedNumberFormatter& LocalizedNumberFormatterAsFormat::getNumberFormatter() const {
return fFormatter;
}
const char16_t* utils::getPatternForStyle(const Locale& locale, const char* nsName, CldrPatternStyle style,
UErrorCode& status) {
const char* patternKey;
@ -330,6 +250,4 @@ bool DecNum::isZero() const {
return decNumberIsZero(fData.getAlias());
}
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -20,145 +20,9 @@
U_NAMESPACE_BEGIN
#define DECNUM_INITIAL_CAPACITY 34
// Export an explicit template instantiation of the MaybeStackHeaderAndArray that is used as a data member of DecNum.
// When building DLLs for Windows this is required even though no direct access to the MaybeStackHeaderAndArray leaks out of the i18n library.
// (See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples.)
#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
template class U_I18N_API MaybeStackHeaderAndArray<decNumber, char, DECNUM_INITIAL_CAPACITY>;
#endif
namespace number {
namespace impl {
struct MicroProps : public MicroPropsGenerator {
// NOTE: All of these fields are properly initialized in NumberFormatterImpl.
RoundingImpl rounder;
Grouper grouping;
Padder padding;
IntegerWidth integerWidth;
UNumberSignDisplay sign;
UNumberDecimalSeparatorDisplay decimal;
bool useCurrency;
// Note: This struct has no direct ownership of the following pointers.
const DecimalFormatSymbols* symbols;
const Modifier* modOuter;
const Modifier* modMiddle;
const Modifier* modInner;
// The following "helper" fields may optionally be used during the MicroPropsGenerator.
// They live here to retain memory.
struct {
ScientificModifier scientificModifier;
EmptyModifier emptyWeakModifier{false};
EmptyModifier emptyStrongModifier{true};
MultiplierFormatHandler multiplier;
} helpers;
MicroProps() = default;
MicroProps(const MicroProps& other) = default;
MicroProps& operator=(const MicroProps& other) = default;
void processQuantity(DecimalQuantity&, MicroProps& micros, UErrorCode& status) const U_OVERRIDE {
(void) status;
if (this == &micros) {
// Unsafe path: no need to perform a copy.
U_ASSERT(!exhausted);
micros.exhausted = true;
U_ASSERT(exhausted);
} else {
// Safe path: copy self into the output micros.
micros = *this;
}
}
private:
// Internal fields:
bool exhausted = false;
};
/**
* A wrapper around LocalizedNumberFormatter implementing the Format interface, enabling improved
* compatibility with other APIs.
*
* @draft ICU 62
* @see NumberFormatter
*/
class U_I18N_API LocalizedNumberFormatterAsFormat : public Format {
public:
LocalizedNumberFormatterAsFormat(const LocalizedNumberFormatter& formatter, const Locale& locale);
/**
* Destructor.
*/
~LocalizedNumberFormatterAsFormat() U_OVERRIDE;
/**
* Equals operator.
*/
UBool operator==(const Format& other) const U_OVERRIDE;
/**
* Creates a copy of this object.
*/
Format* clone() const U_OVERRIDE;
/**
* Formats a Number using the wrapped LocalizedNumberFormatter. The provided formattable must be a
* number type.
*/
UnicodeString& format(const Formattable& obj, UnicodeString& appendTo, FieldPosition& pos,
UErrorCode& status) const U_OVERRIDE;
/**
* Formats a Number using the wrapped LocalizedNumberFormatter. The provided formattable must be a
* number type.
*/
UnicodeString& format(const Formattable& obj, UnicodeString& appendTo, FieldPositionIterator* posIter,
UErrorCode& status) const U_OVERRIDE;
/**
* Not supported: sets an error index and returns.
*/
void parseObject(const UnicodeString& source, Formattable& result,
ParsePosition& parse_pos) const U_OVERRIDE;
/**
* Gets the LocalizedNumberFormatter that this wrapper class uses to format numbers.
*
* For maximum efficiency, this function returns by const reference. You must copy the return value
* into a local variable if you want to use it beyond the lifetime of the current object:
*
* <pre>
* LocalizedNumberFormatter localFormatter = fmt->getNumberFormatter();
* </pre>
*
* You can however use the return value directly when chaining:
*
* <pre>
* FormattedNumber result = fmt->getNumberFormatter().formatDouble(514.23, status);
* </pre>
*
* @return The unwrapped LocalizedNumberFormatter.
*/
const LocalizedNumberFormatter& getNumberFormatter() const;
private:
LocalizedNumberFormatter fFormatter;
// Even though the locale is inside the LocalizedNumberFormatter, we have to keep it here, too, because
// LocalizedNumberFormatter doesn't have a getLocale() method, and ICU-TC didn't want to add one.
Locale fLocale;
};
enum CldrPatternStyle {
CLDR_PATTERN_STYLE_DECIMAL,
CLDR_PATTERN_STYLE_CURRENCY,
@ -200,55 +64,29 @@ inline bool unitIsPermille(const MeasureUnit& unit) {
const char16_t*
getPatternForStyle(const Locale& locale, const char* nsName, CldrPatternStyle style, UErrorCode& status);
} // namespace utils
/** A very thin C++ wrapper around decNumber.h */
// Exported as U_I18N_API for tests
class U_I18N_API DecNum : public UMemory {
public:
DecNum(); // leaves object in valid but undefined state
// Copy-like constructor; use the default move operators.
DecNum(const DecNum& other, UErrorCode& status);
/** Sets the decNumber to the StringPiece. */
void setTo(StringPiece str, UErrorCode& status);
/** Sets the decNumber to the NUL-terminated char string. */
void setTo(const char* str, UErrorCode& status);
/** Uses double_conversion to set this decNumber to the given double. */
void setTo(double d, UErrorCode& status);
/** Sets the decNumber to the BCD representation. */
void setTo(const uint8_t* bcd, int32_t length, int32_t scale, bool isNegative, UErrorCode& status);
void normalize();
void multiplyBy(const DecNum& rhs, UErrorCode& status);
void divideBy(const DecNum& rhs, UErrorCode& status);
bool isNegative() const;
bool isZero() const;
inline const decNumber* getRawDecNumber() const {
return fData.getAlias();
/**
* Computes the plural form for this number based on the specified set of rules.
*
* @param rules A {@link PluralRules} object representing the set of rules.
* @return The {@link StandardPlural} according to the PluralRules. If the plural form is not in
* the set of standard plurals, {@link StandardPlural#OTHER} is returned instead.
*/
inline StandardPlural::Form getStandardPlural(const PluralRules *rules,
const IFixedDecimal &fdec) {
if (rules == nullptr) {
// Fail gracefully if the user didn't provide a PluralRules
return StandardPlural::Form::OTHER;
} else {
UnicodeString ruleString = rules->select(fdec);
return StandardPlural::orOtherFromString(ruleString);
}
}
private:
static constexpr int32_t kDefaultDigits = DECNUM_INITIAL_CAPACITY;
MaybeStackHeaderAndArray<decNumber, char, kDefaultDigits> fData;
decContext fContext;
void _setTo(const char* str, int32_t maxDigits, UErrorCode& status);
};
} // namespace utils
} // namespace impl
} // namespace number
U_NAMESPACE_END
#endif //__NUMBER_UTILS_H__

View file

@ -68,5 +68,18 @@ UnicodeString RequireNumberValidator::toString() const {
return u"<ReqNumber>";
}
MultiplierParseHandler::MultiplierParseHandler(::icu::number::Scale multiplier)
: fMultiplier(std::move(multiplier)) {}
void MultiplierParseHandler::postProcess(ParsedNumber& result) const {
if (!result.quantity.bogus) {
fMultiplier.applyReciprocalTo(result.quantity);
// NOTE: It is okay if the multiplier was negative.
}
}
UnicodeString MultiplierParseHandler::toString() const {
return u"<Scale>";
}
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -71,8 +71,6 @@ class RequireNumberValidator : public ValidationMatcher, public UMemory {
/**
* Wraps a {@link Multiplier} for use in the number parsing pipeline.
*
* NOTE: Implemented in number_multiplier.cpp
*/
class MultiplierParseHandler : public ValidationMatcher, public UMemory {
public:

View file

@ -248,26 +248,6 @@ PluralRules::select(double number) const {
return select(FixedDecimal(number));
}
UnicodeString
PluralRules::select(const Formattable& obj, const NumberFormat& fmt, UErrorCode& status) const {
if (U_SUCCESS(status)) {
const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(&fmt);
if (decFmt != NULL) {
number::impl::DecimalQuantity dq;
decFmt->formatToDecimalQuantity(obj, dq, status);
if (U_SUCCESS(status)) {
return select(dq);
}
} else {
double number = obj.getDouble(status);
if (U_SUCCESS(status)) {
return select(number);
}
}
}
return UnicodeString();
}
UnicodeString
PluralRules::select(const IFixedDecimal &number) const {
if (mRules == NULL) {
@ -1418,8 +1398,6 @@ PluralOperand tokenTypeToPluralOperand(tokenType tt) {
}
}
IFixedDecimal::~IFixedDecimal() = default;
FixedDecimal::FixedDecimal(double n, int32_t v, int64_t f) {
init(n, v, f);
// check values. TODO make into unit test.

View file

@ -347,22 +347,6 @@ public:
UnicodeString select(double number) const;
#ifndef U_HIDE_INTERNAL_API
/**
* Given a number and a format, returns the keyword of the first applicable
* rule for this PluralRules object.
* Note: This internal preview interface may be removed in the future if
* an architecturally cleaner solution reaches stable status.
* @param obj The numeric object for which the rule should be determined.
* @param fmt The NumberFormat specifying how the number will be formatted
* (this can affect the plural form, e.g. "1 dollar" vs "1.0 dollars").
* @param status Input/output parameter. If at entry this indicates a
* failure status, the method returns immediately; otherwise
* this is set to indicate the outcome of the call.
* @return The keyword of the selected rule. Undefined in the case of an error.
* @internal ICU 59 technology preview, may be removed in the future
*/
UnicodeString select(const Formattable& obj, const NumberFormat& fmt, UErrorCode& status) const;
/**
* @internal
*/

View file

@ -17,9 +17,44 @@
#include "unicode/unistr.h"
#include "unicode/unum.h"
#include "unicode/numfmt.h"
#include "number_decimalquantity.h"
U_NAMESPACE_USE
namespace {
/**
* Given a number and a format, returns the keyword of the first applicable
* rule for the PluralRules object.
* @param rules The plural rules.
* @param obj The numeric object for which the rule should be determined.
* @param fmt The NumberFormat specifying how the number will be formatted
* (this can affect the plural form, e.g. "1 dollar" vs "1.0 dollars").
* @param status Input/output parameter. If at entry this indicates a
* failure status, the method returns immediately; otherwise
* this is set to indicate the outcome of the call.
* @return The keyword of the selected rule. Undefined in the case of an error.
*/
UnicodeString select(const PluralRules &rules, const Formattable& obj, const NumberFormat& fmt, UErrorCode& status) {
if (U_SUCCESS(status)) {
const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(&fmt);
if (decFmt != NULL) {
number::impl::DecimalQuantity dq;
decFmt->formatToDecimalQuantity(obj, dq, status);
if (U_SUCCESS(status)) {
return rules.select(dq);
}
} else {
double number = obj.getDouble(status);
if (U_SUCCESS(status)) {
return rules.select(number);
}
}
}
return UnicodeString();
}
} // namespace
U_CAPI UPluralRules* U_EXPORT2
uplrules_open(const char *locale, UErrorCode *status)
@ -73,7 +108,7 @@ uplrules_selectWithFormat(const UPluralRules *uplrules,
return 0;
}
Formattable obj(number);
UnicodeString result = plrules->select(obj, *nf, *status);
UnicodeString result = select(*plrules, obj, *nf, *status);
return result.extract(keyword, capacity, *status);
}

View file

@ -18,7 +18,7 @@ system_symbols:
# C
PIC system_misc system_debug malloc_functions ubsan
c_strings c_string_formatting
floating_point trigonometry
int_functions floating_point trigonometry
stdlib_qsort
pthread system_locale
stdio_input stdio_output file_io readlink_function dir_io mmap_functions dlfcn
@ -58,8 +58,11 @@ group: c_string_formatting
# Additional symbols in an optimized build.
__sprintf_chk
group: int_functions
div
group: floating_point
abs fabs floor ceil modf fmod log pow round sqrt
abs fabs floor ceil modf fmod log pow round sqrt trunc
group: trigonometry
acos asin atan atan2 cos sin tan
@ -154,6 +157,7 @@ library: common
unistr_props unistr_case unistr_case_locale unistr_titlecase_brkiter unistr_cnv
cstr
uniset_core uniset_props uniset_closure usetiter uset uset_props
static_unicode_sets
uiter edits
ucasemap ucasemap_titlecase_brkiter script_runs
uprops ubidi_props ucase uscript uscript_props
@ -281,6 +285,11 @@ group: punycode
deps
platform
group: static_unicode_sets
static_unicode_sets.o
deps
resourcebundle uniset_props
group: uset_props
uset_props.o
deps
@ -475,6 +484,8 @@ group: ustr_titlecase_brkiter
group: edits
edits.o
deps
# Edits::Iterator::toString() calls ICU_Utility::appendNumber()
icu_utility
platform
group: ucasemap_titlecase_brkiter
@ -574,6 +585,7 @@ group: currency
deps
loclikely resourcebundle ulist ustring_case_locale
stdlib_qsort # for ucurr.o (which does not use ICU's uarrsort.o)
static_unicode_sets usetiter
group: icudataver # u_getDataVersion()
icudataver.o
@ -804,7 +816,7 @@ library: i18n
alphabetic_index collation collation_builder string_search
dayperiodrules
formatting formattable_cnv regex regex_cnv translit
double_conversion numberformatter
double_conversion number_representation numberformatter numberparser
universal_time_scale
uclean_i18n
@ -881,39 +893,57 @@ group: dayperiodrules
group: double_conversion
double-conversion.o double-conversion-bignum.o double-conversion-bignum-dtoa.o
double-conversion-cached-powers.o double-conversion-diy-fp.o
double-conversion-fast-dtoa.o
double-conversion-fast-dtoa.o double-conversion-strtod.o
deps
platform
group: number_representation
number_decimalquantity.o number_stringbuilder.o numparse_stringsegment.o number_utils.o
deps
decnumber double_conversion
# for data loading; that could be split off
resourcebundle
int_functions
ucase uniset_core
group: numberformatter
# ICU 60+ NumberFormatter API
number_affixutils.o number_compact.o number_decimalquantity.o
number_decimfmtprops.o number_fluent.o number_formatimpl.o
number_affixutils.o number_asformat.o
number_capi.o number_compact.o number_currencysymbols.o
number_decimfmtprops.o
number_fluent.o number_formatimpl.o
number_grouping.o number_integerwidth.o number_longnames.o
number_modifiers.o number_notation.o number_padding.o
number_mapper.o number_modifiers.o number_multiplier.o
number_notation.o number_padding.o
number_patternmodifier.o number_patternstring.o number_rounding.o
number_scientific.o number_stringbuilder.o
number_scientific.o number_skeletons.o
currpinf.o dcfmtsym.o numsys.o
# pluralrules
standardplural.o plurrule.o
deps
digitlist formattable format units
# TODO: fix: dependency on formatting needed for circular dependency pluralrules <-> decimfmt.o
# We should be able to have a small pluralrules group and depend on that here.
formatting
decnumber double_conversion formattable format units
number_representation
uclean_i18n common
group: numberparser
numparse_affixes.o numparse_compositions.o numparse_currency.o
numparse_decimal.o numparse_impl.o numparse_parsednumber.o
numparse_scientific.o numparse_symbols.o
numparse_validators.o
deps
numberformatter
group: formatting
# TODO: Try to subdivide this ball of wax.
# currencyformat
curramt.o currfmt.o currpinf.o
curramt.o currfmt.o
# pluralrules C API
upluralrules.o
# decimalformat
dcfmtsym.o numsys.o unumsys.o
affixpatternparser.o decimfmtimpl.o digitaffix.o digitaffixesandpadding.o
digitformatter.o digitgrouping.o digitinterval.o
pluralaffix.o precision.o smallintformatter.o valueformatter.o
decfmtst.o decimfmt.o decimalformatpattern.o compactdecimalformat.o
unumsys.o
decimfmt.o compactdecimalformat.o
numfmt.o unum.o
winnmfmt.o
# pluralrules
standardplural.o plurrule.o upluralrules.o
# scientificnumberformatter - would depend on dcfmtsym, so would be circular.
scientificnumberformatter.o
# rbnf
@ -934,7 +964,7 @@ group: formatting
# messageformat
choicfmt.o msgfmt.o plurfmt.o selfmt.o umsg.o
deps
digitlist formattable format units
decnumber formattable format units numberformatter numberparser
dayperiodrules
collation collation_builder # for rbnf
common
@ -953,8 +983,8 @@ group: units
deps
stringenumeration
group: digitlist
digitlst.o decContext.o decNumber.o visibledigits.o
group: decnumber
decContext.o decNumber.o
deps
double_conversion uclean_i18n
@ -962,7 +992,7 @@ group: formattable
fmtable.o
measure.o
deps
digitlist
decnumber number_representation
group: formattable_cnv
fmtable_cnv.o

View file

@ -10,6 +10,7 @@
#include <cmath>
#include "unicode/unum.h"
#include "unicode/numberformatter.h"
#include "number_asformat.h"
#include "number_types.h"
#include "number_utils.h"
#include "numbertest.h"

View file

@ -6,6 +6,7 @@
#if !UCONFIG_NO_FORMATTING
#include "number_decimalquantity.h"
#include "number_decnum.h"
#include "math.h"
#include <cmath>
#include "number_utils.h"

View file

@ -6,6 +6,7 @@
#if !UCONFIG_NO_FORMATTING
#include "numbertest.h"
#include "number_microprops.h"
#include "number_patternmodifier.h"
void PatternModifierTest::runIndexedTest(int32_t index, UBool exec, const char *&name, char *) {