]> granicus.if.org Git - icu/commitdiff
ICU-20665 Removing number-dependence from ICU4C FormattedStringBuilder fields.
authorShane Carr <shane@unicode.org>
Wed, 20 Nov 2019 02:22:20 +0000 (02:22 +0000)
committerShane F. Carr <shane@unicode.org>
Fri, 17 Jan 2020 10:22:02 +0000 (11:22 +0100)
See #727

27 files changed:
icu4c/source/common/uassert.h
icu4c/source/i18n/formatted_string_builder.cpp
icu4c/source/i18n/formatted_string_builder.h
icu4c/source/i18n/formattedval_impl.h
icu4c/source/i18n/formattedval_sbimpl.cpp
icu4c/source/i18n/measfmt.cpp
icu4c/source/i18n/number_affixutils.cpp
icu4c/source/i18n/number_compact.cpp
icu4c/source/i18n/number_formatimpl.cpp
icu4c/source/i18n/number_longnames.cpp
icu4c/source/i18n/number_modifiers.cpp
icu4c/source/i18n/number_modifiers.h
icu4c/source/i18n/number_padding.cpp
icu4c/source/i18n/number_patternmodifier.cpp
icu4c/source/i18n/number_patternmodifier.h
icu4c/source/i18n/number_scientific.cpp
icu4c/source/i18n/number_scientific.h
icu4c/source/i18n/number_types.h
icu4c/source/i18n/number_utypes.h
icu4c/source/i18n/numrange_impl.cpp
icu4c/source/i18n/numrange_impl.h
icu4c/source/i18n/quantityformatter.cpp
icu4c/source/i18n/reldatefmt.cpp
icu4c/source/test/intltest/formatted_string_builder_test.cpp
icu4c/source/test/intltest/numbertest_affixutils.cpp
icu4c/source/test/intltest/numbertest_modifiers.cpp
icu4c/source/test/intltest/numbertest_patternmodifier.cpp

index f0f7a92574b4d41b1aef6531d56db3e2c48b0228..15cd55c873487cc2bf50f2523cbef5f825c674de 100644 (file)
@@ -31,6 +31,8 @@
 #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
index 3024bff6addaccb1b987e6bdf780a44a9e72df89..5aabc31cc4391b117f79d7b2e00a8d71ca7dee51 100644 (file)
@@ -8,6 +8,7 @@
 #include "formatted_string_builder.h"
 #include "unicode/ustring.h"
 #include "unicode/utf16.h"
+#include "unicode/unum.h" // for UNumberFormatFields literals
 
 namespace {
 
@@ -246,7 +247,7 @@ void FormattedStringBuilder::writeTerminator(UErrorCode& status) {
         return;
     }
     getCharPtr()[position] = 0;
-    getFieldPtr()[position] = UNUM_FIELD_COUNT;
+    getFieldPtr()[position] = kUndefinedField;
     fLength--;
 }
 
