ICU-13551 Adding EXCEPT_ZERO enum value to SignDisplay.

X-SVN-Rev: 40824
This commit is contained in:
Shane Carr 2018-01-30 02:49:07 +00:00
parent a7c4b0a3a8
commit 3dce9dcab9
18 changed files with 366 additions and 94 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -161,8 +161,9 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps &macros, 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

View File

@ -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);
}
};

View File

@ -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 &micros, 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;

View File

@ -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)

View File

@ -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;
/**

View File

@ -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)

View File

@ -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);
}

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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,
}
/**

View File

@ -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) {

View File

@ -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);
}

View File

@ -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);

View File

@ -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",