ICU-13551 Adding EXCEPT_ZERO enum value to SignDisplay.
X-SVN-Rev: 40824
This commit is contained in:
parent
a7c4b0a3a8
commit
3dce9dcab9
@ -265,6 +265,10 @@ bool DecimalQuantity::isNegative() const {
|
||||
return (flags & NEGATIVE_FLAG) != 0;
|
||||
}
|
||||
|
||||
int8_t DecimalQuantity::signum() const {
|
||||
return isNegative() ? -1 : isZero() ? 0 : 1;
|
||||
}
|
||||
|
||||
bool DecimalQuantity::isInfinite() const {
|
||||
return (flags & INFINITY_FLAG) != 0;
|
||||
}
|
||||
|
@ -115,6 +115,9 @@ class U_I18N_API DecimalQuantity : public IFixedDecimal, public UMemory {
|
||||
/** @return Whether the value represented by this {@link DecimalQuantity} is less than zero. */
|
||||
bool isNegative() const;
|
||||
|
||||
/** @return -1 if the value is negative; 1 if positive; or 0 if zero. */
|
||||
int8_t signum() const;
|
||||
|
||||
/** @return Whether the value represented by this {@link DecimalQuantity} is infinite. */
|
||||
bool isInfinite() const U_OVERRIDE;
|
||||
|
||||
|
@ -161,8 +161,9 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps ¯os, bool safe,
|
||||
bool isPercent = isNoUnit && unitIsPercent(macros.unit);
|
||||
bool isPermille = isNoUnit && unitIsPermille(macros.unit);
|
||||
bool isCldrUnit = !isCurrency && !isNoUnit;
|
||||
bool isAccounting =
|
||||
macros.sign == UNUM_SIGN_ACCOUNTING || macros.sign == UNUM_SIGN_ACCOUNTING_ALWAYS;
|
||||
bool isAccounting = macros.sign == UNUM_SIGN_ACCOUNTING
|
||||
|| macros.sign == UNUM_SIGN_ACCOUNTING_ALWAYS
|
||||
|| macros.sign == UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO;
|
||||
CurrencyUnit currency(kDefaultCurrency, status);
|
||||
if (isCurrency) {
|
||||
currency = CurrencyUnit(macros.unit, status); // Restore CurrencyUnit from MeasureUnit
|
||||
|
@ -216,31 +216,33 @@ class U_I18N_API ParameterizedModifier : public UMemory {
|
||||
}
|
||||
}
|
||||
|
||||
void adoptPositiveNegativeModifiers(const Modifier *positive, const Modifier *negative) {
|
||||
mods[0] = positive;
|
||||
mods[1] = negative;
|
||||
void adoptPositiveNegativeModifiers(
|
||||
const Modifier *positive, const Modifier *zero, const Modifier *negative) {
|
||||
mods[2] = positive;
|
||||
mods[1] = zero;
|
||||
mods[0] = negative;
|
||||
}
|
||||
|
||||
/** The modifier is ADOPTED. */
|
||||
void adoptSignPluralModifier(bool isNegative, StandardPlural::Form plural, const Modifier *mod) {
|
||||
mods[getModIndex(isNegative, plural)] = mod;
|
||||
void adoptSignPluralModifier(int8_t signum, StandardPlural::Form plural, const Modifier *mod) {
|
||||
mods[getModIndex(signum, plural)] = mod;
|
||||
}
|
||||
|
||||
/** Returns a reference to the modifier; no ownership change. */
|
||||
const Modifier *getModifier(bool isNegative) const {
|
||||
return mods[isNegative ? 1 : 0];
|
||||
const Modifier *getModifier(int8_t signum) const {
|
||||
return mods[signum + 1];
|
||||
}
|
||||
|
||||
/** Returns a reference to the modifier; no ownership change. */
|
||||
const Modifier *getModifier(bool isNegative, StandardPlural::Form plural) const {
|
||||
return mods[getModIndex(isNegative, plural)];
|
||||
const Modifier *getModifier(int8_t signum, StandardPlural::Form plural) const {
|
||||
return mods[getModIndex(signum, plural)];
|
||||
}
|
||||
|
||||
private:
|
||||
const Modifier *mods[2 * StandardPlural::COUNT];
|
||||
const Modifier *mods[3 * StandardPlural::COUNT];
|
||||
|
||||
inline static int32_t getModIndex(bool isNegative, StandardPlural::Form plural) {
|
||||
return static_cast<int32_t>(plural) * 2 + (isNegative ? 1 : 0);
|
||||
inline static int32_t getModIndex(int8_t signum, StandardPlural::Form plural) {
|
||||
return static_cast<int32_t>(plural) * 3 + (signum + 1);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -38,8 +38,8 @@ MutablePatternModifier::setSymbols(const DecimalFormatSymbols *symbols, const Cu
|
||||
this->rules = rules;
|
||||
}
|
||||
|
||||
void MutablePatternModifier::setNumberProperties(bool isNegative, StandardPlural::Form plural) {
|
||||
this->isNegative = isNegative;
|
||||
void MutablePatternModifier::setNumberProperties(int8_t signum, StandardPlural::Form plural) {
|
||||
this->signum = signum;
|
||||
this->plural = plural;
|
||||
}
|
||||
|
||||
@ -74,10 +74,12 @@ MutablePatternModifier::createImmutableAndChain(const MicroPropsGenerator *paren
|
||||
if (needsPlurals()) {
|
||||
// Slower path when we require the plural keyword.
|
||||
for (StandardPlural::Form plural : STANDARD_PLURAL_VALUES) {
|
||||
setNumberProperties(false, plural);
|
||||
pm->adoptSignPluralModifier(false, plural, createConstantModifier(status));
|
||||
setNumberProperties(true, plural);
|
||||
pm->adoptSignPluralModifier(true, plural, createConstantModifier(status));
|
||||
setNumberProperties(1, plural);
|
||||
pm->adoptSignPluralModifier(1, plural, createConstantModifier(status));
|
||||
setNumberProperties(0, plural);
|
||||
pm->adoptSignPluralModifier(0, plural, createConstantModifier(status));
|
||||
setNumberProperties(-1, plural);
|
||||
pm->adoptSignPluralModifier(-1, plural, createConstantModifier(status));
|
||||
}
|
||||
if (U_FAILURE(status)) {
|
||||
delete pm;
|
||||
@ -86,11 +88,13 @@ MutablePatternModifier::createImmutableAndChain(const MicroPropsGenerator *paren
|
||||
return new ImmutablePatternModifier(pm, rules, parent); // adopts pm
|
||||
} else {
|
||||
// Faster path when plural keyword is not needed.
|
||||
setNumberProperties(false, StandardPlural::Form::COUNT);
|
||||
setNumberProperties(1, StandardPlural::Form::COUNT);
|
||||
Modifier *positive = createConstantModifier(status);
|
||||
setNumberProperties(true, StandardPlural::Form::COUNT);
|
||||
setNumberProperties(0, StandardPlural::Form::COUNT);
|
||||
Modifier *zero = createConstantModifier(status);
|
||||
setNumberProperties(-1, StandardPlural::Form::COUNT);
|
||||
Modifier *negative = createConstantModifier(status);
|
||||
pm->adoptPositiveNegativeModifiers(positive, negative);
|
||||
pm->adoptPositiveNegativeModifiers(positive, zero, negative);
|
||||
if (U_FAILURE(status)) {
|
||||
delete pm;
|
||||
return nullptr;
|
||||
@ -123,13 +127,13 @@ void ImmutablePatternModifier::processQuantity(DecimalQuantity &quantity, MicroP
|
||||
|
||||
void ImmutablePatternModifier::applyToMicros(MicroProps µs, DecimalQuantity &quantity) const {
|
||||
if (rules == nullptr) {
|
||||
micros.modMiddle = pm->getModifier(quantity.isNegative());
|
||||
micros.modMiddle = pm->getModifier(quantity.signum());
|
||||
} else {
|
||||
// TODO: Fix this. Avoid the copy.
|
||||
DecimalQuantity copy(quantity);
|
||||
copy.roundToInfinity();
|
||||
StandardPlural::Form plural = copy.getStandardPlural(rules);
|
||||
micros.modMiddle = pm->getModifier(quantity.isNegative(), plural);
|
||||
micros.modMiddle = pm->getModifier(quantity.signum(), plural);
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,9 +153,9 @@ void MutablePatternModifier::processQuantity(DecimalQuantity &fq, MicroProps &mi
|
||||
// TODO: Fix this. Avoid the copy.
|
||||
DecimalQuantity copy(fq);
|
||||
micros.rounding.apply(copy, status);
|
||||
nonConstThis->setNumberProperties(fq.isNegative(), copy.getStandardPlural(rules));
|
||||
nonConstThis->setNumberProperties(fq.signum(), copy.getStandardPlural(rules));
|
||||
} else {
|
||||
nonConstThis->setNumberProperties(fq.isNegative(), StandardPlural::Form::COUNT);
|
||||
nonConstThis->setNumberProperties(fq.signum(), StandardPlural::Form::COUNT);
|
||||
}
|
||||
micros.modMiddle = this;
|
||||
}
|
||||
@ -278,14 +282,17 @@ void MutablePatternModifier::enterCharSequenceMode(bool isPrefix) {
|
||||
inCharSequenceMode = true;
|
||||
|
||||
// Should the output render '+' where '-' would normally appear in the pattern?
|
||||
plusReplacesMinusSign = !isNegative && (
|
||||
signDisplay == UNUM_SIGN_ALWAYS ||
|
||||
signDisplay == UNUM_SIGN_ACCOUNTING_ALWAYS) &&
|
||||
patternInfo->positiveHasPlusSign() == false;
|
||||
plusReplacesMinusSign = signum != -1
|
||||
&& (signDisplay == UNUM_SIGN_ALWAYS
|
||||
|| signDisplay == UNUM_SIGN_ACCOUNTING_ALWAYS
|
||||
|| (signum == 1
|
||||
&& (signDisplay == UNUM_SIGN_EXCEPT_ZERO
|
||||
|| signDisplay == UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO)))
|
||||
&& patternInfo->positiveHasPlusSign() == false;
|
||||
|
||||
// Should we use the affix from the negative subpattern? (If not, we will use the positive subpattern.)
|
||||
bool useNegativeAffixPattern = patternInfo->hasNegativeSubpattern() && (
|
||||
isNegative || (patternInfo->negativeHasMinusSign() && plusReplacesMinusSign));
|
||||
signum == -1 || (patternInfo->negativeHasMinusSign() && plusReplacesMinusSign));
|
||||
|
||||
// Resolve the flags for the affix pattern.
|
||||
fFlags = 0;
|
||||
@ -303,7 +310,7 @@ void MutablePatternModifier::enterCharSequenceMode(bool isPrefix) {
|
||||
// Should we prepend a sign to the pattern?
|
||||
if (!isPrefix || useNegativeAffixPattern) {
|
||||
prependSign = false;
|
||||
} else if (isNegative) {
|
||||
} else if (signum == -1) {
|
||||
prependSign = signDisplay != UNUM_SIGN_NEVER;
|
||||
} else {
|
||||
prependSign = plusReplacesMinusSign;
|
||||
|
@ -125,13 +125,13 @@ class U_I18N_API MutablePatternModifier
|
||||
/**
|
||||
* Sets attributes of the current number being processed.
|
||||
*
|
||||
* @param isNegative
|
||||
* Whether the number is negative.
|
||||
* @param signum
|
||||
* -1 if negative; +1 if positive; or 0 if zero.
|
||||
* @param plural
|
||||
* The plural form of the number, required only if the pattern contains the triple currency sign, "¤¤¤"
|
||||
* (and as indicated by {@link #needsPlurals()}).
|
||||
* The plural form of the number, required only if the pattern contains the triple
|
||||
* currency sign, "¤¤¤" (and as indicated by {@link #needsPlurals()}).
|
||||
*/
|
||||
void setNumberProperties(bool isNegative, StandardPlural::Form plural);
|
||||
void setNumberProperties(int8_t signum, StandardPlural::Form plural);
|
||||
|
||||
/**
|
||||
* Returns true if the pattern represented by this MurkyModifier requires a plural keyword in order to localize.
|
||||
@ -211,7 +211,7 @@ class U_I18N_API MutablePatternModifier
|
||||
const PluralRules *rules;
|
||||
|
||||
// Number details (initialized in setNumberProperties)
|
||||
bool isNegative;
|
||||
int8_t signum;
|
||||
StandardPlural::Form plural;
|
||||
|
||||
// QuantityChain details (initialized in addToChain)
|
||||
|
@ -190,21 +190,22 @@ typedef enum UNumberSignDisplay {
|
||||
*
|
||||
* @draft ICU 60
|
||||
*/
|
||||
UNUM_SIGN_AUTO,
|
||||
UNUM_SIGN_AUTO,
|
||||
|
||||
/**
|
||||
* Show the minus sign on negative numbers and the plus sign on positive numbers.
|
||||
* 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,
|
||||
UNUM_SIGN_ALWAYS,
|
||||
|
||||
/**
|
||||
* Do not show the sign on positive or negative numbers.
|
||||
*
|
||||
* @draft ICU 60
|
||||
*/
|
||||
UNUM_SIGN_NEVER,
|
||||
UNUM_SIGN_NEVER,
|
||||
|
||||
/**
|
||||
* Use the locale-dependent accounting format on negative numbers, and do not show the sign on positive numbers.
|
||||
@ -220,22 +221,41 @@ typedef enum UNumberSignDisplay {
|
||||
*
|
||||
* @draft ICU 60
|
||||
*/
|
||||
UNUM_SIGN_ACCOUNTING,
|
||||
UNUM_SIGN_ACCOUNTING,
|
||||
|
||||
/**
|
||||
* Use the locale-dependent accounting format on negative numbers, and show the plus sign on positive numbers.
|
||||
* For more information on the accounting format, see the ACCOUNTING sign display strategy.
|
||||
* 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,
|
||||
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
|
||||
UNUM_SIGN_COUNT
|
||||
} UNumberSignDisplay;
|
||||
|
||||
/**
|
||||
|
@ -1380,6 +1380,13 @@ void NumberFormatterApiTest::sign() {
|
||||
-444444,
|
||||
u"-444,444");
|
||||
|
||||
assertFormatSingle(
|
||||
u"Sign Auto Zero",
|
||||
NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_AUTO),
|
||||
Locale::getEnglish(),
|
||||
0,
|
||||
u"0");
|
||||
|
||||
assertFormatSingle(
|
||||
u"Sign Always Positive",
|
||||
NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ALWAYS),
|
||||
@ -1394,6 +1401,13 @@ void NumberFormatterApiTest::sign() {
|
||||
-444444,
|
||||
u"-444,444");
|
||||
|
||||
assertFormatSingle(
|
||||
u"Sign Always Zero",
|
||||
NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ALWAYS),
|
||||
Locale::getEnglish(),
|
||||
0,
|
||||
u"+0");
|
||||
|
||||
assertFormatSingle(
|
||||
u"Sign Never Positive",
|
||||
NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_NEVER),
|
||||
@ -1408,6 +1422,13 @@ void NumberFormatterApiTest::sign() {
|
||||
-444444,
|
||||
u"444,444");
|
||||
|
||||
assertFormatSingle(
|
||||
u"Sign Never Zero",
|
||||
NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_NEVER),
|
||||
Locale::getEnglish(),
|
||||
0,
|
||||
u"0");
|
||||
|
||||
assertFormatSingle(
|
||||
u"Sign Accounting Positive",
|
||||
NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING).unit(USD),
|
||||
@ -1422,6 +1443,13 @@ void NumberFormatterApiTest::sign() {
|
||||
-444444,
|
||||
u"($444,444.00)");
|
||||
|
||||
assertFormatSingle(
|
||||
u"Sign Accounting Zero",
|
||||
NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING).unit(USD),
|
||||
Locale::getEnglish(),
|
||||
0,
|
||||
u"$0.00");
|
||||
|
||||
assertFormatSingle(
|
||||
u"Sign Accounting-Always Positive",
|
||||
NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_ALWAYS).unit(USD),
|
||||
@ -1436,6 +1464,55 @@ void NumberFormatterApiTest::sign() {
|
||||
-444444,
|
||||
u"($444,444.00)");
|
||||
|
||||
assertFormatSingle(
|
||||
u"Sign Accounting-Always Zero",
|
||||
NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_ALWAYS).unit(USD),
|
||||
Locale::getEnglish(),
|
||||
0,
|
||||
u"+$0.00");
|
||||
|
||||
assertFormatSingle(
|
||||
u"Sign Except-Zero Positive",
|
||||
NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_EXCEPT_ZERO),
|
||||
Locale::getEnglish(),
|
||||
444444,
|
||||
u"+444,444");
|
||||
|
||||
assertFormatSingle(
|
||||
u"Sign Except-Zero Negative",
|
||||
NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_EXCEPT_ZERO),
|
||||
Locale::getEnglish(),
|
||||
-444444,
|
||||
u"-444,444");
|
||||
|
||||
assertFormatSingle(
|
||||
u"Sign Except-Zero Zero",
|
||||
NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_EXCEPT_ZERO),
|
||||
Locale::getEnglish(),
|
||||
0,
|
||||
u"0");
|
||||
|
||||
assertFormatSingle(
|
||||
u"Sign Accounting-Except-Zero Positive",
|
||||
NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO).unit(USD),
|
||||
Locale::getEnglish(),
|
||||
444444,
|
||||
u"+$444,444.00");
|
||||
|
||||
assertFormatSingle(
|
||||
u"Sign Accounting-Except-Zero Negative",
|
||||
NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO).unit(USD),
|
||||
Locale::getEnglish(),
|
||||
-444444,
|
||||
u"($444,444.00)");
|
||||
|
||||
assertFormatSingle(
|
||||
u"Sign Accounting-Except-Zero Zero",
|
||||
NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO).unit(USD),
|
||||
Locale::getEnglish(),
|
||||
0,
|
||||
u"$0.00");
|
||||
|
||||
assertFormatSingle(
|
||||
u"Sign Accounting Negative Hidden",
|
||||
NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING)
|
||||
|
@ -31,13 +31,19 @@ void PatternModifierTest::testBasic() {
|
||||
assertSuccess("Spot 2", status);
|
||||
mod.setSymbols(&symbols, currency, UNUM_UNIT_WIDTH_SHORT, nullptr);
|
||||
|
||||
mod.setNumberProperties(false, StandardPlural::Form::COUNT);
|
||||
mod.setNumberProperties(1, StandardPlural::Form::COUNT);
|
||||
assertEquals("Pattern a0b", u"a", getPrefix(mod, status));
|
||||
assertEquals("Pattern a0b", u"b", getSuffix(mod, status));
|
||||
mod.setPatternAttributes(UNUM_SIGN_ALWAYS, false);
|
||||
assertEquals("Pattern a0b", u"+a", getPrefix(mod, status));
|
||||
assertEquals("Pattern a0b", u"b", getSuffix(mod, status));
|
||||
mod.setNumberProperties(true, StandardPlural::Form::COUNT);
|
||||
mod.setNumberProperties(0, StandardPlural::Form::COUNT);
|
||||
assertEquals("Pattern a0b", u"+a", getPrefix(mod, status));
|
||||
assertEquals("Pattern a0b", u"b", getSuffix(mod, status));
|
||||
mod.setPatternAttributes(UNUM_SIGN_EXCEPT_ZERO, false);
|
||||
assertEquals("Pattern a0b", u"a", getPrefix(mod, status));
|
||||
assertEquals("Pattern a0b", u"b", getSuffix(mod, status));
|
||||
mod.setNumberProperties(-1, StandardPlural::Form::COUNT);
|
||||
assertEquals("Pattern a0b", u"-a", getPrefix(mod, status));
|
||||
assertEquals("Pattern a0b", u"b", getSuffix(mod, status));
|
||||
mod.setPatternAttributes(UNUM_SIGN_NEVER, false);
|
||||
@ -50,20 +56,24 @@ void PatternModifierTest::testBasic() {
|
||||
assertSuccess("Spot 4", status);
|
||||
mod.setPatternInfo(&patternInfo2);
|
||||
mod.setPatternAttributes(UNUM_SIGN_AUTO, false);
|
||||
mod.setNumberProperties(false, StandardPlural::Form::COUNT);
|
||||
mod.setNumberProperties(1, StandardPlural::Form::COUNT);
|
||||
assertEquals("Pattern a0b;c-0d", u"a", getPrefix(mod, status));
|
||||
assertEquals("Pattern a0b;c-0d", u"b", getSuffix(mod, status));
|
||||
mod.setPatternAttributes(UNUM_SIGN_ALWAYS, false);
|
||||
assertEquals("Pattern a0b;c-0d", u"c+", getPrefix(mod, status));
|
||||
assertEquals("Pattern a0b;c-0d", u"d", getSuffix(mod, status));
|
||||
mod.setNumberProperties(true, StandardPlural::Form::COUNT);
|
||||
mod.setNumberProperties(0, StandardPlural::Form::COUNT);
|
||||
assertEquals("Pattern a0b;c-0d", u"c+", getPrefix(mod, status));
|
||||
assertEquals("Pattern a0b;c-0d", u"d", getSuffix(mod, status));
|
||||
mod.setPatternAttributes(UNUM_SIGN_EXCEPT_ZERO, false);
|
||||
assertEquals("Pattern a0b;c-0d", u"a", getPrefix(mod, status));
|
||||
assertEquals("Pattern a0b;c-0d", u"b", getSuffix(mod, status));
|
||||
mod.setNumberProperties(-1, StandardPlural::Form::COUNT);
|
||||
assertEquals("Pattern a0b;c-0d", u"c-", getPrefix(mod, status));
|
||||
assertEquals("Pattern a0b;c-0d", u"d", getSuffix(mod, status));
|
||||
mod.setPatternAttributes(UNUM_SIGN_NEVER, false);
|
||||
assertEquals(
|
||||
"Pattern a0b;c-0d",
|
||||
u"c-",
|
||||
getPrefix(mod, status)); // TODO: What should this behavior be?
|
||||
// TODO: What should this behavior be?
|
||||
assertEquals("Pattern a0b;c-0d", u"c-", getPrefix(mod, status));
|
||||
assertEquals("Pattern a0b;c-0d", u"d", getSuffix(mod, status));
|
||||
assertSuccess("Spot 5", status);
|
||||
}
|
||||
|
@ -108,6 +108,9 @@ public interface DecimalQuantity extends PluralRules.IFixedDecimal {
|
||||
/** @return Whether the value represented by this {@link DecimalQuantity} is less than zero. */
|
||||
public boolean isNegative();
|
||||
|
||||
/** @return -1 if the value is negative; 1 if positive; or 0 if zero. */
|
||||
public int signum();
|
||||
|
||||
/** @return Whether the value represented by this {@link DecimalQuantity} is infinite. */
|
||||
@Override
|
||||
public boolean isInfinite();
|
||||
|
@ -295,6 +295,11 @@ public abstract class DecimalQuantity_AbstractBCD implements DecimalQuantity {
|
||||
return (flags & NEGATIVE_FLAG) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int signum() {
|
||||
return isNegative() ? -1 : isZero() ? 0 : 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInfinite() {
|
||||
return (flags & INFINITY_FLAG) != 0;
|
||||
|
@ -48,7 +48,7 @@ public class MutablePatternModifier
|
||||
PluralRules rules;
|
||||
|
||||
// Number details
|
||||
boolean isNegative;
|
||||
int signum;
|
||||
StandardPlural plural;
|
||||
|
||||
// QuantityChain details
|
||||
@ -121,15 +121,15 @@ public class MutablePatternModifier
|
||||
/**
|
||||
* Sets attributes of the current number being processed.
|
||||
*
|
||||
* @param isNegative
|
||||
* Whether the number is negative.
|
||||
* @param signum
|
||||
* -1 if negative; +1 if positive; or 0 if zero.
|
||||
* @param plural
|
||||
* The plural form of the number, required only if the pattern contains the triple
|
||||
* currency sign, "¤¤¤" (and as indicated by {@link #needsPlurals()}).
|
||||
*/
|
||||
public void setNumberProperties(boolean isNegative, StandardPlural plural) {
|
||||
public void setNumberProperties(int signum, StandardPlural plural) {
|
||||
assert (plural != null) == needsPlurals();
|
||||
this.isNegative = isNegative;
|
||||
this.signum = signum;
|
||||
this.plural = plural;
|
||||
}
|
||||
|
||||
@ -172,20 +172,24 @@ public class MutablePatternModifier
|
||||
// Slower path when we require the plural keyword.
|
||||
ParameterizedModifier pm = new ParameterizedModifier();
|
||||
for (StandardPlural plural : StandardPlural.VALUES) {
|
||||
setNumberProperties(false, plural);
|
||||
pm.setModifier(false, plural, createConstantModifier(a, b));
|
||||
setNumberProperties(true, plural);
|
||||
pm.setModifier(true, plural, createConstantModifier(a, b));
|
||||
setNumberProperties(1, plural);
|
||||
pm.setModifier(1, plural, createConstantModifier(a, b));
|
||||
setNumberProperties(0, plural);
|
||||
pm.setModifier(0, plural, createConstantModifier(a, b));
|
||||
setNumberProperties(-1, plural);
|
||||
pm.setModifier(-1, plural, createConstantModifier(a, b));
|
||||
}
|
||||
pm.freeze();
|
||||
return new ImmutablePatternModifier(pm, rules, parent);
|
||||
} else {
|
||||
// Faster path when plural keyword is not needed.
|
||||
setNumberProperties(false, null);
|
||||
setNumberProperties(1, null);
|
||||
Modifier positive = createConstantModifier(a, b);
|
||||
setNumberProperties(true, null);
|
||||
setNumberProperties(0, null);
|
||||
Modifier zero = createConstantModifier(a, b);
|
||||
setNumberProperties(-1, null);
|
||||
Modifier negative = createConstantModifier(a, b);
|
||||
ParameterizedModifier pm = new ParameterizedModifier(positive, negative);
|
||||
ParameterizedModifier pm = new ParameterizedModifier(positive, zero, negative);
|
||||
return new ImmutablePatternModifier(pm, null, parent);
|
||||
}
|
||||
}
|
||||
@ -236,13 +240,13 @@ public class MutablePatternModifier
|
||||
|
||||
public void applyToMicros(MicroProps micros, DecimalQuantity quantity) {
|
||||
if (rules == null) {
|
||||
micros.modMiddle = pm.getModifier(quantity.isNegative());
|
||||
micros.modMiddle = pm.getModifier(quantity.signum());
|
||||
} else {
|
||||
// TODO: Fix this. Avoid the copy.
|
||||
DecimalQuantity copy = quantity.createCopy();
|
||||
copy.roundToInfinity();
|
||||
StandardPlural plural = copy.getStandardPlural(rules);
|
||||
micros.modMiddle = pm.getModifier(quantity.isNegative(), plural);
|
||||
micros.modMiddle = pm.getModifier(quantity.signum(), plural);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -260,9 +264,9 @@ public class MutablePatternModifier
|
||||
// TODO: Fix this. Avoid the copy.
|
||||
DecimalQuantity copy = fq.createCopy();
|
||||
micros.rounding.apply(copy);
|
||||
setNumberProperties(fq.isNegative(), copy.getStandardPlural(rules));
|
||||
setNumberProperties(fq.signum(), copy.getStandardPlural(rules));
|
||||
} else {
|
||||
setNumberProperties(fq.isNegative(), null);
|
||||
setNumberProperties(fq.signum(), null);
|
||||
}
|
||||
micros.modMiddle = this;
|
||||
return micros;
|
||||
@ -370,14 +374,18 @@ public class MutablePatternModifier
|
||||
inCharSequenceMode = true;
|
||||
|
||||
// Should the output render '+' where '-' would normally appear in the pattern?
|
||||
plusReplacesMinusSign = !isNegative
|
||||
&& (signDisplay == SignDisplay.ALWAYS || signDisplay == SignDisplay.ACCOUNTING_ALWAYS)
|
||||
plusReplacesMinusSign = signum != -1
|
||||
&& (signDisplay == SignDisplay.ALWAYS
|
||||
|| signDisplay == SignDisplay.ACCOUNTING_ALWAYS
|
||||
|| (signum == 1
|
||||
&& (signDisplay == SignDisplay.EXCEPT_ZERO
|
||||
|| signDisplay == SignDisplay.ACCOUNTING_EXCEPT_ZERO)))
|
||||
&& patternInfo.positiveHasPlusSign() == false;
|
||||
|
||||
// Should we use the affix from the negative subpattern? (If not, we will use the positive
|
||||
// subpattern.)
|
||||
boolean useNegativeAffixPattern = patternInfo.hasNegativeSubpattern()
|
||||
&& (isNegative || (patternInfo.negativeHasMinusSign() && plusReplacesMinusSign));
|
||||
&& (signum == -1 || (patternInfo.negativeHasMinusSign() && plusReplacesMinusSign));
|
||||
|
||||
// Resolve the flags for the affix pattern.
|
||||
flags = 0;
|
||||
@ -395,7 +403,7 @@ public class MutablePatternModifier
|
||||
// Should we prepend a sign to the pattern?
|
||||
if (!isPrefix || useNegativeAffixPattern) {
|
||||
prependSign = false;
|
||||
} else if (isNegative) {
|
||||
} else if (signum == -1) {
|
||||
prependSign = signDisplay != SignDisplay.NEVER;
|
||||
} else {
|
||||
prependSign = plusReplacesMinusSign;
|
||||
|
@ -10,6 +10,7 @@ import com.ibm.icu.impl.StandardPlural;
|
||||
*/
|
||||
public class ParameterizedModifier {
|
||||
private final Modifier positive;
|
||||
private final Modifier zero;
|
||||
private final Modifier negative;
|
||||
final Modifier[] mods;
|
||||
boolean frozen;
|
||||
@ -20,8 +21,9 @@ public class ParameterizedModifier {
|
||||
* <p>
|
||||
* If this constructor is used, a plural form CANNOT be passed to {@link #getModifier}.
|
||||
*/
|
||||
public ParameterizedModifier(Modifier positive, Modifier negative) {
|
||||
public ParameterizedModifier(Modifier positive, Modifier zero, Modifier negative) {
|
||||
this.positive = positive;
|
||||
this.zero = zero;
|
||||
this.negative = negative;
|
||||
this.mods = null;
|
||||
this.frozen = true;
|
||||
@ -36,33 +38,34 @@ public class ParameterizedModifier {
|
||||
*/
|
||||
public ParameterizedModifier() {
|
||||
this.positive = null;
|
||||
this.zero = null;
|
||||
this.negative = null;
|
||||
this.mods = new Modifier[2 * StandardPlural.COUNT];
|
||||
this.mods = new Modifier[3 * StandardPlural.COUNT];
|
||||
this.frozen = false;
|
||||
}
|
||||
|
||||
public void setModifier(boolean isNegative, StandardPlural plural, Modifier mod) {
|
||||
public void setModifier(int signum, StandardPlural plural, Modifier mod) {
|
||||
assert !frozen;
|
||||
mods[getModIndex(isNegative, plural)] = mod;
|
||||
mods[getModIndex(signum, plural)] = mod;
|
||||
}
|
||||
|
||||
public void freeze() {
|
||||
frozen = true;
|
||||
}
|
||||
|
||||
public Modifier getModifier(boolean isNegative) {
|
||||
public Modifier getModifier(int signum) {
|
||||
assert frozen;
|
||||
assert mods == null;
|
||||
return isNegative ? negative : positive;
|
||||
return signum == 0 ? zero : signum < 0 ? negative : positive;
|
||||
}
|
||||
|
||||
public Modifier getModifier(boolean isNegative, StandardPlural plural) {
|
||||
public Modifier getModifier(int signum, StandardPlural plural) {
|
||||
assert frozen;
|
||||
assert positive == null;
|
||||
return mods[getModIndex(isNegative, plural)];
|
||||
return mods[getModIndex(signum, plural)];
|
||||
}
|
||||
|
||||
private static int getModIndex(boolean isNegative, StandardPlural plural) {
|
||||
return plural.ordinal() * 2 + (isNegative ? 1 : 0);
|
||||
private static int getModIndex(int signum, StandardPlural plural) {
|
||||
return plural.ordinal() * 3 + (signum + 1);
|
||||
}
|
||||
}
|
||||
|
@ -191,7 +191,8 @@ public final class NumberFormatter {
|
||||
AUTO,
|
||||
|
||||
/**
|
||||
* Show the minus sign on negative numbers and the plus sign on positive numbers.
|
||||
* Show the minus sign on negative numbers and the plus sign on positive numbers, including zero.
|
||||
* To hide the sign on zero, see {@link #EXCEPT_ZERO}.
|
||||
*
|
||||
* @draft ICU 60
|
||||
* @provisional This API might change or be removed in a future release.
|
||||
@ -229,14 +230,36 @@ public final class NumberFormatter {
|
||||
|
||||
/**
|
||||
* Use the locale-dependent accounting format on negative numbers, and show the plus sign on
|
||||
* positive numbers. For more information on the accounting format, see the ACCOUNTING sign
|
||||
* display strategy.
|
||||
* 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 #ACCOUNTING_EXCEPT_ZERO}.
|
||||
*
|
||||
* @draft ICU 60
|
||||
* @provisional This API might change or be removed in a future release.
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
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
|
||||
* @provisional This API might change or be removed in a future release.
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
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
|
||||
* @provisional This API might change or be removed in a future release.
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
ACCOUNTING_EXCEPT_ZERO,
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -115,7 +115,8 @@ class NumberFormatterImpl {
|
||||
boolean isPermille = isNoUnit && unitIsPermille(macros.unit);
|
||||
boolean isCldrUnit = !isCurrency && !isNoUnit;
|
||||
boolean isAccounting = macros.sign == SignDisplay.ACCOUNTING
|
||||
|| macros.sign == SignDisplay.ACCOUNTING_ALWAYS;
|
||||
|| macros.sign == SignDisplay.ACCOUNTING_ALWAYS
|
||||
|| macros.sign == SignDisplay.ACCOUNTING_EXCEPT_ZERO;
|
||||
Currency currency = isCurrency ? (Currency) macros.unit : DEFAULT_CURRENCY;
|
||||
UnitWidth unitWidth = UnitWidth.SHORT;
|
||||
if (macros.unitWidth != null) {
|
||||
|
@ -503,6 +503,11 @@ public class DecimalQuantity_SimpleStorage implements DecimalQuantity {
|
||||
return (flags & NEGATIVE_FLAG) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int signum() {
|
||||
return isNegative() ? -1 : isZero() ? 0 : 1;
|
||||
}
|
||||
|
||||
private void setNegative(boolean isNegative) {
|
||||
flags = (flags & (~NEGATIVE_FLAG)) | (isNegative ? NEGATIVE_FLAG : 0);
|
||||
}
|
||||
|
@ -32,13 +32,19 @@ public class MutablePatternModifierTest {
|
||||
UnitWidth.SHORT,
|
||||
null);
|
||||
|
||||
mod.setNumberProperties(false, null);
|
||||
mod.setNumberProperties(1, null);
|
||||
assertEquals("a", getPrefix(mod));
|
||||
assertEquals("b", getSuffix(mod));
|
||||
mod.setPatternAttributes(SignDisplay.ALWAYS, false);
|
||||
assertEquals("+a", getPrefix(mod));
|
||||
assertEquals("b", getSuffix(mod));
|
||||
mod.setNumberProperties(true, null);
|
||||
mod.setNumberProperties(0, null);
|
||||
assertEquals("+a", getPrefix(mod));
|
||||
assertEquals("b", getSuffix(mod));
|
||||
mod.setPatternAttributes(SignDisplay.EXCEPT_ZERO, false);
|
||||
assertEquals("a", getPrefix(mod));
|
||||
assertEquals("b", getSuffix(mod));
|
||||
mod.setNumberProperties(-1, null);
|
||||
assertEquals("-a", getPrefix(mod));
|
||||
assertEquals("b", getSuffix(mod));
|
||||
mod.setPatternAttributes(SignDisplay.NEVER, false);
|
||||
@ -47,13 +53,19 @@ public class MutablePatternModifierTest {
|
||||
|
||||
mod.setPatternInfo(PatternStringParser.parseToPatternInfo("a0b;c-0d"));
|
||||
mod.setPatternAttributes(SignDisplay.AUTO, false);
|
||||
mod.setNumberProperties(false, null);
|
||||
mod.setNumberProperties(1, null);
|
||||
assertEquals("a", getPrefix(mod));
|
||||
assertEquals("b", getSuffix(mod));
|
||||
mod.setPatternAttributes(SignDisplay.ALWAYS, false);
|
||||
assertEquals("c+", getPrefix(mod));
|
||||
assertEquals("d", getSuffix(mod));
|
||||
mod.setNumberProperties(true, null);
|
||||
mod.setNumberProperties(0, null);
|
||||
assertEquals("c+", getPrefix(mod));
|
||||
assertEquals("d", getSuffix(mod));
|
||||
mod.setPatternAttributes(SignDisplay.EXCEPT_ZERO, false);
|
||||
assertEquals("a", getPrefix(mod));
|
||||
assertEquals("b", getSuffix(mod));
|
||||
mod.setNumberProperties(-1, null);
|
||||
assertEquals("c-", getPrefix(mod));
|
||||
assertEquals("d", getSuffix(mod));
|
||||
mod.setPatternAttributes(SignDisplay.NEVER, false);
|
||||
|
@ -1477,6 +1477,14 @@ public class NumberFormatterApiTest {
|
||||
-444444,
|
||||
"-444,444");
|
||||
|
||||
assertFormatSingle(
|
||||
"Sign Auto Zero",
|
||||
"",
|
||||
NumberFormatter.with().sign(SignDisplay.AUTO),
|
||||
ULocale.ENGLISH,
|
||||
0,
|
||||
"0");
|
||||
|
||||
assertFormatSingle(
|
||||
"Sign Always Positive",
|
||||
"sign=ALWAYS",
|
||||
@ -1493,6 +1501,14 @@ public class NumberFormatterApiTest {
|
||||
-444444,
|
||||
"-444,444");
|
||||
|
||||
assertFormatSingle(
|
||||
"Sign Always Zero",
|
||||
"",
|
||||
NumberFormatter.with().sign(SignDisplay.ALWAYS),
|
||||
ULocale.ENGLISH,
|
||||
0,
|
||||
"+0");
|
||||
|
||||
assertFormatSingle(
|
||||
"Sign Never Positive",
|
||||
"sign=NEVER",
|
||||
@ -1509,6 +1525,14 @@ public class NumberFormatterApiTest {
|
||||
-444444,
|
||||
"444,444");
|
||||
|
||||
assertFormatSingle(
|
||||
"Sign Never Zero",
|
||||
"",
|
||||
NumberFormatter.with().sign(SignDisplay.NEVER),
|
||||
ULocale.ENGLISH,
|
||||
0,
|
||||
"0");
|
||||
|
||||
assertFormatSingle(
|
||||
"Sign Accounting Positive",
|
||||
"$USD sign=ACCOUNTING",
|
||||
@ -1525,6 +1549,14 @@ public class NumberFormatterApiTest {
|
||||
-444444,
|
||||
"($444,444.00)");
|
||||
|
||||
assertFormatSingle(
|
||||
"Sign Accounting Zero",
|
||||
"",
|
||||
NumberFormatter.with().sign(SignDisplay.ACCOUNTING).unit(USD),
|
||||
ULocale.ENGLISH,
|
||||
0,
|
||||
"$0.00");
|
||||
|
||||
assertFormatSingle(
|
||||
"Sign Accounting-Always Positive",
|
||||
"$USD sign=ACCOUNTING_ALWAYS",
|
||||
@ -1541,6 +1573,62 @@ public class NumberFormatterApiTest {
|
||||
-444444,
|
||||
"($444,444.00)");
|
||||
|
||||
assertFormatSingle(
|
||||
"Sign Accounting-Always Zero",
|
||||
"",
|
||||
NumberFormatter.with().sign(SignDisplay.ACCOUNTING_ALWAYS).unit(USD),
|
||||
ULocale.ENGLISH,
|
||||
0,
|
||||
"+$0.00");
|
||||
|
||||
assertFormatSingle(
|
||||
"Sign Except-Zero Positive",
|
||||
"",
|
||||
NumberFormatter.with().sign(SignDisplay.EXCEPT_ZERO),
|
||||
ULocale.ENGLISH,
|
||||
444444,
|
||||
"+444,444");
|
||||
|
||||
assertFormatSingle(
|
||||
"Sign Always Negative",
|
||||
"",
|
||||
NumberFormatter.with().sign(SignDisplay.EXCEPT_ZERO),
|
||||
ULocale.ENGLISH,
|
||||
-444444,
|
||||
"-444,444");
|
||||
|
||||
assertFormatSingle(
|
||||
"Sign Except-Zero Zero",
|
||||
"",
|
||||
NumberFormatter.with().sign(SignDisplay.EXCEPT_ZERO),
|
||||
ULocale.ENGLISH,
|
||||
0,
|
||||
"0");
|
||||
|
||||
assertFormatSingle(
|
||||
"Sign Accounting-Except-Zero Positive",
|
||||
"$USD sign=ACCOUNTING_ALWAYS",
|
||||
NumberFormatter.with().sign(SignDisplay.ACCOUNTING_EXCEPT_ZERO).unit(USD),
|
||||
ULocale.ENGLISH,
|
||||
444444,
|
||||
"+$444,444.00");
|
||||
|
||||
assertFormatSingle(
|
||||
"Sign Accounting-Except-Zero Negative",
|
||||
"$USD sign=ACCOUNTING_ALWAYS",
|
||||
NumberFormatter.with().sign(SignDisplay.ACCOUNTING_EXCEPT_ZERO).unit(USD),
|
||||
ULocale.ENGLISH,
|
||||
-444444,
|
||||
"($444,444.00)");
|
||||
|
||||
assertFormatSingle(
|
||||
"Sign Accounting-Except-Zero Zero",
|
||||
"",
|
||||
NumberFormatter.with().sign(SignDisplay.ACCOUNTING_EXCEPT_ZERO).unit(USD),
|
||||
ULocale.ENGLISH,
|
||||
0,
|
||||
"$0.00");
|
||||
|
||||
assertFormatSingle(
|
||||
"Sign Accounting Negative Hidden",
|
||||
"$USD unit-width=HIDDEN sign=ACCOUNTING",
|
||||
|
Loading…
Reference in New Issue
Block a user