@@ -360,11 +361,11 @@ UnicodeString FormattedStringBuilder::toDebugString() const {
     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;
@@ -399,10 +400,12 @@ UnicodeString FormattedStringBuilder::toDebugString() const {
                     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);
index 2949ae73e0ff9efb2697fa54001226518ccbcac4..4567dc1d66b0ce3534ca0574eda7b9fe4a9e3e8d 100644 (file)
@@ -9,7 +9,8 @@
 
 
 #include <cstdint>
-#include "unicode/unum.h" // for UNUM_FIELD_COUNT
+#include <type_traits>
+
 #include "cstring.h"
 #include "uassert.h"
 #include "fphdlimp.h"
@@ -55,7 +56,20 @@ class U_I18N_API FormattedStringBuilder : public UMemory {
     // 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);
 
@@ -204,46 +218,50 @@ class U_I18N_API FormattedStringBuilder : public UMemory {
     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
 
index 9aab36a52fecda4eda978713c39a05f3009fd497..7bee374286949b79b24b19231366aef242924f26 100644 (file)
@@ -153,7 +153,6 @@ private:
 
     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;
 };
index ca28f222813afc67031ed76fef3a3d41661b7e7a..dfe3af6686df2f6bcb980ffa2f59aa5beb16512b 100644 (file)
@@ -63,7 +63,7 @@ UBool FormattedValueStringBuilderImpl::nextFieldPosition(FieldPosition& fp, UErr
     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;
@@ -74,7 +74,7 @@ UBool FormattedValueStringBuilderImpl::nextFieldPosition(FieldPosition& fp, UErr
         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;
@@ -90,42 +90,40 @@ UBool FormattedValueStringBuilderImpl::nextFieldPosition(FieldPosition& fp, UErr
 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;
@@ -147,51 +145,46 @@ bool FormattedValueStringBuilderImpl::nextPositionImpl(ConstrainedFieldPosition&
             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 {
index 1949f17b13723d729c4be00fdff2c84c70588e0d..f3ba6198cef2035a8f110d65a7d539b9be9a5e1b 100644 (file)
@@ -774,11 +774,6 @@ UnicodeString &MeasureFormat::formatNumeric(
             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...
@@ -787,7 +782,7 @@ UnicodeString &MeasureFormat::formatNumeric(
             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
@@ -797,20 +792,20 @@ UnicodeString &MeasureFormat::formatNumeric(
                         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);
         }
     }
 
index 1039a84c656124b45fb69874cc40c22aa5d5351e..a74ec2d634799e49157f3026bb7c659012135923 100644 (file)
@@ -131,25 +131,25 @@ UnicodeString AffixUtils::escape(const UnicodeString &input) {
 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;
     }
@@ -165,7 +165,11 @@ AffixUtils::unescape(const UnicodeString &affixPattern, FormattedStringBuilder &
         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);
@@ -218,7 +222,7 @@ bool AffixUtils::hasCurrencySymbols(const UnicodeString &affixPattern, UErrorCod
     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;
         }
     }
index e3c6bbc0f9ef68abbe80ec7673010e05da30941f..9d9e6c9ab1438521283fd6308f409ec99a88577e 100644 (file)
@@ -266,7 +266,7 @@ void CompactHandler::precomputeAllModifiers(MutablePatternModifier &buildReferen
         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;
@@ -315,7 +315,9 @@ void CompactHandler::processQuantity(DecimalQuantity &quantity, MicroProps &micr
         // 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;
     }
index 708aaa54c202ae490dc5b66fe51422de89dbb5f7..83ee2a8bfe9cf52acde91419fa65fd9b7acfd2aa 100644 (file)
@@ -370,7 +370,7 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps& macros, bool safe,
     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(
@@ -480,14 +480,14 @@ int32_t NumberFormatterImpl::writeNumber(const MicroProps& micros, DecimalQuanti
         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 {
@@ -503,7 +503,7 @@ int32_t NumberFormatterImpl::writeNumber(const MicroProps& micros, DecimalQuanti
                             .symbols
                             ->getSymbol(
                                     DecimalFormatSymbols::ENumberFormatSymbol::kDecimalSeparatorSymbol),
-                    UNUM_DECIMAL_SEPARATOR_FIELD,
+                    {UFIELD_CATEGORY_NUMBER, UNUM_DECIMAL_SEPARATOR_FIELD},
                     status);
         }
 
@@ -513,7 +513,12 @@ int32_t NumberFormatterImpl::writeNumber(const MicroProps& micros, DecimalQuanti
         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);
         }
     }
 
@@ -534,14 +539,20 @@ int32_t NumberFormatterImpl::writeIntegerDigits(const MicroProps& micros, Decima
                             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;
 }
@@ -555,7 +566,12 @@ int32_t NumberFormatterImpl::writeFractionDigits(const MicroProps& micros, Decim
         // 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;
 }
index 5519398a059f07aee574b2f591f2c7c5ae4dd3a0..5378eda8b2400bef58fdb4b060f57871f6648463 100644 (file)
@@ -209,7 +209,7 @@ LongNameHandler::forMeasureUnit(const Locale &loc, const MeasureUnit &unitRef, c
     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;
 }
 
@@ -247,7 +247,7 @@ LongNameHandler::forCompoundUnit(const Locale &loc, const MeasureUnit &unit, con
         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;
 }
 
@@ -296,7 +296,7 @@ LongNameHandler* LongNameHandler::forCurrencyLongNames(const Locale &loc, const
     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;
 }
 
index 3a44f8f6f1532829e49ad4a04141aabd0836fa7d..1267f6aeb559735d160220a8b412b013cc7996a8 100644 (file)
@@ -89,7 +89,7 @@ bool ConstantAffixModifier::isStrong() const {
     return fStrong;
 }
 
-bool ConstantAffixModifier::containsField(UNumberFormatFields field) const {
+bool ConstantAffixModifier::containsField(Field field) const {
     (void)field;
     // This method is not currently used.
     UPRV_UNREACHABLE;
@@ -151,7 +151,7 @@ SimpleModifier::SimpleModifier(const SimpleFormatter &simpleFormatter, Field fie
 }
 
 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,
@@ -178,7 +178,7 @@ bool SimpleModifier::isStrong() const {
     return fStrong;
 }
 
-bool SimpleModifier::containsField(UNumberFormatFields field) const {
+bool SimpleModifier::containsField(Field field) const {
     (void)field;
     // This method is not currently used.
     UPRV_UNREACHABLE;
@@ -292,7 +292,7 @@ int32_t ConstantMultiFieldModifier::apply(FormattedStringBuilder &output, int le
             leftIndex + length,
             rightIndex + length,
             UnicodeString(), 0, 0,
-            UNUM_FIELD_COUNT, status);
+            kUndefinedField, status);
     }
     length += output.insert(rightIndex + length, fSuffix, status);
     return length;
@@ -310,7 +310,7 @@ bool ConstantMultiFieldModifier::isStrong() const {
     return fStrong;
 }
 
-bool ConstantMultiFieldModifier::containsField(UNumberFormatFields field) const {
+bool ConstantMultiFieldModifier::containsField(Field field) const {
     return fPrefix.containsField(field) || fSuffix.containsField(field);
 }
 
@@ -342,7 +342,7 @@ CurrencySpacingEnabledModifier::CurrencySpacingEnabledModifier(const FormattedSt
         : 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)) {
@@ -357,7 +357,7 @@ CurrencySpacingEnabledModifier::CurrencySpacingEnabledModifier(const FormattedSt
         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)) {
@@ -381,12 +381,20 @@ int32_t CurrencySpacingEnabledModifier::apply(FormattedStringBuilder &output, in
     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
@@ -422,7 +430,7 @@ CurrencySpacingEnabledModifier::applyCurrencySpacingAffix(FormattedStringBuilder
     // 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);
@@ -443,7 +451,7 @@ CurrencySpacingEnabledModifier::applyCurrencySpacingAffix(FormattedStringBuilder
     // 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
index e3820b6b384db9242127fbaedcc69e4e3e2fd820..375254310ca0564f412fdc8bd2e8bf2e65ed3ef0 100644 (file)
@@ -37,7 +37,7 @@ class U_I18N_API ConstantAffixModifier : public Modifier, public UObject {
 
     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;
 
@@ -73,7 +73,7 @@ class U_I18N_API SimpleModifier : public Modifier, public UMemory {
 
     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;
 
@@ -166,7 +166,7 @@ class U_I18N_API ConstantMultiFieldModifier : public Modifier, public UMemory {
 
     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;
 
@@ -255,7 +255,7 @@ class U_I18N_API EmptyModifier : public Modifier, public UMemory {
         return fStrong;
     }
 
-    bool containsField(UNumberFormatFields field) const U_OVERRIDE {
+    bool containsField(Field field) const U_OVERRIDE {
         (void)field;
         return false;
     }
index c68a9875b2055f18fb23606161dd3453c8f5e103..c320c3ffb6fadcb28e2c30a10f07669180520917 100644 (file)
@@ -21,7 +21,7 @@ addPaddingHelper(UChar32 paddingCp, int32_t requiredPadding, FormattedStringBuil
                  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;
 }
index 892ac372f51ffd71db06d78f930a69827a0ad57e..e37dde8c175dfcb8b167ef30976395ba6553b12c 100644 (file)
@@ -195,7 +195,7 @@ int32_t MutablePatternModifier::apply(FormattedStringBuilder& output, int32_t le
                 UnicodeString(),
                 0,
                 0,
-                UNUM_FIELD_COUNT,
+                kUndefinedField,
                 status);
     }
     CurrencySpacingEnabledModifier::applyCurrencySpacing(
@@ -239,7 +239,7 @@ bool MutablePatternModifier::isStrong() const {
     return fStrong;
 }
 
-bool MutablePatternModifier::containsField(UNumberFormatFields field) const {
+bool MutablePatternModifier::containsField(Field field) const {
     (void)field;
     // This method is not currently used.
     UPRV_UNREACHABLE;
index 4034c9a47eea9fa110f358c73a845c1e225f9ad9..2597afefd53f49b7c3d0d93e0a49869f4b0ced01 100644 (file)
@@ -180,7 +180,7 @@ class U_I18N_API MutablePatternModifier
 
     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;
 
index f3de74141253686a2c446a5e1b96b92c6086971c..edafa80cb9ce1dd1b8c83e2dadc2b68a33c6891f 100644 (file)
@@ -44,21 +44,21 @@ int32_t ScientificModifier::apply(FormattedStringBuilder &output, int32_t /*left
     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)
@@ -70,7 +70,7 @@ int32_t ScientificModifier::apply(FormattedStringBuilder &output, int32_t /*left
                 i - j,
                 d,
                 *fHandler->fSymbols,
-                UNUM_EXPONENT_FIELD,
+                {UFIELD_CATEGORY_NUMBER, UNUM_EXPONENT_FIELD},
                 status);
     }
     return i - rightIndex;
@@ -93,7 +93,7 @@ bool ScientificModifier::isStrong() const {
     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;
index 1c9ce1efa80a3f408a2f6599fbb1545d26efca17..a55d5ed1d410de206a5107fb10736d3e482a0694 100644 (file)
@@ -30,7 +30,7 @@ class U_I18N_API ScientificModifier : public UMemory, public Modifier {
 
     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;
 
index 641e082d361d39907e06a16e7686c268dcc8e62f..5c2b8cf8b5d19c5deb9d61ab21175b6840216852 100644 (file)
@@ -194,7 +194,7 @@ class U_I18N_API Modifier {
     /**
      * 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
index 6dbe5bee68fb71354b5bcf44b948dba93ad72696..af25aa3398898c2f728f6b8260b5709b078586e4 100644 (file)
@@ -33,7 +33,7 @@ const DecimalQuantity* validateUFormattedNumberToDecimalQuantity(
  */
 class UFormattedNumberData : public FormattedValueStringBuilderImpl {
 public:
-    UFormattedNumberData() : FormattedValueStringBuilderImpl(0) {}
+    UFormattedNumberData() : FormattedValueStringBuilderImpl(kUndefinedField) {}
     virtual ~UFormattedNumberData();
 
     DecimalQuantity quantity;
index 7d732b31ec177a0e03459cb3e0194c7719006eae..9fb3dee861f1f611546ea936deb89db0c4262afd 100644 (file)
@@ -210,7 +210,7 @@ NumberRangeFormatterImpl::NumberRangeFormatterImpl(const RangeMacroProps& macros
     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);
@@ -368,7 +368,8 @@ void NumberRangeFormatterImpl::formatRange(UFormattedNumberRangeData& data,
                 // 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) {
@@ -416,7 +417,7 @@ void NumberRangeFormatterImpl::formatRange(UFormattedNumberRangeData& data,
         0,
         &lengthPrefix,
         &lengthSuffix,
-        UNUM_FIELD_COUNT,
+        kUndefinedField,
         status);
     if (U_FAILURE(status)) { return; }
     lengthInfix = lengthRange - lengthPrefix - lengthSuffix;
@@ -434,10 +435,10 @@ void NumberRangeFormatterImpl::formatRange(UFormattedNumberRangeData& data,
         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);
             }
         }
     }
index f88e300913642d9ceeab78e4ecb352e4aedda6a4..8f4c8a40ba2fdc7e7ece251d2cb618d73f187ed5 100644 (file)
@@ -31,7 +31,7 @@ namespace impl {
  */
 class UFormattedNumberRangeData : public FormattedValueStringBuilderImpl {
 public:
-    UFormattedNumberRangeData() : FormattedValueStringBuilderImpl(0) {}
+    UFormattedNumberRangeData() : FormattedValueStringBuilderImpl(kUndefinedField) {}
     virtual ~UFormattedNumberRangeData();
 
     DecimalQuantity quantity1;
index e88b70fbd71795c0c85cc651473ca6a35737418e..9c9aa99b670944748ffeeaaf44585701aebc73f1 100644 (file)
@@ -204,7 +204,8 @@ void QuantityFormatter::formatAndSelect(
         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;
         }
index f66092ba948e5dcff000ca88550e1c38d9ea3343..8c6688c5b9ad8a897ad774da5283ab60324542c6 100644 (file)
@@ -728,11 +728,11 @@ const RelativeDateTimeCacheData *LocaleCacheKey<RelativeDateTimeCacheData>::crea
 
 
 
-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:
index 4ce63daec569b05edcdb2758c9a28376a6734f90..18f56d392dcd3f7f634d60eb762d11e30257d5b0 100644 (file)
@@ -10,6 +10,7 @@
 #include "intltest.h"
 #include "formatted_string_builder.h"
 #include "formattedval_impl.h"
+#include "unicode/unum.h"
 
 
 class FormattedStringBuilderTest : public IntlTest {
@@ -61,10 +62,9 @@ void FormattedStringBuilderTest::testInsertAppendUnicodeString() {
 
         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);
@@ -74,16 +74,16 @@ void FormattedStringBuilderTest::testInsertAppendUnicodeString() {
         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);
 
@@ -124,8 +124,8 @@ void FormattedStringBuilderTest::testSplice() {
             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);
 
@@ -137,8 +137,8 @@ void FormattedStringBuilderTest::testSplice() {
             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);
         }
@@ -154,9 +154,9 @@ void FormattedStringBuilderTest::testInsertAppendCodePoint() {
     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());
@@ -170,9 +170,9 @@ void FormattedStringBuilderTest::testInsertAppendCodePoint() {
         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);
 
@@ -180,10 +180,10 @@ void FormattedStringBuilderTest::testInsertAppendCodePoint() {
         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);
@@ -194,33 +194,35 @@ void FormattedStringBuilderTest::testCopy() {
     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.
@@ -232,10 +234,12 @@ void FormattedStringBuilderTest::testFields() {
         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);
@@ -245,13 +249,14 @@ void FormattedStringBuilderTest::testFields() {
         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");
@@ -271,7 +276,7 @@ void FormattedStringBuilderTest::testUnlimitedCapacity() {
         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);
     }
@@ -284,7 +289,7 @@ void FormattedStringBuilderTest::testCodePoints() {
     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());
@@ -293,7 +298,7 @@ void FormattedStringBuilderTest::testCodePoints() {
     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());
index 7f29ad19903baa47130fc6e30bd0a2fc93594595..499b5d0e0903d0e276724eeb752ba78edd3346e8 100644 (file)
@@ -222,7 +222,7 @@ void AffixUtilsTest::testUnescapeWithSymbolProvider() {
         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());
@@ -230,9 +230,9 @@ void AffixUtilsTest::testUnescapeWithSymbolProvider() {
 
     // 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());
 }
@@ -240,7 +240,7 @@ void AffixUtilsTest::testUnescapeWithSymbolProvider() {
 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();
 }
index 90144ad1c64acd4746598334eddf9a8f73caca9d..5ffca12b70e9d223acd0ffa354bb6b7626b61345 100644 (file)
@@ -25,11 +25,11 @@ void ModifiersTest::runIndexedTest(int32_t index, UBool exec, const char *&name,
 
 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);
 }
@@ -42,8 +42,8 @@ void ModifiersTest::testConstantMultiFieldModifier() {
     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);
@@ -80,7 +80,7 @@ void ModifiersTest::testSimpleModifier() {
         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);
@@ -88,7 +88,7 @@ void ModifiersTest::testSimpleModifier() {
         // 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();
@@ -112,7 +112,7 @@ void ModifiersTest::testCurrencySpacingEnabledModifier() {
     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);
@@ -121,7 +121,7 @@ void ModifiersTest::testCurrencySpacingEnabledModifier() {
 
     // 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);
@@ -129,7 +129,7 @@ void ModifiersTest::testCurrencySpacingEnabledModifier() {
 
     // 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);
@@ -138,7 +138,7 @@ void ModifiersTest::testCurrencySpacingEnabledModifier() {
     // 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);
@@ -150,7 +150,7 @@ void ModifiersTest::assertModifierEquals(const Modifier &mod, int32_t expectedPr
                                          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);
 
index 1d1e634cd332dcc5830601f962dfa690edd6f8cf..42d3a6f7cf4a3d551db9d852859158729640ef87 100644 (file)
@@ -26,7 +26,7 @@ void PatternModifierTest::testBasic() {
     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);
@@ -61,7 +61,7 @@ void PatternModifierTest::testBasic() {
     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));
@@ -93,7 +93,7 @@ void PatternModifierTest::testPatternWithNoPlaceholder() {
     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);
@@ -105,7 +105,7 @@ void PatternModifierTest::testPatternWithNoPlaceholder() {
 
     // 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);
@@ -113,7 +113,7 @@ void PatternModifierTest::testPatternWithNoPlaceholder() {
 
     // 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);
@@ -136,7 +136,7 @@ void PatternModifierTest::testMutableEqualsImmutable() {
     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);