#if U_DEBUG
# include <assert.h>
# define U_ASSERT(exp) assert(exp)
+#elif U_CPLUSPLUS_VERSION
+# define U_ASSERT(exp) void()
#else
# define U_ASSERT(exp)
#endif
#include "formatted_string_builder.h"
#include "unicode/ustring.h"
#include "unicode/utf16.h"
+#include "unicode/unum.h" // for UNumberFormatFields literals
namespace {
return;
}
getCharPtr()[position] = 0;
- getFieldPtr()[position] = UNUM_FIELD_COUNT;
+ getFieldPtr()[position] = kUndefinedField;
fLength--;
}
sb.append(toUnicodeString());
sb.append(u"] [", -1);
for (int i = 0; i < fLength; i++) {
- if (fieldAt(i) == UNUM_FIELD_COUNT) {
+ if (fieldAt(i) == kUndefinedField) {
sb.append(u'n');
- } else {
+ } else if (fieldAt(i).getCategory() == UFIELD_CATEGORY_NUMBER) {
char16_t c;
- switch (fieldAt(i)) {
+ switch (fieldAt(i).getField()) {
case UNUM_SIGN_FIELD:
c = u'-';
break;
c = u'$';
break;
default:
- c = u'?';
+ c = u'0' + fieldAt(i).getField();
break;
}
sb.append(c);
+ } else {
+ sb.append(u'0' + fieldAt(i).getCategory());
}
}
sb.append(u"]>", -1);
#include <cstdint>
-#include "unicode/unum.h" // for UNUM_FIELD_COUNT
+#include <type_traits>
+
#include "cstring.h"
#include "uassert.h"
#include "fphdlimp.h"
// Field category 0 implies the number category so that the number field
// literals can be directly passed as a Field type.
// See the helper functions in "StringBuilderFieldUtils" below.
- typedef uint8_t Field;
+ // Exported as U_I18N_API so it can be used by other exports on Windows.
+ struct U_I18N_API Field {
+ uint8_t bits;
+
+ Field() = default;
+ constexpr Field(uint8_t category, uint8_t field);
+
+ inline UFieldCategory getCategory() const;
+ inline int32_t getField() const;
+ inline bool isNumeric() const;
+ inline bool isUndefined() const;
+ inline bool operator==(const Field& other) const;
+ inline bool operator!=(const Field& other) const;
+ };
FormattedStringBuilder &operator=(const FormattedStringBuilder &other);
friend class FormattedValueStringBuilderImpl;
};
+static_assert(
+ std::is_pod<FormattedStringBuilder::Field>::value,
+ "Field should be a POD type for efficient initialization");
+
+constexpr FormattedStringBuilder::Field::Field(uint8_t category, uint8_t field)
+ : bits((
+ U_ASSERT(category <= 0xf),
+ U_ASSERT(field <= 0xf),
+ static_cast<uint8_t>((category << 4) | field)
+ )) {}
+
/**
- * Helper functions for dealing with the Field typedef, which stores fields
- * in a compressed format.
+ * Internal constant for the undefined field for use in FormattedStringBuilder.
*/
-class StringBuilderFieldUtils {
-public:
- struct CategoryFieldPair {
- int32_t category;
- int32_t field;
- };
+constexpr FormattedStringBuilder::Field kUndefinedField = {UFIELD_CATEGORY_UNDEFINED, 0};
- /** Compile-time function to construct a Field from a category and a field */
- template <int32_t category, int32_t field>
- static constexpr FormattedStringBuilder::Field compress() {
- static_assert(category != 0, "cannot use Undefined category in FieldUtils");
- static_assert(category <= 0xf, "only 4 bits for category");
- static_assert(field <= 0xf, "only 4 bits for field");
- return static_cast<int8_t>((category << 4) | field);
- }
+/**
+ * Internal field to signal "numeric" when fields are not supported in NumberFormat.
+ */
+constexpr FormattedStringBuilder::Field kGeneralNumericField = {UFIELD_CATEGORY_UNDEFINED, 1};
- /** Runtime inline function to unpack the category and field from the Field */
- static inline CategoryFieldPair expand(FormattedStringBuilder::Field field) {
- if (field == UNUM_FIELD_COUNT) {
- return {UFIELD_CATEGORY_UNDEFINED, 0};
- }
- CategoryFieldPair ret = {
- (field >> 4),
- (field & 0xf)
- };
- if (ret.category == 0) {
- ret.category = UFIELD_CATEGORY_NUMBER;
- }
- return ret;
- }
+inline UFieldCategory FormattedStringBuilder::Field::getCategory() const {
+ return static_cast<UFieldCategory>(bits >> 4);
+}
- static inline bool isNumericField(FormattedStringBuilder::Field field) {
- int8_t category = field >> 4;
- return category == 0 || category == UFIELD_CATEGORY_NUMBER;
- }
-};
+inline int32_t FormattedStringBuilder::Field::getField() const {
+ return bits & 0xf;
+}
+
+inline bool FormattedStringBuilder::Field::isNumeric() const {
+ return getCategory() == UFIELD_CATEGORY_NUMBER || *this == kGeneralNumericField;
+}
+
+inline bool FormattedStringBuilder::Field::isUndefined() const {
+ return getCategory() == UFIELD_CATEGORY_UNDEFINED;
+}
+
+inline bool FormattedStringBuilder::Field::operator==(const Field& other) const {
+ return bits == other.bits;
+}
+
+inline bool FormattedStringBuilder::Field::operator!=(const Field& other) const {
+ return bits != other.bits;
+}
U_NAMESPACE_END
bool nextPositionImpl(ConstrainedFieldPosition& cfpos, FormattedStringBuilder::Field numericField, UErrorCode& status) const;
static bool isIntOrGroup(FormattedStringBuilder::Field field);
- static bool isNumericField(FormattedStringBuilder::Field field);
int32_t trimBack(int32_t limit) const;
int32_t trimFront(int32_t start) const;
};
ConstrainedFieldPosition cfpos;
cfpos.constrainField(UFIELD_CATEGORY_NUMBER, rawField);
cfpos.setState(UFIELD_CATEGORY_NUMBER, rawField, fp.getBeginIndex(), fp.getEndIndex());
- if (nextPositionImpl(cfpos, 0, status)) {
+ if (nextPositionImpl(cfpos, kUndefinedField, status)) {
fp.setBeginIndex(cfpos.getStart());
fp.setEndIndex(cfpos.getLimit());
return TRUE;
bool inside = false;
int32_t i = fString.fZero;
for (; i < fString.fZero + fString.fLength; i++) {
- if (isIntOrGroup(fString.getFieldPtr()[i]) || fString.getFieldPtr()[i] == UNUM_DECIMAL_SEPARATOR_FIELD) {
+ if (isIntOrGroup(fString.getFieldPtr()[i]) || fString.getFieldPtr()[i] == Field(UFIELD_CATEGORY_NUMBER, UNUM_DECIMAL_SEPARATOR_FIELD)) {
inside = true;
} else if (inside) {
break;
void FormattedValueStringBuilderImpl::getAllFieldPositions(FieldPositionIteratorHandler& fpih,
UErrorCode& status) const {
ConstrainedFieldPosition cfpos;
- while (nextPositionImpl(cfpos, 0, status)) {
+ while (nextPositionImpl(cfpos, kUndefinedField, status)) {
fpih.addAttribute(cfpos.getField(), cfpos.getStart(), cfpos.getLimit());
}
}
// Signal the end of the string using a field that doesn't exist and that is
-// different from UNUM_FIELD_COUNT, which is used for "null number field".
-static constexpr Field kEndField = 0xff;
+// different from kUndefinedField, which is used for "null field".
+static constexpr Field kEndField = Field(0xf, 0xf);
bool FormattedValueStringBuilderImpl::nextPositionImpl(ConstrainedFieldPosition& cfpos, Field numericField, UErrorCode& /*status*/) const {
- auto numericCAF = StringBuilderFieldUtils::expand(numericField);
int32_t fieldStart = -1;
- Field currField = UNUM_FIELD_COUNT;
+ Field currField = kUndefinedField;
for (int32_t i = fString.fZero + cfpos.getLimit(); i <= fString.fZero + fString.fLength; i++) {
Field _field = (i < fString.fZero + fString.fLength) ? fString.getFieldPtr()[i] : kEndField;
// Case 1: currently scanning a field.
- if (currField != UNUM_FIELD_COUNT) {
+ if (currField != kUndefinedField) {
if (currField != _field) {
int32_t end = i - fString.fZero;
// Grouping separators can be whitespace; don't throw them out!
- if (currField != UNUM_GROUPING_SEPARATOR_FIELD) {
+ if (currField != Field(UFIELD_CATEGORY_NUMBER, UNUM_GROUPING_SEPARATOR_FIELD)) {
end = trimBack(i - fString.fZero);
}
if (end <= fieldStart) {
// Entire field position is ignorable; skip.
fieldStart = -1;
- currField = UNUM_FIELD_COUNT;
+ currField = kUndefinedField;
i--; // look at this index again
continue;
}
int32_t start = fieldStart;
- if (currField != UNUM_GROUPING_SEPARATOR_FIELD) {
+ if (currField != Field(UFIELD_CATEGORY_NUMBER, UNUM_GROUPING_SEPARATOR_FIELD)) {
start = trimFront(start);
}
- auto caf = StringBuilderFieldUtils::expand(currField);
- cfpos.setState(caf.category, caf.field, start, end);
+ cfpos.setState(currField.getCategory(), currField.getField(), start, end);
return true;
}
continue;
return true;
}
// Special case: coalesce NUMERIC if we are pointing at the end of the NUMERIC.
- if (numericField != 0
- && cfpos.matchesField(numericCAF.category, numericCAF.field)
+ if (numericField != kUndefinedField
+ && cfpos.matchesField(numericField.getCategory(), numericField.getField())
&& i > fString.fZero
// don't return the same field twice in a row:
&& (i - fString.fZero > cfpos.getLimit()
- || cfpos.getCategory() != numericCAF.category
- || cfpos.getField() != numericCAF.field)
- && isNumericField(fString.getFieldPtr()[i - 1])
- && !isNumericField(_field)) {
+ || cfpos.getCategory() != numericField.getCategory()
+ || cfpos.getField() != numericField.getField())
+ && fString.getFieldPtr()[i - 1].isNumeric()
+ && !_field.isNumeric()) {
int j = i - 1;
- for (; j >= fString.fZero && isNumericField(fString.getFieldPtr()[j]); j--) {}
+ for (; j >= fString.fZero && fString.getFieldPtr()[j].isNumeric(); j--) {}
cfpos.setState(
- numericCAF.category,
- numericCAF.field,
+ numericField.getCategory(),
+ numericField.getField(),
j - fString.fZero + 1,
i - fString.fZero);
return true;
}
// Special case: skip over INTEGER; will be coalesced later.
- if (_field == UNUM_INTEGER_FIELD) {
- _field = UNUM_FIELD_COUNT;
+ if (_field == Field(UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD)) {
+ _field = kUndefinedField;
}
// Case 2: no field starting at this position.
- if (_field == UNUM_FIELD_COUNT || _field == kEndField) {
+ if (_field.isUndefined() || _field == kEndField) {
continue;
}
// Case 3: check for field starting at this position
- auto caf = StringBuilderFieldUtils::expand(_field);
- if (cfpos.matchesField(caf.category, caf.field)) {
+ if (cfpos.matchesField(_field.getCategory(), _field.getField())) {
fieldStart = i - fString.fZero;
currField = _field;
}
}
- U_ASSERT(currField == UNUM_FIELD_COUNT);
+ U_ASSERT(currField == kUndefinedField);
return false;
}
bool FormattedValueStringBuilderImpl::isIntOrGroup(Field field) {
- return field == UNUM_INTEGER_FIELD
- || field == UNUM_GROUPING_SEPARATOR_FIELD;
-}
-
-bool FormattedValueStringBuilderImpl::isNumericField(Field field) {
- return StringBuilderFieldUtils::isNumericField(field);
+ return field == Field(UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD)
+ || field == Field(UFIELD_CATEGORY_NUMBER, UNUM_GROUPING_SEPARATOR_FIELD);
}
int32_t FormattedValueStringBuilderImpl::trimBack(int32_t limit) const {
case u's': value = seconds; break;
}
- // For undefined field we use UNUM_FIELD_COUNT, for historical reasons.
- // See cleanup bug: https://unicode-org.atlassian.net/browse/ICU-20665
- // But we give it a clear name, to keep "the ugly part" in one place.
- constexpr UNumberFormatFields undefinedField = UNUM_FIELD_COUNT;
-
// There is not enough info to add Field(s) for the unit because all we have are plain
// text patterns. For example in "21:51" there is no text for something like "hour",
// while in something like "21h51" there is ("h"). But we can't really tell...
case u'm':
case u's':
if (protect) {
- fsb.appendChar16(c, undefinedField, status);
+ fsb.appendChar16(c, kUndefinedField, status);
} else {
UnicodeString tmp;
if ((i + 1 < patternLength) && pattern[i + 1] == c) { // doubled
numberFormatter->format(value, tmp, status);
}
// TODO: Use proper Field
- fsb.append(tmp, undefinedField, status);
+ fsb.append(tmp, kUndefinedField, status);
}
break;
case u'\'':
// '' is escaped apostrophe
if ((i + 1 < patternLength) && pattern[i + 1] == c) {
- fsb.appendChar16(c, undefinedField, status);
+ fsb.appendChar16(c, kUndefinedField, status);
i++;
} else {
protect = !protect;
}
break;
default:
- fsb.appendChar16(c, undefinedField, status);
+ fsb.appendChar16(c, kUndefinedField, status);
}
}
Field AffixUtils::getFieldForType(AffixPatternType type) {
switch (type) {
case TYPE_MINUS_SIGN:
- return UNUM_SIGN_FIELD;
+ return {UFIELD_CATEGORY_NUMBER, UNUM_SIGN_FIELD};
case TYPE_PLUS_SIGN:
- return UNUM_SIGN_FIELD;
+ return {UFIELD_CATEGORY_NUMBER, UNUM_SIGN_FIELD};
case TYPE_PERCENT:
- return UNUM_PERCENT_FIELD;
+ return {UFIELD_CATEGORY_NUMBER, UNUM_PERCENT_FIELD};
case TYPE_PERMILLE:
- return UNUM_PERMILL_FIELD;
+ return {UFIELD_CATEGORY_NUMBER, UNUM_PERMILL_FIELD};
case TYPE_CURRENCY_SINGLE:
- return UNUM_CURRENCY_FIELD;
+ return {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD};
case TYPE_CURRENCY_DOUBLE:
- return UNUM_CURRENCY_FIELD;
+ return {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD};
case TYPE_CURRENCY_TRIPLE:
- return UNUM_CURRENCY_FIELD;
+ return {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD};
case TYPE_CURRENCY_QUAD:
- return UNUM_CURRENCY_FIELD;
+ return {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD};
case TYPE_CURRENCY_QUINT:
- return UNUM_CURRENCY_FIELD;
+ return {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD};
case TYPE_CURRENCY_OVERFLOW:
- return UNUM_CURRENCY_FIELD;
+ return {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD};
default:
UPRV_UNREACHABLE;
}
if (U_FAILURE(status)) { return length; }
if (tag.type == TYPE_CURRENCY_OVERFLOW) {
// Don't go to the provider for this special case
- length += output.insertCodePoint(position + length, 0xFFFD, UNUM_CURRENCY_FIELD, status);
+ length += output.insertCodePoint(
+ position + length,
+ 0xFFFD,
+ {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD},
+ status);
} else if (tag.type < 0) {
length += output.insert(
position + length, provider.getSymbol(tag.type), getFieldForType(tag.type), status);
while (hasNext(tag, affixPattern)) {
tag = nextToken(tag, affixPattern, status);
if (U_FAILURE(status)) { return false; }
- if (tag.type < 0 && getFieldForType(tag.type) == UNUM_CURRENCY_FIELD) {
+ if (tag.type < 0 && getFieldForType(tag.type) == Field(UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD)) {
return true;
}
}
ParsedPatternInfo patternInfo;
PatternParser::parseToPatternInfo(UnicodeString(patternString), patternInfo, status);
if (U_FAILURE(status)) { return; }
- buildReference.setPatternInfo(&patternInfo, UNUM_COMPACT_FIELD);
+ buildReference.setPatternInfo(&patternInfo, {UFIELD_CATEGORY_NUMBER, UNUM_COMPACT_FIELD});
info.mod = buildReference.createImmutable(status);
if (U_FAILURE(status)) { return; }
info.patternString = patternString;
// C++ Note: Use unsafePatternInfo for proper lifecycle.
ParsedPatternInfo &patternInfo = const_cast<CompactHandler *>(this)->unsafePatternInfo;
PatternParser::parseToPatternInfo(UnicodeString(patternString), patternInfo, status);
- unsafePatternModifier->setPatternInfo(&unsafePatternInfo, UNUM_COMPACT_FIELD);
+ unsafePatternModifier->setPatternInfo(
+ &unsafePatternInfo,
+ {UFIELD_CATEGORY_NUMBER, UNUM_COMPACT_FIELD});
unsafePatternModifier->setNumberProperties(quantity.signum(), StandardPlural::Form::COUNT);
micros.modMiddle = unsafePatternModifier;
}
patternModifier->setPatternInfo(
macros.affixProvider != nullptr ? macros.affixProvider
: static_cast<const AffixPatternProvider*>(fPatternInfo.getAlias()),
- UNUM_FIELD_COUNT);
+ kUndefinedField);
patternModifier->setPatternAttributes(fMicros.sign, isPermille);
if (patternModifier->needsPlurals()) {
patternModifier->setSymbols(
length += string.insert(
length + index,
micros.symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kInfinitySymbol),
- UNUM_INTEGER_FIELD,
+ {UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD},
status);
} else if (quantity.isNaN()) {
length += string.insert(
length + index,
micros.symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kNaNSymbol),
- UNUM_INTEGER_FIELD,
+ {UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD},
status);
} else {
.symbols
->getSymbol(
DecimalFormatSymbols::ENumberFormatSymbol::kDecimalSeparatorSymbol),
- UNUM_DECIMAL_SEPARATOR_FIELD,
+ {UFIELD_CATEGORY_NUMBER, UNUM_DECIMAL_SEPARATOR_FIELD},
status);
}
if (length == 0) {
// Force output of the digit for value 0
length += utils::insertDigitFromSymbols(
- string, index, 0, *micros.symbols, UNUM_INTEGER_FIELD, status);
+ string,
+ index,
+ 0,
+ *micros.symbols,
+ {UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD},
+ status);
}
}
DecimalFormatSymbols::ENumberFormatSymbol::kMonetaryGroupingSeparatorSymbol)
: micros.symbols->getSymbol(
DecimalFormatSymbols::ENumberFormatSymbol::kGroupingSeparatorSymbol),
- UNUM_GROUPING_SEPARATOR_FIELD,
+ {UFIELD_CATEGORY_NUMBER, UNUM_GROUPING_SEPARATOR_FIELD},
status);
}
// Get and append the next digit value
int8_t nextDigit = quantity.getDigit(i);
length += utils::insertDigitFromSymbols(
- string, index, nextDigit, *micros.symbols, UNUM_INTEGER_FIELD, status);
+ string,
+ index,
+ nextDigit,
+ *micros.symbols,
+ {UFIELD_CATEGORY_NUMBER,
+ UNUM_INTEGER_FIELD},
+ status);
}
return length;
}
// Get and append the next digit value
int8_t nextDigit = quantity.getDigit(-i - 1);
length += utils::insertDigitFromSymbols(
- string, length + index, nextDigit, *micros.symbols, UNUM_FRACTION_FIELD, status);
+ string,
+ length + index,
+ nextDigit,
+ *micros.symbols,
+ {UFIELD_CATEGORY_NUMBER, UNUM_FRACTION_FIELD},
+ status);
}
return length;
}
UnicodeString simpleFormats[ARRAY_LENGTH];
getMeasureData(loc, unit, width, simpleFormats, status);
if (U_FAILURE(status)) { return result; }
- result->simpleFormatsToModifiers(simpleFormats, UNUM_MEASURE_UNIT_FIELD, status);
+ result->simpleFormatsToModifiers(simpleFormats, {UFIELD_CATEGORY_NUMBER, UNUM_MEASURE_UNIT_FIELD}, status);
return result;
}
compiled.format(UnicodeString(u"{0}"), secondaryString, perUnitFormat, status);
if (U_FAILURE(status)) { return result; }
}
- result->multiSimpleFormatsToModifiers(primaryData, perUnitFormat, UNUM_MEASURE_UNIT_FIELD, status);
+ result->multiSimpleFormatsToModifiers(primaryData, perUnitFormat, {UFIELD_CATEGORY_NUMBER, UNUM_MEASURE_UNIT_FIELD}, status);
return result;
}
UnicodeString simpleFormats[ARRAY_LENGTH];
getCurrencyLongNameData(loc, currency, simpleFormats, status);
if (U_FAILURE(status)) { return nullptr; }
- result->simpleFormatsToModifiers(simpleFormats, UNUM_CURRENCY_FIELD, status);
+ result->simpleFormatsToModifiers(simpleFormats, {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD}, status);
return result;
}
return fStrong;
}
-bool ConstantAffixModifier::containsField(UNumberFormatFields field) const {
+bool ConstantAffixModifier::containsField(Field field) const {
(void)field;
// This method is not currently used.
UPRV_UNREACHABLE;
}
SimpleModifier::SimpleModifier()
- : fField(UNUM_FIELD_COUNT), fStrong(false), fPrefixLength(0), fSuffixLength(0) {
+ : fField(kUndefinedField), fStrong(false), fPrefixLength(0), fSuffixLength(0) {
}
int32_t SimpleModifier::apply(FormattedStringBuilder &output, int leftIndex, int rightIndex,
return fStrong;
}
-bool SimpleModifier::containsField(UNumberFormatFields field) const {
+bool SimpleModifier::containsField(Field field) const {
(void)field;
// This method is not currently used.
UPRV_UNREACHABLE;
leftIndex + length,
rightIndex + length,
UnicodeString(), 0, 0,
- UNUM_FIELD_COUNT, status);
+ kUndefinedField, status);
}
length += output.insert(rightIndex + length, fSuffix, status);
return length;
return fStrong;
}
-bool ConstantMultiFieldModifier::containsField(UNumberFormatFields field) const {
+bool ConstantMultiFieldModifier::containsField(Field field) const {
return fPrefix.containsField(field) || fSuffix.containsField(field);
}
: ConstantMultiFieldModifier(prefix, suffix, overwrite, strong) {
// Check for currency spacing. Do not build the UnicodeSets unless there is
// a currency code point at a boundary.
- if (prefix.length() > 0 && prefix.fieldAt(prefix.length() - 1) == UNUM_CURRENCY_FIELD) {
+ if (prefix.length() > 0 && prefix.fieldAt(prefix.length() - 1) == Field(UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD)) {
int prefixCp = prefix.getLastCodePoint();
UnicodeSet prefixUnicodeSet = getUnicodeSet(symbols, IN_CURRENCY, PREFIX, status);
if (prefixUnicodeSet.contains(prefixCp)) {
fAfterPrefixUnicodeSet.setToBogus();
fAfterPrefixInsert.setToBogus();
}
- if (suffix.length() > 0 && suffix.fieldAt(0) == UNUM_CURRENCY_FIELD) {
+ if (suffix.length() > 0 && suffix.fieldAt(0) == Field(UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD)) {
int suffixCp = suffix.getLastCodePoint();
UnicodeSet suffixUnicodeSet = getUnicodeSet(symbols, IN_CURRENCY, SUFFIX, status);
if (suffixUnicodeSet.contains(suffixCp)) {
if (rightIndex - leftIndex > 0 && !fAfterPrefixUnicodeSet.isBogus() &&
fAfterPrefixUnicodeSet.contains(output.codePointAt(leftIndex))) {
// TODO: Should we use the CURRENCY field here?
- length += output.insert(leftIndex, fAfterPrefixInsert, UNUM_FIELD_COUNT, status);
+ length += output.insert(
+ leftIndex,
+ fAfterPrefixInsert,
+ kUndefinedField,
+ status);
}
if (rightIndex - leftIndex > 0 && !fBeforeSuffixUnicodeSet.isBogus() &&
fBeforeSuffixUnicodeSet.contains(output.codePointBefore(rightIndex))) {
// TODO: Should we use the CURRENCY field here?
- length += output.insert(rightIndex + length, fBeforeSuffixInsert, UNUM_FIELD_COUNT, status);
+ length += output.insert(
+ rightIndex + length,
+ fBeforeSuffixInsert,
+ kUndefinedField,
+ status);
}
// Call super for the remaining logic
// This works even if the last code point in the prefix is 2 code units because the
// field value gets populated to both indices in the field array.
Field affixField = (affix == PREFIX) ? output.fieldAt(index - 1) : output.fieldAt(index);
- if (affixField != UNUM_CURRENCY_FIELD) {
+ if (affixField != Field(UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD)) {
return 0;
}
int affixCp = (affix == PREFIX) ? output.codePointBefore(index) : output.codePointAt(index);
// However, the build code path is more efficient, and this is the most natural
// place to put currency spacing in the non-build code path.
// TODO: Should we use the CURRENCY field here?
- return output.insert(index, spacingString, UNUM_FIELD_COUNT, status);
+ return output.insert(index, spacingString, kUndefinedField, status);
}
UnicodeSet
bool isStrong() const U_OVERRIDE;
- bool containsField(UNumberFormatFields field) const U_OVERRIDE;
+ bool containsField(Field field) const U_OVERRIDE;
void getParameters(Parameters& output) const U_OVERRIDE;
bool isStrong() const U_OVERRIDE;
- bool containsField(UNumberFormatFields field) const U_OVERRIDE;
+ bool containsField(Field field) const U_OVERRIDE;
void getParameters(Parameters& output) const U_OVERRIDE;
bool isStrong() const U_OVERRIDE;
- bool containsField(UNumberFormatFields field) const U_OVERRIDE;
+ bool containsField(Field field) const U_OVERRIDE;
void getParameters(Parameters& output) const U_OVERRIDE;
return fStrong;
}
- bool containsField(UNumberFormatFields field) const U_OVERRIDE {
+ bool containsField(Field field) const U_OVERRIDE {
(void)field;
return false;
}
UErrorCode &status) {
for (int32_t i = 0; i < requiredPadding; i++) {
// TODO: If appending to the end, this will cause actual insertion operations. Improve.
- string.insertCodePoint(index, paddingCp, UNUM_FIELD_COUNT, status);
+ string.insertCodePoint(index, paddingCp, kUndefinedField, status);
}
return U16_LENGTH(paddingCp) * requiredPadding;
}
UnicodeString(),
0,
0,
- UNUM_FIELD_COUNT,
+ kUndefinedField,
status);
}
CurrencySpacingEnabledModifier::applyCurrencySpacing(
return fStrong;
}
-bool MutablePatternModifier::containsField(UNumberFormatFields field) const {
+bool MutablePatternModifier::containsField(Field field) const {
(void)field;
// This method is not currently used.
UPRV_UNREACHABLE;
bool isStrong() const U_OVERRIDE;
- bool containsField(UNumberFormatFields field) const U_OVERRIDE;
+ bool containsField(Field field) const U_OVERRIDE;
void getParameters(Parameters& output) const U_OVERRIDE;
i += output.insert(
i,
fHandler->fSymbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kExponentialSymbol),
- UNUM_EXPONENT_SYMBOL_FIELD,
+ {UFIELD_CATEGORY_NUMBER, UNUM_EXPONENT_SYMBOL_FIELD},
status);
if (fExponent < 0 && fHandler->fSettings.fExponentSignDisplay != UNUM_SIGN_NEVER) {
i += output.insert(
i,
fHandler->fSymbols
->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kMinusSignSymbol),
- UNUM_EXPONENT_SIGN_FIELD,
+ {UFIELD_CATEGORY_NUMBER, UNUM_EXPONENT_SIGN_FIELD},
status);
} else if (fExponent >= 0 && fHandler->fSettings.fExponentSignDisplay == UNUM_SIGN_ALWAYS) {
i += output.insert(
i,
fHandler->fSymbols
->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPlusSignSymbol),
- UNUM_EXPONENT_SIGN_FIELD,
+ {UFIELD_CATEGORY_NUMBER, UNUM_EXPONENT_SIGN_FIELD},
status);
}
// Append the exponent digits (using a simple inline algorithm)
i - j,
d,
*fHandler->fSymbols,
- UNUM_EXPONENT_FIELD,
+ {UFIELD_CATEGORY_NUMBER, UNUM_EXPONENT_FIELD},
status);
}
return i - rightIndex;
return true;
}
-bool ScientificModifier::containsField(UNumberFormatFields field) const {
+bool ScientificModifier::containsField(Field field) const {
(void)field;
// This method is not used for inner modifiers.
UPRV_UNREACHABLE;
bool isStrong() const U_OVERRIDE;
- bool containsField(UNumberFormatFields field) const U_OVERRIDE;
+ bool containsField(Field field) const U_OVERRIDE;
void getParameters(Parameters& output) const U_OVERRIDE;
/**
* Whether the modifier contains at least one occurrence of the given field.
*/
- virtual bool containsField(UNumberFormatFields field) const = 0;
+ virtual bool containsField(Field field) const = 0;
/**
* A fill-in for getParameters(). obj will always be set; if non-null, the other
*/
class UFormattedNumberData : public FormattedValueStringBuilderImpl {
public:
- UFormattedNumberData() : FormattedValueStringBuilderImpl(0) {}
+ UFormattedNumberData() : FormattedValueStringBuilderImpl(kUndefinedField) {}
virtual ~UFormattedNumberData();
DecimalQuantity quantity;
getNumberRangeData(macros.locale.getName(), nsName, data, status);
if (U_FAILURE(status)) { return; }
fRangeFormatter = data.rangePattern;
- fApproximatelyModifier = {data.approximatelyPattern, UNUM_FIELD_COUNT, false};
+ fApproximatelyModifier = {data.approximatelyPattern, kUndefinedField, false};
// TODO: Get locale from PluralRules instead?
fPluralRanges.initialize(macros.locale, status);
// Only collapse if the modifier is a unit.
// TODO: Make a better way to check for a unit?
// TODO: Handle case where the modifier has both notation and unit (compact currency)?
- if (!mm->containsField(UNUM_CURRENCY_FIELD) && !mm->containsField(UNUM_PERCENT_FIELD)) {
+ if (!mm->containsField({UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD})
+ && !mm->containsField({UFIELD_CATEGORY_NUMBER, UNUM_PERCENT_FIELD})) {
collapseMiddle = false;
}
} else if (fCollapse == UNUM_RANGE_COLLAPSE_AUTO) {
0,
&lengthPrefix,
&lengthSuffix,
- UNUM_FIELD_COUNT,
+ kUndefinedField,
status);
if (U_FAILURE(status)) { return; }
lengthInfix = lengthRange - lengthPrefix - lengthSuffix;
if (repeatInner || repeatMiddle || repeatOuter) {
// Add spacing if there is not already spacing
if (!PatternProps::isWhiteSpace(string.charAt(UPRV_INDEX_1))) {
- lengthInfix += string.insertCodePoint(UPRV_INDEX_1, u'\u0020', UNUM_FIELD_COUNT, status);
+ lengthInfix += string.insertCodePoint(UPRV_INDEX_1, u'\u0020', kUndefinedField, status);
}
if (!PatternProps::isWhiteSpace(string.charAt(UPRV_INDEX_2 - 1))) {
- lengthInfix += string.insertCodePoint(UPRV_INDEX_2, u'\u0020', UNUM_FIELD_COUNT, status);
+ lengthInfix += string.insertCodePoint(UPRV_INDEX_2, u'\u0020', kUndefinedField, status);
}
}
}
*/
class UFormattedNumberRangeData : public FormattedValueStringBuilderImpl {
public:
- UFormattedNumberRangeData() : FormattedValueStringBuilderImpl(0) {}
+ UFormattedNumberRangeData() : FormattedValueStringBuilderImpl(kUndefinedField) {}
virtual ~UFormattedNumberRangeData();
DecimalQuantity quantity1;
if (U_FAILURE(status)) {
return;
}
- output.append(result, UNUM_FIELD_COUNT, status);
+ // This code path is probably RBNF. Use the generic numeric field.
+ output.append(result, kGeneralNumericField, status);
if (U_FAILURE(status)) {
return;
}
-static constexpr number::impl::Field kRDTNumericField
- = StringBuilderFieldUtils::compress<UFIELD_CATEGORY_RELATIVE_DATETIME, UDAT_REL_NUMERIC_FIELD>();
+static constexpr FormattedStringBuilder::Field kRDTNumericField
+ = {UFIELD_CATEGORY_RELATIVE_DATETIME, UDAT_REL_NUMERIC_FIELD};
-static constexpr number::impl::Field kRDTLiteralField
- = StringBuilderFieldUtils::compress<UFIELD_CATEGORY_RELATIVE_DATETIME, UDAT_REL_LITERAL_FIELD>();
+static constexpr FormattedStringBuilder::Field kRDTLiteralField
+ = {UFIELD_CATEGORY_RELATIVE_DATETIME, UDAT_REL_LITERAL_FIELD};
class FormattedRelativeDateTimeData : public FormattedValueStringBuilderImpl {
public:
#include "intltest.h"
#include "formatted_string_builder.h"
#include "formattedval_impl.h"
+#include "unicode/unum.h"
class FormattedStringBuilderTest : public IntlTest {
FormattedStringBuilder sb3;
sb1.append(str);
- // Note: UNUM_FIELD_COUNT is like passing null in Java
- sb2.append(str, UNUM_FIELD_COUNT, status);
+ sb2.append(str, kUndefinedField, status);
assertSuccess("Appending to sb2", status);
- sb3.append(str, UNUM_FIELD_COUNT, status);
+ sb3.append(str, kUndefinedField, status);
assertSuccess("Appending to sb3", status);
assertEqualsImpl(sb1, sb2);
assertEqualsImpl(str, sb3);
sb4.append(u"😇");
sb4.append(str);
sb4.append(u"xx");
- sb5.append(u"😇xx", UNUM_FIELD_COUNT, status);
+ sb5.append(u"😇xx", kUndefinedField, status);
assertSuccess("Appending to sb5", status);
- sb5.insert(2, str, UNUM_FIELD_COUNT, status);
+ sb5.insert(2, str, kUndefinedField, status);
assertSuccess("Inserting into sb5", status);
assertEqualsImpl(sb4, sb5);
int start = uprv_min(1, str.length());
int end = uprv_min(10, str.length());
sb4.insert(3, str, start, end - start); // UnicodeString uses length instead of end index
- sb5.insert(3, str, start, end, UNUM_FIELD_COUNT, status);
+ sb5.insert(3, str, start, end, kUndefinedField, status);
assertSuccess("Inserting into sb5 again", status);
assertEqualsImpl(sb4, sb5);
sb1.append(cas.input);
sb1.replace(cas.startThis, cas.endThis - cas.startThis, replacement);
sb2.clear();
- sb2.append(cas.input, UNUM_FIELD_COUNT, status);
- sb2.splice(cas.startThis, cas.endThis, replacement, 0, replacement.length(), UNUM_FIELD_COUNT, status);
+ sb2.append(cas.input, kUndefinedField, status);
+ sb2.splice(cas.startThis, cas.endThis, replacement, 0, replacement.length(), kUndefinedField, status);
assertSuccess("Splicing into sb2 first time", status);
assertEqualsImpl(sb1, sb2);
sb1.append(cas.input);
sb1.replace(cas.startThis, cas.endThis - cas.startThis, UnicodeString(replacement, 1, 2));
sb2.clear();
- sb2.append(cas.input, UNUM_FIELD_COUNT, status);
- sb2.splice(cas.startThis, cas.endThis, replacement, 1, 3, UNUM_FIELD_COUNT, status);
+ sb2.append(cas.input, kUndefinedField, status);
+ sb2.splice(cas.startThis, cas.endThis, replacement, 1, 3, kUndefinedField, status);
assertSuccess("Splicing into sb2 second time", status);
assertEqualsImpl(sb1, sb2);
}
for (UChar32 cas : cases) {
FormattedStringBuilder sb3;
sb1.append(cas);
- sb2.appendCodePoint(cas, UNUM_FIELD_COUNT, status);
+ sb2.appendCodePoint(cas, kUndefinedField, status);
assertSuccess("Appending to sb2", status);
- sb3.appendCodePoint(cas, UNUM_FIELD_COUNT, status);
+ sb3.appendCodePoint(cas, kUndefinedField, status);
assertSuccess("Appending to sb3", status);
assertEqualsImpl(sb1, sb2);
assertEquals("Length of sb3", U16_LENGTH(cas), sb3.length());
FormattedStringBuilder sb5;
sb4.append(u"😇xx");
sb4.insert(2, cas);
- sb5.append(u"😇xx", UNUM_FIELD_COUNT, status);
+ sb5.append(u"😇xx", kUndefinedField, status);
assertSuccess("Appending to sb5", status);
- sb5.insertCodePoint(2, cas, UNUM_FIELD_COUNT, status);
+ sb5.insertCodePoint(2, cas, kUndefinedField, status);
assertSuccess("Inserting into sb5", status);
assertEqualsImpl(sb4, sb5);
FormattedStringBuilder sb7;
sb6.append(cas);
if (U_IS_SUPPLEMENTARY(cas)) {
- sb7.appendChar16(U16_TRAIL(cas), UNUM_FIELD_COUNT, status);
- sb7.insertChar16(0, U16_LEAD(cas), UNUM_FIELD_COUNT, status);
+ sb7.appendChar16(U16_TRAIL(cas), kUndefinedField, status);
+ sb7.insertChar16(0, U16_LEAD(cas), kUndefinedField, status);
} else {
- sb7.insertChar16(0, cas, UNUM_FIELD_COUNT, status);
+ sb7.insertChar16(0, cas, kUndefinedField, status);
}
assertSuccess("Insert/append into sb7", status);
assertEqualsImpl(sb6, sb7);
UErrorCode status = U_ZERO_ERROR;
for (UnicodeString str : EXAMPLE_STRINGS) {
FormattedStringBuilder sb1;
- sb1.append(str, UNUM_FIELD_COUNT, status);
+ sb1.append(str, kUndefinedField, status);
assertSuccess("Appending to sb1 first time", status);
FormattedStringBuilder sb2(sb1);
assertTrue("Content should equal itself", sb1.contentEquals(sb2));
- sb1.append("12345", UNUM_FIELD_COUNT, status);
+ sb1.append("12345", kUndefinedField, status);
assertSuccess("Appending to sb1 second time", status);
assertFalse("Content should no longer equal itself", sb1.contentEquals(sb2));
}
}
void FormattedStringBuilderTest::testFields() {
+ typedef FormattedStringBuilder::Field Field;
UErrorCode status = U_ZERO_ERROR;
// Note: This is a C++11 for loop that calls the UnicodeString constructor on each iteration.
for (UnicodeString str : EXAMPLE_STRINGS) {
- FormattedValueStringBuilderImpl sbi(0);
+ FormattedValueStringBuilderImpl sbi(kUndefinedField);
FormattedStringBuilder& sb = sbi.getStringRef();
- sb.append(str, UNUM_FIELD_COUNT, status);
+ sb.append(str, kUndefinedField, status);
assertSuccess("Appending to sb", status);
- sb.append(str, UNUM_CURRENCY_FIELD, status);
+ sb.append(str, {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD}, status);
assertSuccess("Appending to sb", status);
assertEquals("Reference string copied twice", str.length() * 2, sb.length());
for (int32_t i = 0; i < str.length(); i++) {
assertEquals("Null field first",
- (FormattedStringBuilder::Field) UNUM_FIELD_COUNT, sb.fieldAt(i));
+ kUndefinedField.bits, sb.fieldAt(i).bits);
assertEquals("Currency field second",
- (FormattedStringBuilder::Field) UNUM_CURRENCY_FIELD, sb.fieldAt(i + str.length()));
+ Field(UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD).bits,
+ sb.fieldAt(i + str.length()).bits);
}
// Very basic FieldPosition test. More robust tests happen in NumberFormatTest.
assertEquals("Currency end position", str.length() * 2, fp.getEndIndex());
if (str.length() > 0) {
- sb.insertCodePoint(2, 100, UNUM_INTEGER_FIELD, status);
+ sb.insertCodePoint(2, 100, {UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD}, status);
assertSuccess("Inserting code point into sb", status);
assertEquals("New length", str.length() * 2 + 1, sb.length());
- assertEquals("Integer field", (FormattedStringBuilder::Field) UNUM_INTEGER_FIELD, sb.fieldAt(2));
+ assertEquals("Integer field",
+ Field(UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD).bits,
+ sb.fieldAt(2).bits);
}
FormattedStringBuilder old(sb);
int32_t numCurr = 0;
int32_t numInt = 0;
for (int32_t i = 0; i < sb.length(); i++) {
- FormattedStringBuilder::Field field = sb.fieldAt(i);
- assertEquals("Field should equal location in old", old.fieldAt(i % old.length()), field);
- if (field == UNUM_FIELD_COUNT) {
+ auto field = sb.fieldAt(i);
+ assertEquals("Field should equal location in old",
+ old.fieldAt(i % old.length()).bits, field.bits);
+ if (field == kUndefinedField) {
numNull++;
- } else if (field == UNUM_CURRENCY_FIELD) {
+ } else if (field == Field(UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD)) {
numCurr++;
- } else if (field == UNUM_INTEGER_FIELD) {
+ } else if (field == Field(UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD)) {
numInt++;
} else {
errln("Encountered unknown field");
UnicodeString message("Iteration #");
message += Int64ToUnicodeString(i);
assertEquals(message, builder.length(), i);
- builder.appendCodePoint(u'x', UNUM_FIELD_COUNT, status);
+ builder.appendCodePoint(u'x', kUndefinedField, status);
assertSuccess(message, status);
assertEquals(message, builder.length(), i + 1);
}
assertEquals("Last is -1 on empty string", -1, nsb.getLastCodePoint());
assertEquals("Length is 0 on empty string", 0, nsb.codePointCount());
- nsb.append(u"q", UNUM_FIELD_COUNT, status);
+ nsb.append(u"q", kUndefinedField, status);
assertSuccess("Spot 1", status);
assertEquals("First is q", u'q', nsb.getFirstCodePoint());
assertEquals("Last is q", u'q', nsb.getLastCodePoint());
assertEquals("Code point count is 1", 1, nsb.codePointCount());
// 🚀 is two char16s
- nsb.append(u"🚀", UNUM_FIELD_COUNT, status);
+ nsb.append(u"🚀", kUndefinedField, status);
assertSuccess("Spot 2" ,status);
assertEquals("First is still q", u'q', nsb.getFirstCodePoint());
assertEquals("Last is space ship", 128640, nsb.getLastCodePoint());
UnicodeString input(cas[0]);
UnicodeString expected(cas[1]);
sb.clear();
- AffixUtils::unescape(input, sb, 0, provider, UNUM_FIELD_COUNT, status);
+ AffixUtils::unescape(input, sb, 0, provider, kUndefinedField, status);
assertSuccess("Spot 1", status);
assertEquals(input, expected, sb.toUnicodeString());
assertEquals(input, expected, sb.toTempUnicodeString());
// Test insertion position
sb.clear();
- sb.append(u"abcdefg", UNUM_FIELD_COUNT, status);
+ sb.append(u"abcdefg", kUndefinedField, status);
assertSuccess("Spot 2", status);
- AffixUtils::unescape(u"-+%", sb, 4, provider, UNUM_FIELD_COUNT, status);
+ AffixUtils::unescape(u"-+%", sb, 4, provider, kUndefinedField, status);
assertSuccess("Spot 3", status);
assertEquals(u"Symbol provider into middle", u"abcd123efg", sb.toUnicodeString());
}
UnicodeString AffixUtilsTest::unescapeWithDefaults(const SymbolProvider &defaultProvider,
UnicodeString input, UErrorCode &status) {
FormattedStringBuilder nsb;
- int32_t length = AffixUtils::unescape(input, nsb, 0, defaultProvider, UNUM_FIELD_COUNT, status);
+ int32_t length = AffixUtils::unescape(input, nsb, 0, defaultProvider, kUndefinedField, status);
assertEquals("Return value of unescape", nsb.length(), length);
return nsb.toUnicodeString();
}
void ModifiersTest::testConstantAffixModifier() {
UErrorCode status = U_ZERO_ERROR;
- ConstantAffixModifier mod0(u"", u"", UNUM_PERCENT_FIELD, true);
+ ConstantAffixModifier mod0(u"", u"", {UFIELD_CATEGORY_NUMBER, UNUM_PERCENT_FIELD}, true);
assertModifierEquals(mod0, 0, true, u"|", u"n", status);
assertSuccess("Spot 1", status);
- ConstantAffixModifier mod1(u"a📻", u"b", UNUM_PERCENT_FIELD, true);
+ ConstantAffixModifier mod1(u"a📻", u"b", {UFIELD_CATEGORY_NUMBER, UNUM_PERCENT_FIELD}, true);
assertModifierEquals(mod1, 3, true, u"a📻|b", u"%%%n%", status);
assertSuccess("Spot 2", status);
}
assertModifierEquals(mod1, 0, true, u"|", u"n", status);
assertSuccess("Spot 1", status);
- prefix.append(u"a📻", UNUM_PERCENT_FIELD, status);
- suffix.append(u"b", UNUM_CURRENCY_FIELD, status);
+ prefix.append(u"a📻", {UFIELD_CATEGORY_NUMBER, UNUM_PERCENT_FIELD}, status);
+ suffix.append(u"b", {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD}, status);
ConstantMultiFieldModifier mod2(prefix, suffix, false, true);
assertModifierEquals(mod2, 3, true, u"a📻|b", u"%%%n$", status);
assertSuccess("Spot 2", status);
const UnicodeString pattern(patterns[i]);
SimpleFormatter compiledFormatter(pattern, 1, 1, status);
assertSuccess("Spot 1", status);
- SimpleModifier mod(compiledFormatter, UNUM_PERCENT_FIELD, false);
+ SimpleModifier mod(compiledFormatter, {UFIELD_CATEGORY_NUMBER, UNUM_PERCENT_FIELD}, false);
assertModifierEquals(
mod, prefixLens[i], false, expectedCharFields[i][0], expectedCharFields[i][1], status);
assertSuccess("Spot 2", status);
// Test strange insertion positions
for (int32_t j = 0; j < NUM_OUTPUTS; j++) {
FormattedStringBuilder output;
- output.append(outputs[j].baseString, UNUM_FIELD_COUNT, status);
+ output.append(outputs[j].baseString, kUndefinedField, status);
mod.apply(output, outputs[j].leftIndex, outputs[j].rightIndex, status);
UnicodeString expected = expecteds[j][i];
UnicodeString actual = output.toUnicodeString();
assertModifierEquals(mod1, 0, true, u"|", u"n", status);
assertSuccess("Spot 3", status);
- prefix.append(u"USD", UNUM_CURRENCY_FIELD, status);
+ prefix.append(u"USD", {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD}, status);
assertSuccess("Spot 4", status);
CurrencySpacingEnabledModifier mod2(prefix, suffix, false, true, symbols, status);
assertSuccess("Spot 5", status);
// Test the default currency spacing rules
FormattedStringBuilder sb;
- sb.append("123", UNUM_INTEGER_FIELD, status);
+ sb.append("123", {UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD}, status);
assertSuccess("Spot 7", status);
FormattedStringBuilder sb1(sb);
assertModifierEquals(mod2, sb1, 3, true, u"USD\u00A0123", u"$$$niii", status);
// Compare with the unsafe code path
FormattedStringBuilder sb2(sb);
- sb2.insert(0, "USD", UNUM_CURRENCY_FIELD, status);
+ sb2.insert(0, "USD", {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD}, status);
assertSuccess("Spot 9", status);
CurrencySpacingEnabledModifier::applyCurrencySpacing(sb2, 0, 3, 6, 0, symbols, status);
assertSuccess("Spot 10", status);
// Test custom patterns
// The following line means that the last char of the number should be a | (rather than a digit)
symbols.setPatternForCurrencySpacing(UNUM_CURRENCY_SURROUNDING_MATCH, true, u"[|]");
- suffix.append("XYZ", UNUM_CURRENCY_FIELD, status);
+ suffix.append("XYZ", {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD}, status);
assertSuccess("Spot 11", status);
CurrencySpacingEnabledModifier mod3(prefix, suffix, false, true, symbols, status);
assertSuccess("Spot 12", status);
bool expectedStrong, UnicodeString expectedChars,
UnicodeString expectedFields, UErrorCode &status) {
FormattedStringBuilder sb;
- sb.appendCodePoint('|', UNUM_FIELD_COUNT, status);
+ sb.appendCodePoint('|', kUndefinedField, status);
assertModifierEquals(
mod, sb, expectedPrefixLength, expectedStrong, expectedChars, expectedFields, status);
ParsedPatternInfo patternInfo;
PatternParser::parseToPatternInfo(u"a0b", patternInfo, status);
assertSuccess("Spot 1", status);
- mod.setPatternInfo(&patternInfo, UNUM_FIELD_COUNT);
+ mod.setPatternInfo(&patternInfo, kUndefinedField);
mod.setPatternAttributes(UNUM_SIGN_AUTO, false);
DecimalFormatSymbols symbols(Locale::getEnglish(), status);
CurrencySymbols currencySymbols({u"USD", status}, "en", status);
ParsedPatternInfo patternInfo2;
PatternParser::parseToPatternInfo(u"a0b;c-0d", patternInfo2, status);
assertSuccess("Spot 4", status);
- mod.setPatternInfo(&patternInfo2, UNUM_FIELD_COUNT);
+ mod.setPatternInfo(&patternInfo2, kUndefinedField);
mod.setPatternAttributes(UNUM_SIGN_AUTO, false);
mod.setNumberProperties(SIGNUM_POS, StandardPlural::Form::COUNT);
assertEquals("Pattern a0b;c-0d", u"a", getPrefix(mod, status));
ParsedPatternInfo patternInfo;
PatternParser::parseToPatternInfo(u"abc", patternInfo, status);
assertSuccess("Spot 1", status);
- mod.setPatternInfo(&patternInfo, UNUM_FIELD_COUNT);
+ mod.setPatternInfo(&patternInfo, kUndefinedField);
mod.setPatternAttributes(UNUM_SIGN_AUTO, false);
DecimalFormatSymbols symbols(Locale::getEnglish(), status);
CurrencySymbols currencySymbols({u"USD", status}, "en", status);
// Unsafe Code Path
FormattedStringBuilder nsb;
- nsb.append(u"x123y", UNUM_FIELD_COUNT, status);
+ nsb.append(u"x123y", kUndefinedField, status);
assertSuccess("Spot 3", status);
mod.apply(nsb, 1, 4, status);
assertSuccess("Spot 4", status);
// Safe Code Path
nsb.clear();
- nsb.append(u"x123y", UNUM_FIELD_COUNT, status);
+ nsb.append(u"x123y", kUndefinedField, status);
assertSuccess("Spot 5", status);
MicroProps micros;
LocalPointer<ImmutablePatternModifier> imod(mod.createImmutable(status), status);
ParsedPatternInfo patternInfo;
PatternParser::parseToPatternInfo("a0b;c-0d", patternInfo, status);
assertSuccess("Spot 1", status);
- mod.setPatternInfo(&patternInfo, UNUM_FIELD_COUNT);
+ mod.setPatternInfo(&patternInfo, kUndefinedField);
mod.setPatternAttributes(UNUM_SIGN_AUTO, false);
DecimalFormatSymbols symbols(Locale::getEnglish(), status);
CurrencySymbols currencySymbols({u"USD", status}, "en", status);