ICU-13634 The property mapper appears to be basically functional; data passes from the old API through the mapper into the new API and then back out through the old API again.

X-SVN-Rev: 41108
This commit is contained in:
Shane Carr 2018-03-15 10:08:26 +00:00
parent 1a95c170d2
commit 00a23a07f7
8 changed files with 302 additions and 35 deletions

View file

@ -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 \
number_mapper.o
number_mapper.o number_multiplier.o
## Header files to install

View file

@ -64,6 +64,7 @@ DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols*
DecimalFormat::DecimalFormat(const DecimalFormatSymbols* symbolsToAdopt, UErrorCode& status) {
fProperties.adoptInsteadAndCheckErrorCode(new DecimalFormatProperties(), status);
fExportedProperties.adoptInsteadAndCheckErrorCode(new DecimalFormatProperties(), status);
fWarehouse.adoptInsteadAndCheckErrorCode(new DecimalFormatWarehouse(), status);
if (symbolsToAdopt == nullptr) {
fSymbols.adoptInsteadAndCheckErrorCode(new DecimalFormatSymbols(status), status);
} else {
@ -313,8 +314,10 @@ DecimalFormat::DecimalFormat(const UnicodeString& pattern, const DecimalFormatSy
DecimalFormat::DecimalFormat(const DecimalFormat& source) {
fProperties.adoptInstead(new DecimalFormatProperties());
fExportedProperties.adoptInstead(new DecimalFormatProperties());
fWarehouse.adoptInstead(new DecimalFormatWarehouse());
fSymbols.adoptInstead(new DecimalFormatSymbols(*source.fSymbols));
if (fProperties == nullptr || fExportedProperties == nullptr || fSymbols == nullptr) {
if (fProperties == nullptr || fExportedProperties == nullptr || fWarehouse == nullptr ||
fSymbols == nullptr) {
return;
}
refreshFormatterNoError();
@ -862,7 +865,7 @@ void DecimalFormat::formatToDecimalQuantity(const Formattable& number, DecimalQu
status = U_UNSUPPORTED_ERROR;
}
number::LocalizedNumberFormatter DecimalFormat::toNumberFormatter() const {
const number::LocalizedNumberFormatter& DecimalFormat::toNumberFormatter() const {
return *fFormatter;
}
@ -897,14 +900,16 @@ void DecimalFormat::refreshFormatter(UErrorCode& status) {
fFormatter.adoptInsteadAndCheckErrorCode(
new LocalizedNumberFormatter(
NumberPropertyMapper::create(
*fProperties, *fSymbols, *fExportedProperties, status).locale(
*fProperties, *fSymbols, *fWarehouse, *fExportedProperties, status).locale(
locale)), status);
fParser.adoptInsteadAndCheckErrorCode(
NumberParserImpl::createParserFromProperties(
*fProperties, *fSymbols, false, false, status), status);
fParserWithCurrency.adoptInsteadAndCheckErrorCode(
NumberParserImpl::createParserFromProperties(
*fProperties, *fSymbols, true, false, status), status);
// fParser.adoptInsteadAndCheckErrorCode(
// NumberParserImpl::createParserFromProperties(
// *fProperties, *fSymbols, false, false, status), status);
// fParserWithCurrency.adoptInsteadAndCheckErrorCode(
// NumberParserImpl::createParserFromProperties(
// *fProperties, *fSymbols, true, false, status), status);
}
void DecimalFormat::refreshFormatterNoError() {

View file

@ -276,6 +276,12 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps& macros, bool safe,
/// START POPULATING THE DEFAULT MICROPROPS AND BUILDING THE MICROPROPS GENERATOR ///
/////////////////////////////////////////////////////////////////////////////////////
// Multiplier (compatibility mode value).
if (macros.multiplier.isValid()) {
fMicros.helpers.multiplier.setAndChain(macros.multiplier, chain);
chain = &fMicros.helpers.multiplier;
}
// Rounding strategy
if (!macros.rounder.isBogus()) {
fMicros.rounding = macros.rounder;
@ -342,7 +348,9 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps& macros, bool safe,
// Middle modifier (patterns, positive/negative, currency symbols, percent)
auto patternModifier = new MutablePatternModifier(false);
fPatternModifier.adoptInstead(patternModifier);
patternModifier->setPatternInfo(fPatternInfo.getAlias());
patternModifier->setPatternInfo(
macros.affixProvider != nullptr ? macros.affixProvider
: static_cast<const AffixPatternProvider*>(fPatternInfo.getAlias()));
patternModifier->setPatternAttributes(fMicros.sign, isPermille);
if (patternModifier->needsPlurals()) {
patternModifier->setSymbols(

View file

@ -11,6 +11,8 @@
#include "number_mapper.h"
#include "number_patternstring.h"
#include "unicode/errorcode.h"
#include "number_utils.h"
using namespace icu;
using namespace icu::number;
@ -61,10 +63,10 @@ MacroProps NumberPropertyMapper::oldToNew(const DecimalFormatProperties& propert
AffixPatternProvider* affixProvider;
if (properties.currencyPluralInfo.fPtr.isNull()) {
warehouse.currencyPluralInfoAPP.setToBogus();
warehouse.propertiesAPP.setTo(properties);
warehouse.propertiesAPP.setTo(properties, status);
affixProvider = &warehouse.propertiesAPP;
} else {
warehouse.currencyPluralInfoAPP.setTo(*properties.currencyPluralInfo.fPtr);
warehouse.currencyPluralInfoAPP.setTo(*properties.currencyPluralInfo.fPtr, status);
warehouse.propertiesAPP.setToBogus();
affixProvider = &warehouse.currencyPluralInfoAPP;
}
@ -229,8 +231,8 @@ MacroProps NumberPropertyMapper::oldToNew(const DecimalFormatProperties& propert
macros.rounder = Rounder::constructSignificant(1, maxFrac_ + 1).withMode(roundingMode);
} else {
// All other scientific patterns, which mean round to minInt+maxFrac
macros.rounder = Rounder::constructSignificant(minInt_ + minFrac_, minInt_ + maxFrac_)
.withMode(roundingMode);
macros.rounder = Rounder::constructSignificant(
minInt_ + minFrac_, minInt_ + maxFrac_).withMode(roundingMode);
}
}
}
@ -254,9 +256,9 @@ MacroProps NumberPropertyMapper::oldToNew(const DecimalFormatProperties& propert
/////////////////
if (properties.magnitudeMultiplier != 0) {
macros.multiplier = MultiplierImpl::magnitude(properties.magnitudeMultiplier);
macros.multiplier = Multiplier::magnitude(properties.magnitudeMultiplier);
} else if (properties.multiplier != 1) {
macros.multiplier = MultiplierImpl::integer(properties.multiplier);
macros.multiplier = Multiplier::integer(properties.multiplier);
}
//////////////////////
@ -303,8 +305,127 @@ MacroProps NumberPropertyMapper::oldToNew(const DecimalFormatProperties& propert
}
void PropertiesAffixPatternProvider::setTo(const DecimalFormatProperties& properties) {
// TODO
void PropertiesAffixPatternProvider::setTo(const DecimalFormatProperties& properties, UErrorCode&) {
// There are two ways to set affixes in DecimalFormat: via the pattern string (applyPattern), and via the
// explicit setters (setPositivePrefix and friends). The way to resolve the settings is as follows:
//
// 1) If the explicit setting is present for the field, use it.
// 2) Otherwise, follows UTS 35 rules based on the pattern string.
//
// Importantly, the explicit setters affect only the one field they override. If you set the positive
// prefix, that should not affect the negative prefix. Since it is impossible for the user of this class
// to know whether the origin for a string was the override or the pattern, we have to say that we always
// have a negative subpattern and perform all resolution logic here.
// Convenience: Extract the properties into local variables.
// Variables are named with three chars: [p/n][p/s][o/p]
// [p/n] => p for positive, n for negative
// [p/s] => p for prefix, s for suffix
// [o/p] => o for escaped custom override string, p for pattern string
UnicodeString ppo = AffixUtils::escape(UnicodeStringCharSequence(properties.positivePrefix));
UnicodeString pso = AffixUtils::escape(UnicodeStringCharSequence(properties.positiveSuffix));
UnicodeString npo = AffixUtils::escape(UnicodeStringCharSequence(properties.negativePrefix));
UnicodeString nso = AffixUtils::escape(UnicodeStringCharSequence(properties.negativeSuffix));
const UnicodeString& ppp = properties.positivePrefixPattern;
const UnicodeString& psp = properties.positiveSuffixPattern;
const UnicodeString& npp = properties.negativePrefixPattern;
const UnicodeString& nsp = properties.negativeSuffixPattern;
if (!properties.positivePrefix.isBogus()) {
posPrefix = ppo;
} else if (!ppp.isBogus()) {
posPrefix = ppp;
} else {
// UTS 35: Default positive prefix is empty string.
posPrefix = u"";
}
if (!properties.positiveSuffix.isBogus()) {
posSuffix = pso;
} else if (!psp.isBogus()) {
posSuffix = psp;
} else {
// UTS 35: Default positive suffix is empty string.
posSuffix = u"";
}
if (!properties.negativePrefix.isBogus()) {
negPrefix = npo;
} else if (!npp.isBogus()) {
negPrefix = npp;
} else {
// UTS 35: Default negative prefix is "-" with positive prefix.
// Important: We prepend the "-" to the pattern, not the override!
negPrefix = ppp.isBogus() ? u"-" : u"-" + ppp;
}
if (!properties.negativeSuffix.isBogus()) {
negSuffix = nso;
} else if (!nsp.isBogus()) {
negSuffix = nsp;
} else {
// UTS 35: Default negative prefix is the positive prefix.
negSuffix = psp.isBogus() ? u"" : psp;
}
}
char16_t PropertiesAffixPatternProvider::charAt(int flags, int i) const {
return getStringInternal(flags).charAt(i);
}
int PropertiesAffixPatternProvider::length(int flags) const {
return getStringInternal(flags).length();
}
UnicodeString PropertiesAffixPatternProvider::getString(int32_t flags) const {
return getStringInternal(flags);
}
const UnicodeString& PropertiesAffixPatternProvider::getStringInternal(int32_t flags) const {
bool prefix = (flags & AFFIX_PREFIX) != 0;
bool negative = (flags & AFFIX_NEGATIVE_SUBPATTERN) != 0;
if (prefix && negative) {
return negPrefix;
} else if (prefix) {
return posPrefix;
} else if (negative) {
return negSuffix;
} else {
return posSuffix;
}
}
bool PropertiesAffixPatternProvider::positiveHasPlusSign() const {
// TODO: Change the internal APIs to propagate out the error?
ErrorCode localStatus;
return AffixUtils::containsType(UnicodeStringCharSequence(posPrefix), TYPE_PLUS_SIGN, localStatus) ||
AffixUtils::containsType(UnicodeStringCharSequence(posSuffix), TYPE_PLUS_SIGN, localStatus);
}
bool PropertiesAffixPatternProvider::hasNegativeSubpattern() const {
// See comments in the constructor for more information on why this is always true.
return true;
}
bool PropertiesAffixPatternProvider::negativeHasMinusSign() const {
ErrorCode localStatus;
return AffixUtils::containsType(UnicodeStringCharSequence(negPrefix), TYPE_MINUS_SIGN, localStatus) ||
AffixUtils::containsType(UnicodeStringCharSequence(negSuffix), TYPE_MINUS_SIGN, localStatus);
}
bool PropertiesAffixPatternProvider::hasCurrencySign() const {
ErrorCode localStatus;
return AffixUtils::hasCurrencySymbols(UnicodeStringCharSequence(posPrefix), localStatus) ||
AffixUtils::hasCurrencySymbols(UnicodeStringCharSequence(posSuffix), localStatus) ||
AffixUtils::hasCurrencySymbols(UnicodeStringCharSequence(negPrefix), localStatus) ||
AffixUtils::hasCurrencySymbols(UnicodeStringCharSequence(negSuffix), localStatus);
}
bool PropertiesAffixPatternProvider::containsSymbolType(AffixPatternType type, UErrorCode& status) const {
return AffixUtils::containsType(UnicodeStringCharSequence(posPrefix), type, status) ||
AffixUtils::containsType(UnicodeStringCharSequence(posSuffix), type, status) ||
AffixUtils::containsType(UnicodeStringCharSequence(negPrefix), type, status) ||
AffixUtils::containsType(UnicodeStringCharSequence(negSuffix), type, status);
}
bool PropertiesAffixPatternProvider::hasBody() const {
@ -312,8 +433,48 @@ bool PropertiesAffixPatternProvider::hasBody() const {
}
void CurrencyPluralInfoAffixProvider::setTo(const CurrencyPluralInfo& cpi) {
// TODO
void CurrencyPluralInfoAffixProvider::setTo(const CurrencyPluralInfo& cpi, UErrorCode& status) {
for (int32_t plural = 0; plural < StandardPlural::COUNT; plural++) {
const char* keyword = StandardPlural::getKeyword(static_cast<StandardPlural::Form>(plural));
UnicodeString patternString;
patternString = cpi.getCurrencyPluralPattern(keyword, patternString);
PatternParser::parseToPatternInfo(patternString, affixesByPlural[plural], status);
}
}
char16_t CurrencyPluralInfoAffixProvider::charAt(int32_t flags, int32_t i) const {
int32_t pluralOrdinal = (flags & AFFIX_PLURAL_MASK);
return affixesByPlural[pluralOrdinal].charAt(flags, i);
}
int32_t CurrencyPluralInfoAffixProvider::length(int32_t flags) const {
int32_t pluralOrdinal = (flags & AFFIX_PLURAL_MASK);
return affixesByPlural[pluralOrdinal].length(flags);
}
UnicodeString CurrencyPluralInfoAffixProvider::getString(int32_t flags) const {
int32_t pluralOrdinal = (flags & AFFIX_PLURAL_MASK);
return affixesByPlural[pluralOrdinal].getString(flags);
}
bool CurrencyPluralInfoAffixProvider::positiveHasPlusSign() const {
return affixesByPlural[StandardPlural::OTHER].positiveHasPlusSign();
}
bool CurrencyPluralInfoAffixProvider::hasNegativeSubpattern() const {
return affixesByPlural[StandardPlural::OTHER].hasNegativeSubpattern();
}
bool CurrencyPluralInfoAffixProvider::negativeHasMinusSign() const {
return affixesByPlural[StandardPlural::OTHER].negativeHasMinusSign();
}
bool CurrencyPluralInfoAffixProvider::hasCurrencySign() const {
return affixesByPlural[StandardPlural::OTHER].hasCurrencySign();
}
bool CurrencyPluralInfoAffixProvider::containsSymbolType(AffixPatternType type, UErrorCode& status) const {
return affixesByPlural[StandardPlural::OTHER].containsSymbolType(type, status);
}
bool CurrencyPluralInfoAffixProvider::hasBody() const {

View file

@ -18,19 +18,23 @@ namespace impl {
class PropertiesAffixPatternProvider : public AffixPatternProvider, public UMemory {
public:
bool isBogus() const;
bool isBogus() const {
return fBogus;
}
void setTo(const DecimalFormatProperties& properties);
void setToBogus() {
fBogus = true;
}
void setToBogus();
void setTo(const DecimalFormatProperties& properties, UErrorCode& status);
// AffixPatternProvider Methods:
char16_t charAt(int flags, int i) const U_OVERRIDE;
char16_t charAt(int32_t flags, int32_t i) const U_OVERRIDE;
int length(int flags) const U_OVERRIDE;
int32_t length(int32_t flags) const U_OVERRIDE;
UnicodeString getString(int flags) const U_OVERRIDE;
UnicodeString getString(int32_t flags) const U_OVERRIDE;
bool hasCurrencySign() const U_OVERRIDE;
@ -42,7 +46,7 @@ class PropertiesAffixPatternProvider : public AffixPatternProvider, public UMemo
bool containsSymbolType(AffixPatternType, UErrorCode&) const U_OVERRIDE;
virtual bool hasBody() const U_OVERRIDE;
bool hasBody() const U_OVERRIDE;
private:
UnicodeString posPrefix;
@ -50,25 +54,31 @@ class PropertiesAffixPatternProvider : public AffixPatternProvider, public UMemo
UnicodeString negPrefix;
UnicodeString negSuffix;
const UnicodeString& getStringInternal(int32_t flags) const;
bool fBogus{true};
};
class CurrencyPluralInfoAffixProvider : public AffixPatternProvider, public UMemory {
public:
bool isBogus() const;
bool isBogus() const {
return fBogus;
}
void setTo(const CurrencyPluralInfo& cpi);
void setToBogus() {
fBogus = true;
}
void setToBogus();
void setTo(const CurrencyPluralInfo& cpi, UErrorCode& status);
// AffixPatternProvider Methods:
char16_t charAt(int flags, int i) const U_OVERRIDE;
char16_t charAt(int32_t flags, int32_t i) const U_OVERRIDE;
int length(int flags) const U_OVERRIDE;
int32_t length(int32_t flags) const U_OVERRIDE;
UnicodeString getString(int flags) const U_OVERRIDE;
UnicodeString getString(int32_t flags) const U_OVERRIDE;
bool hasCurrencySign() const U_OVERRIDE;
@ -80,7 +90,7 @@ class CurrencyPluralInfoAffixProvider : public AffixPatternProvider, public UMem
bool containsSymbolType(AffixPatternType, UErrorCode&) const U_OVERRIDE;
virtual bool hasBody() const U_OVERRIDE;
bool hasBody() const U_OVERRIDE;
private:
ParsedPatternInfo affixesByPlural[StandardPlural::COUNT];

View file

@ -0,0 +1,47 @@
// © 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 "number_types.h"
#include "number_multiplier.h"
using namespace icu;
using namespace icu::number;
using namespace icu::number::impl;
Multiplier::Multiplier(int32_t magnitudeMultiplier, int32_t multiplier)
: magnitudeMultiplier(magnitudeMultiplier), multiplier(multiplier) {}
Multiplier Multiplier::magnitude(int32_t magnitudeMultiplier) {
return {magnitudeMultiplier, 1};
}
Multiplier Multiplier::integer(int32_t multiplier) {
return {0, multiplier};
}
void MultiplierChain::setAndChain(const Multiplier& multiplier, const MicroPropsGenerator* parent) {
this->multiplier = multiplier;
this->parent = parent;
}
void
MultiplierChain::processQuantity(DecimalQuantity& quantity, MicroProps& micros, UErrorCode& status) const {
parent->processQuantity(quantity, micros, status);
quantity.adjustMagnitude(multiplier.magnitudeMultiplier);
if (multiplier.multiplier != 1) {
quantity.multiplyBy(multiplier.multiplier);
}
}
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -0,0 +1,34 @@
// © 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_MULTIPLIER_H__
#define __SOURCE_NUMBER_MULTIPLIER_H__
#include "numparse_types.h"
U_NAMESPACE_BEGIN namespace number {
namespace impl {
class MultiplierChain : public MicroPropsGenerator, public UMemory {
public:
void setAndChain(const Multiplier& other, const MicroPropsGenerator* parent);
void processQuantity(DecimalQuantity& quantity, MicroProps& micros,
UErrorCode& status) const U_OVERRIDE;
private:
Multiplier multiplier;
const MicroPropsGenerator *parent;
};
} // namespace impl
} // namespace number
U_NAMESPACE_END
#endif //__SOURCE_NUMBER_MULTIPLIER_H__
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -13,6 +13,7 @@
#include "number_scientific.h"
#include "number_patternstring.h"
#include "number_modifiers.h"
#include "number_multiplier.h"
U_NAMESPACE_BEGIN namespace number {
namespace impl {
@ -73,6 +74,7 @@ struct MicroProps : public MicroPropsGenerator {
ScientificModifier scientificModifier;
EmptyModifier emptyWeakModifier{false};
EmptyModifier emptyStrongModifier{true};
MultiplierChain multiplier;
} helpers;