]> granicus.if.org Git - icu/commitdiff
ICU-20429 Renaming [Number->Formatted]StringBuilder and refactoring.
authorShane Carr <shane@unicode.org>
Fri, 5 Apr 2019 23:43:19 +0000 (16:43 -0700)
committerShane F. Carr <shane@unicode.org>
Sat, 6 Apr 2019 01:08:07 +0000 (20:08 -0500)
- StringSegment, ICU4C:
  * Moved to top icu namespace
  * Compilation unit renamed to string_segment.
- NumberStringBuilder, C and J:
  * Moved to main icu namespace
  * Compilation unit renamed to formatted_string_builder
  * Renamed class to FormattedStringBuilder
- Moves nextPosition logic of NumberStringBuilder to helper class

80 files changed:
icu4c/source/i18n/Makefile.in
icu4c/source/i18n/formatted_string_builder.cpp [moved from icu4c/source/i18n/number_stringbuilder.cpp with 58% similarity]
icu4c/source/i18n/formatted_string_builder.h [moved from icu4c/source/i18n/number_stringbuilder.h with 54% similarity]
icu4c/source/i18n/formattedval_impl.h
icu4c/source/i18n/formattedval_sbimpl.cpp
icu4c/source/i18n/i18n.vcxproj
icu4c/source/i18n/i18n.vcxproj.filters
icu4c/source/i18n/i18n_uwp.vcxproj
icu4c/source/i18n/number_affixutils.cpp
icu4c/source/i18n/number_affixutils.h
icu4c/source/i18n/number_asformat.cpp
icu4c/source/i18n/number_fluent.cpp
icu4c/source/i18n/number_formatimpl.cpp
icu4c/source/i18n/number_formatimpl.h
icu4c/source/i18n/number_modifiers.cpp
icu4c/source/i18n/number_modifiers.h
icu4c/source/i18n/number_output.cpp
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_skeletons.cpp
icu4c/source/i18n/number_skeletons.h
icu4c/source/i18n/number_types.h
icu4c/source/i18n/number_utils.h
icu4c/source/i18n/number_utypes.h
icu4c/source/i18n/numparse_affixes.cpp
icu4c/source/i18n/numparse_compositions.cpp
icu4c/source/i18n/numparse_currency.cpp
icu4c/source/i18n/numparse_decimal.cpp
icu4c/source/i18n/numparse_impl.h
icu4c/source/i18n/numparse_parsednumber.cpp
icu4c/source/i18n/numparse_scientific.cpp
icu4c/source/i18n/numparse_stringsegment.h [deleted file]
icu4c/source/i18n/numparse_symbols.cpp
icu4c/source/i18n/numparse_types.h
icu4c/source/i18n/numrange_fluent.cpp
icu4c/source/i18n/numrange_impl.cpp
icu4c/source/i18n/numrange_impl.h
icu4c/source/i18n/quantityformatter.cpp
icu4c/source/i18n/quantityformatter.h
icu4c/source/i18n/reldatefmt.cpp
icu4c/source/i18n/string_segment.cpp [moved from icu4c/source/i18n/numparse_stringsegment.cpp with 96% similarity]
icu4c/source/i18n/string_segment.h [new file with mode: 0644]
icu4c/source/i18n/unicode/numberformatter.h
icu4c/source/test/depstest/dependencies.txt
icu4c/source/test/intltest/Makefile.in
icu4c/source/test/intltest/formatted_string_builder_test.cpp [moved from icu4c/source/test/intltest/numbertest_stringbuilder.cpp with 81% similarity]
icu4c/source/test/intltest/intltest.vcxproj
icu4c/source/test/intltest/intltest.vcxproj.filters
icu4c/source/test/intltest/itformat.cpp
icu4c/source/test/intltest/numbertest.h
icu4c/source/test/intltest/numbertest_affixutils.cpp
icu4c/source/test/intltest/numbertest_modifiers.cpp
icu4c/source/test/intltest/numbertest_patternmodifier.cpp
icu4c/source/test/intltest/string_segment_test.cpp [moved from icu4c/source/test/intltest/numbertest_stringsegment.cpp with 91% similarity]
icu4j/main/classes/core/src/com/ibm/icu/impl/FormattedStringBuilder.java [moved from icu4j/main/classes/core/src/com/ibm/icu/impl/number/NumberStringBuilder.java with 64% similarity]
icu4j/main/classes/core/src/com/ibm/icu/impl/FormattedValueStringBuilderImpl.java [new file with mode: 0644]
icu4j/main/classes/core/src/com/ibm/icu/impl/StringSegment.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/AffixUtils.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/ConstantAffixModifier.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/ConstantMultiFieldModifier.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/CurrencySpacingEnabledModifier.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/Modifier.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/MutablePatternModifier.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/Padder.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/SimpleModifier.java
icu4j/main/classes/core/src/com/ibm/icu/number/FormattedNumber.java
icu4j/main/classes/core/src/com/ibm/icu/number/FormattedNumberRange.java
icu4j/main/classes/core/src/com/ibm/icu/number/LocalizedNumberFormatter.java
icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatterImpl.java
icu4j/main/classes/core/src/com/ibm/icu/number/NumberRangeFormatterImpl.java
icu4j/main/classes/core/src/com/ibm/icu/number/ScientificNotation.java
icu4j/main/classes/core/src/com/ibm/icu/text/RelativeDateTimeFormatter.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/FormattedStringBuilderTest.java [moved from icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberStringBuilderTest.java with 87% similarity]
icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/AffixUtilsTest.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/DecimalQuantityTest.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/ModifierTest.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/MutablePatternModifierTest.java

index 2d001879e8fc5d6d521d256e21d6832ace884e14..7487d30354fdf50d319c2dfed78b44d2080a2478 100644 (file)
@@ -103,16 +103,17 @@ number_affixutils.o number_compact.o number_decimalquantity.o \
 number_decimfmtprops.o number_fluent.o number_formatimpl.o number_grouping.o \
 number_integerwidth.o number_longnames.o number_modifiers.o number_notation.o number_output.o \
 number_padding.o number_patternmodifier.o number_patternstring.o \
-number_rounding.o number_scientific.o number_stringbuilder.o number_utils.o number_asformat.o \
+number_rounding.o number_scientific.o number_utils.o number_asformat.o \
 number_mapper.o number_multiplier.o number_currencysymbols.o number_skeletons.o number_capi.o \
 double-conversion.o double-conversion-bignum-dtoa.o double-conversion-bignum.o \
 double-conversion-cached-powers.o double-conversion-diy-fp.o \
 double-conversion-fast-dtoa.o double-conversion-strtod.o \
-numparse_stringsegment.o numparse_parsednumber.o numparse_impl.o \
+string_segment.o numparse_parsednumber.o numparse_impl.o \
 numparse_symbols.o numparse_decimal.o numparse_scientific.o numparse_currency.o \
 numparse_affixes.o numparse_compositions.o numparse_validators.o \
 numrange_fluent.o numrange_impl.o \
-erarules.o formattedvalue.o formattedval_iterimpl.o formattedval_sbimpl.o
+erarules.o \
+formattedvalue.o formattedval_iterimpl.o formattedval_sbimpl.o formatted_string_builder.o
 
 ## Header files to install
 HEADERS = $(srcdir)/unicode/*.h
similarity index 58%
rename from icu4c/source/i18n/number_stringbuilder.cpp
rename to icu4c/source/i18n/formatted_string_builder.cpp
index 03300b33ac5e21be0207aa26dd80b3023b609b9e..4ffc4c704a171201085483dccc69252c8e7b33e4 100644 (file)
@@ -5,14 +5,9 @@
 
 #if !UCONFIG_NO_FORMATTING
 
-#include "number_stringbuilder.h"
-#include "static_unicode_sets.h"
+#include "formatted_string_builder.h"
+#include "unicode/ustring.h"
 #include "unicode/utf16.h"
-#include "number_utils.h"
-
-using namespace icu;
-using namespace icu::number;
-using namespace icu::number::impl;
 
 namespace {
 
@@ -34,7 +29,10 @@ inline void uprv_memmove2(void* dest, const void* src, size_t len) {
 
 } // namespace
 
-NumberStringBuilder::NumberStringBuilder() {
+
+U_NAMESPACE_BEGIN
+
+FormattedStringBuilder::FormattedStringBuilder() {
 #if U_DEBUG
     // Initializing the memory to non-zero helps catch some bugs that involve
     // reading from an improperly terminated string.
@@ -44,18 +42,18 @@ NumberStringBuilder::NumberStringBuilder() {
 #endif
 }
 
-NumberStringBuilder::~NumberStringBuilder() {
+FormattedStringBuilder::~FormattedStringBuilder() {
     if (fUsingHeap) {
         uprv_free(fChars.heap.ptr);
         uprv_free(fFields.heap.ptr);
     }
 }
 
-NumberStringBuilder::NumberStringBuilder(const NumberStringBuilder &other) {
+FormattedStringBuilder::FormattedStringBuilder(const FormattedStringBuilder &other) {
     *this = other;
 }
 
-NumberStringBuilder &NumberStringBuilder::operator=(const NumberStringBuilder &other) {
+FormattedStringBuilder &FormattedStringBuilder::operator=(const FormattedStringBuilder &other) {
     // Check for self-assignment
     if (this == &other) {
         return *this;
@@ -78,7 +76,7 @@ NumberStringBuilder &NumberStringBuilder::operator=(const NumberStringBuilder &o
             // UErrorCode is not available; fail silently.
             uprv_free(newChars);
             uprv_free(newFields);
-            *this = NumberStringBuilder();  // can't fail
+            *this = FormattedStringBuilder();  // can't fail
             return *this;
         }
 
@@ -97,15 +95,15 @@ NumberStringBuilder &NumberStringBuilder::operator=(const NumberStringBuilder &o
     return *this;
 }
 
-int32_t NumberStringBuilder::length() const {
+int32_t FormattedStringBuilder::length() const {
     return fLength;
 }
 
-int32_t NumberStringBuilder::codePointCount() const {
+int32_t FormattedStringBuilder::codePointCount() const {
     return u_countChar32(getCharPtr() + fZero, fLength);
 }
 
-UChar32 NumberStringBuilder::getFirstCodePoint() const {
+UChar32 FormattedStringBuilder::getFirstCodePoint() const {
     if (fLength == 0) {
         return -1;
     }
@@ -114,7 +112,7 @@ UChar32 NumberStringBuilder::getFirstCodePoint() const {
     return cp;
 }
 
-UChar32 NumberStringBuilder::getLastCodePoint() const {
+UChar32 FormattedStringBuilder::getLastCodePoint() const {
     if (fLength == 0) {
         return -1;
     }
@@ -125,13 +123,13 @@ UChar32 NumberStringBuilder::getLastCodePoint() const {
     return cp;
 }
 
-UChar32 NumberStringBuilder::codePointAt(int32_t index) const {
+UChar32 FormattedStringBuilder::codePointAt(int32_t index) const {
     UChar32 cp;
     U16_GET(getCharPtr() + fZero, 0, index, fLength, cp);
     return cp;
 }
 
-UChar32 NumberStringBuilder::codePointBefore(int32_t index) const {
+UChar32 FormattedStringBuilder::codePointBefore(int32_t index) const {
     int32_t offset = index;
     U16_BACK_1(getCharPtr() + fZero, 0, offset);
     UChar32 cp;
@@ -139,19 +137,19 @@ UChar32 NumberStringBuilder::codePointBefore(int32_t index) const {
     return cp;
 }
 
-NumberStringBuilder &NumberStringBuilder::clear() {
+FormattedStringBuilder &FormattedStringBuilder::clear() {
     // TODO: Reset the heap here?
     fZero = getCapacity() / 2;
     fLength = 0;
     return *this;
 }
 
-int32_t NumberStringBuilder::appendCodePoint(UChar32 codePoint, Field field, UErrorCode &status) {
+int32_t FormattedStringBuilder::appendCodePoint(UChar32 codePoint, Field field, UErrorCode &status) {
     return insertCodePoint(fLength, codePoint, field, status);
 }
 
 int32_t
-NumberStringBuilder::insertCodePoint(int32_t index, UChar32 codePoint, Field field, UErrorCode &status) {
+FormattedStringBuilder::insertCodePoint(int32_t index, UChar32 codePoint, Field field, UErrorCode &status) {
     int32_t count = U16_LENGTH(codePoint);
     int32_t position = prepareForInsert(index, count, status);
     if (U_FAILURE(status)) {
@@ -168,11 +166,11 @@ NumberStringBuilder::insertCodePoint(int32_t index, UChar32 codePoint, Field fie
     return count;
 }
 
-int32_t NumberStringBuilder::append(const UnicodeString &unistr, Field field, UErrorCode &status) {
+int32_t FormattedStringBuilder::append(const UnicodeString &unistr, Field field, UErrorCode &status) {
     return insert(fLength, unistr, field, status);
 }
 
-int32_t NumberStringBuilder::insert(int32_t index, const UnicodeString &unistr, Field field,
+int32_t FormattedStringBuilder::insert(int32_t index, const UnicodeString &unistr, Field field,
                                     UErrorCode &status) {
     if (unistr.length() == 0) {
         // Nothing to insert.
@@ -186,7 +184,7 @@ int32_t NumberStringBuilder::insert(int32_t index, const UnicodeString &unistr,
 }
 
 int32_t
-NumberStringBuilder::insert(int32_t index, const UnicodeString &unistr, int32_t start, int32_t end,
+FormattedStringBuilder::insert(int32_t index, const UnicodeString &unistr, int32_t start, int32_t end,
                             Field field, UErrorCode &status) {
     int32_t count = end - start;
     int32_t position = prepareForInsert(index, count, status);
@@ -201,7 +199,7 @@ NumberStringBuilder::insert(int32_t index, const UnicodeString &unistr, int32_t
 }
 
 int32_t
-NumberStringBuilder::splice(int32_t startThis, int32_t endThis,  const UnicodeString &unistr,
+FormattedStringBuilder::splice(int32_t startThis, int32_t endThis,  const UnicodeString &unistr,
                             int32_t startOther, int32_t endOther, Field field, UErrorCode& status) {
     int32_t thisLength = endThis - startThis;
     int32_t otherLength = endOther - startOther;
@@ -224,12 +222,12 @@ NumberStringBuilder::splice(int32_t startThis, int32_t endThis,  const UnicodeSt
     return count;
 }
 
-int32_t NumberStringBuilder::append(const NumberStringBuilder &other, UErrorCode &status) {
+int32_t FormattedStringBuilder::append(const FormattedStringBuilder &other, UErrorCode &status) {
     return insert(fLength, other, status);
 }
 
 int32_t
-NumberStringBuilder::insert(int32_t index, const NumberStringBuilder &other, UErrorCode &status) {
+FormattedStringBuilder::insert(int32_t index, const FormattedStringBuilder &other, UErrorCode &status) {
     if (this == &other) {
         status = U_ILLEGAL_ARGUMENT_ERROR;
         return 0;
@@ -250,7 +248,7 @@ NumberStringBuilder::insert(int32_t index, const NumberStringBuilder &other, UEr
     return count;
 }
 
-void NumberStringBuilder::writeTerminator(UErrorCode& status) {
+void FormattedStringBuilder::writeTerminator(UErrorCode& status) {
     int32_t position = prepareForInsert(fLength, 1, status);
     if (U_FAILURE(status)) {
         return;
@@ -260,7 +258,7 @@ void NumberStringBuilder::writeTerminator(UErrorCode& status) {
     fLength--;
 }
 
-int32_t NumberStringBuilder::prepareForInsert(int32_t index, int32_t count, UErrorCode &status) {
+int32_t FormattedStringBuilder::prepareForInsert(int32_t index, int32_t count, UErrorCode &status) {
     U_ASSERT(index >= 0);
     U_ASSERT(index <= fLength);
     U_ASSERT(count >= 0);
@@ -279,7 +277,7 @@ int32_t NumberStringBuilder::prepareForInsert(int32_t index, int32_t count, UErr
     }
 }
 
-int32_t NumberStringBuilder::prepareForInsertHelper(int32_t index, int32_t count, UErrorCode &status) {
+int32_t FormattedStringBuilder::prepareForInsertHelper(int32_t index, int32_t count, UErrorCode &status) {
     int32_t oldCapacity = getCapacity();
     int32_t oldZero = fZero;
     char16_t *oldChars = getCharPtr();
@@ -342,7 +340,7 @@ int32_t NumberStringBuilder::prepareForInsertHelper(int32_t index, int32_t count
     return fZero + index;
 }
 
-int32_t NumberStringBuilder::remove(int32_t index, int32_t count) {
+int32_t FormattedStringBuilder::remove(int32_t index, int32_t count) {
     // TODO: Reset the heap here?  (If the string after removal can fit on stack?)
     int32_t position = index + fZero;
     uprv_memmove2(getCharPtr() + position,
@@ -355,18 +353,18 @@ int32_t NumberStringBuilder::remove(int32_t index, int32_t count) {
     return position;
 }
 
-UnicodeString NumberStringBuilder::toUnicodeString() const {
+UnicodeString FormattedStringBuilder::toUnicodeString() const {
     return UnicodeString(getCharPtr() + fZero, fLength);
 }
 
-const UnicodeString NumberStringBuilder::toTempUnicodeString() const {
+const UnicodeString FormattedStringBuilder::toTempUnicodeString() const {
     // Readonly-alias constructor:
     return UnicodeString(FALSE, getCharPtr() + fZero, fLength);
 }
 
-UnicodeString NumberStringBuilder::toDebugString() const {
+UnicodeString FormattedStringBuilder::toDebugString() const {
     UnicodeString sb;
-    sb.append(u"<NumberStringBuilder [", -1);
+    sb.append(u"<FormattedStringBuilder [", -1);
     sb.append(toUnicodeString());
     sb.append(u"] [", -1);
     for (int i = 0; i < fLength; i++) {
@@ -419,11 +417,11 @@ UnicodeString NumberStringBuilder::toDebugString() const {
     return sb;
 }
 
-const char16_t *NumberStringBuilder::chars() const {
+const char16_t *FormattedStringBuilder::chars() const {
     return getCharPtr() + fZero;
 }
 
-bool NumberStringBuilder::contentEquals(const NumberStringBuilder &other) const {
+bool FormattedStringBuilder::contentEquals(const FormattedStringBuilder &other) const {
     if (fLength != other.fLength) {
         return false;
     }
@@ -435,136 +433,7 @@ bool NumberStringBuilder::contentEquals(const NumberStringBuilder &other) const
     return true;
 }
 
-bool NumberStringBuilder::nextFieldPosition(FieldPosition& fp, UErrorCode& status) const {
-    int32_t rawField = fp.getField();
-
-    if (rawField == FieldPosition::DONT_CARE) {
-        return FALSE;
-    }
-
-    if (rawField < 0 || rawField >= UNUM_FIELD_COUNT) {
-        status = U_ILLEGAL_ARGUMENT_ERROR;
-        return FALSE;
-    }
-
-    ConstrainedFieldPosition cfpos;
-    cfpos.constrainField(UFIELD_CATEGORY_NUMBER, rawField);
-    cfpos.setState(UFIELD_CATEGORY_NUMBER, rawField, fp.getBeginIndex(), fp.getEndIndex());
-    if (nextPosition(cfpos, 0, status)) {
-        fp.setBeginIndex(cfpos.getStart());
-        fp.setEndIndex(cfpos.getLimit());
-        return true;
-    }
-
-    // Special case: fraction should start after integer if fraction is not present
-    if (rawField == UNUM_FRACTION_FIELD && fp.getEndIndex() == 0) {
-        bool inside = false;
-        int32_t i = fZero;
-        for (; i < fZero + fLength; i++) {
-            if (isIntOrGroup(getFieldPtr()[i]) || getFieldPtr()[i] == UNUM_DECIMAL_SEPARATOR_FIELD) {
-                inside = true;
-            } else if (inside) {
-                break;
-            }
-        }
-        fp.setBeginIndex(i - fZero);
-        fp.setEndIndex(i - fZero);
-    }
-
-    return false;
-}
-
-void NumberStringBuilder::getAllFieldPositions(FieldPositionIteratorHandler& fpih,
-                                               UErrorCode& status) const {
-    ConstrainedFieldPosition cfpos;
-    while (nextPosition(cfpos, 0, 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;
-
-bool NumberStringBuilder::nextPosition(ConstrainedFieldPosition& cfpos, Field numericField, UErrorCode& /*status*/) const {
-    auto numericCAF = NumFieldUtils::expand(numericField);
-    int32_t fieldStart = -1;
-    Field currField = UNUM_FIELD_COUNT;
-    for (int32_t i = fZero + cfpos.getLimit(); i <= fZero + fLength; i++) {
-        Field _field = (i < fZero + fLength) ? getFieldPtr()[i] : kEndField;
-        // Case 1: currently scanning a field.
-        if (currField != UNUM_FIELD_COUNT) {
-            if (currField != _field) {
-                int32_t end = i - fZero;
-                // Grouping separators can be whitespace; don't throw them out!
-                if (currField != UNUM_GROUPING_SEPARATOR_FIELD) {
-                    end = trimBack(i - fZero);
-                }
-                if (end <= fieldStart) {
-                    // Entire field position is ignorable; skip.
-                    fieldStart = -1;
-                    currField = UNUM_FIELD_COUNT;
-                    i--;  // look at this index again
-                    continue;
-                }
-                int32_t start = fieldStart;
-                if (currField != UNUM_GROUPING_SEPARATOR_FIELD) {
-                    start = trimFront(start);
-                }
-                auto caf = NumFieldUtils::expand(currField);
-                cfpos.setState(caf.category, caf.field, start, end);
-                return true;
-            }
-            continue;
-        }
-        // Special case: coalesce the INTEGER if we are pointing at the end of the INTEGER.
-        if (cfpos.matchesField(UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD)
-                && i > fZero
-                // don't return the same field twice in a row:
-                && i - fZero > cfpos.getLimit()
-                && isIntOrGroup(getFieldPtr()[i - 1])
-                && !isIntOrGroup(_field)) {
-            int j = i - 1;
-            for (; j >= fZero && isIntOrGroup(getFieldPtr()[j]); j--) {}
-            cfpos.setState(UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD, j - fZero + 1, i - fZero);
-            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)
-                && i > fZero
-                // don't return the same field twice in a row:
-                && (i - fZero > cfpos.getLimit()
-                    || cfpos.getCategory() != numericCAF.category
-                    || cfpos.getField() != numericCAF.field)
-                && isNumericField(getFieldPtr()[i - 1])
-                && !isNumericField(_field)) {
-            int j = i - 1;
-            for (; j >= fZero && isNumericField(getFieldPtr()[j]); j--) {}
-            cfpos.setState(numericCAF.category, numericCAF.field, j - fZero + 1, i - fZero);
-            return true;
-        }
-        // Special case: skip over INTEGER; will be coalesced later.
-        if (_field == UNUM_INTEGER_FIELD) {
-            _field = UNUM_FIELD_COUNT;
-        }
-        // Case 2: no field starting at this position.
-        if (_field == UNUM_FIELD_COUNT || _field == kEndField) {
-            continue;
-        }
-        // Case 3: check for field starting at this position
-        auto caf = NumFieldUtils::expand(_field);
-        if (cfpos.matchesField(caf.category, caf.field)) {
-            fieldStart = i - fZero;
-            currField = _field;
-        }
-    }
-
-    U_ASSERT(currField == UNUM_FIELD_COUNT);
-    return false;
-}
-
-bool NumberStringBuilder::containsField(Field field) const {
+bool FormattedStringBuilder::containsField(Field field) const {
     for (int32_t i = 0; i < fLength; i++) {
         if (field == fieldAt(i)) {
             return true;
@@ -573,27 +442,6 @@ bool NumberStringBuilder::containsField(Field field) const {
     return false;
 }
 
-bool NumberStringBuilder::isIntOrGroup(Field field) {
-    return field == UNUM_INTEGER_FIELD
-        || field == UNUM_GROUPING_SEPARATOR_FIELD;
-}
-
-bool NumberStringBuilder::isNumericField(Field field) {
-    return NumFieldUtils::isNumericField(field);
-}
-
-int32_t NumberStringBuilder::trimBack(int32_t limit) const {
-    return unisets::get(unisets::DEFAULT_IGNORABLES)->spanBack(
-        getCharPtr() + fZero,
-        limit,
-        USET_SPAN_CONTAINED);
-}
-
-int32_t NumberStringBuilder::trimFront(int32_t start) const {
-    return start + unisets::get(unisets::DEFAULT_IGNORABLES)->span(
-        getCharPtr() + fZero + start,
-        fLength - start,
-        USET_SPAN_CONTAINED);
-}
+U_NAMESPACE_END
 
 #endif /* #if !UCONFIG_NO_FORMATTING */
similarity index 54%
rename from icu4c/source/i18n/number_stringbuilder.h
rename to icu4c/source/i18n/formatted_string_builder.h
index d48f6e106cf87ea29c46b6445eb7a674aa32df91..cc13b66353d3e94f3b0797ad283f2dc9e12434aa 100644 (file)
@@ -9,17 +9,29 @@
 
 
 #include <cstdint>
-#include "unicode/numfmt.h"
-#include "unicode/ustring.h"
+#include "unicode/unum.h" // for UNUM_FIELD_COUNT
 #include "cstring.h"
 #include "uassert.h"
-#include "number_types.h"
 #include "fphdlimp.h"
 
-U_NAMESPACE_BEGIN namespace number {
-namespace impl {
-
-class U_I18N_API NumberStringBuilder : public UMemory {
+U_NAMESPACE_BEGIN
+
+class FormattedValueStringBuilderImpl;
+
+/**
+ * A StringBuilder optimized for formatting. It implements the following key
+ * features beyond a UnicodeString:
+ *
+ * <ol>
+ * <li>Efficient prepend as well as append.
+ * <li>Keeps tracks of Fields in an efficient manner.
+ * </ol>
+ *
+ * See also FormattedValueStringBuilderImpl.
+ *
+ * @author sffc (Shane Carr)
+ */
+class U_I18N_API FormattedStringBuilder : public UMemory {
   private:
     static const int32_t DEFAULT_CAPACITY = 40;
 
@@ -33,13 +45,19 @@ class U_I18N_API NumberStringBuilder : public UMemory {
     };
 
   public:
-    NumberStringBuilder();
+    FormattedStringBuilder();
+
+    ~FormattedStringBuilder();
 
-    ~NumberStringBuilder();
+    FormattedStringBuilder(const FormattedStringBuilder &other);
 
-    NumberStringBuilder(const NumberStringBuilder &other);
+    // Convention: bottom 4 bits for field, top 4 bits for field category.
+    // 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;
 
-    NumberStringBuilder &operator=(const NumberStringBuilder &other);
+    FormattedStringBuilder &operator=(const FormattedStringBuilder &other);
 
     int32_t length() const;
 
@@ -65,7 +83,7 @@ class U_I18N_API NumberStringBuilder : public UMemory {
 
     UChar32 codePointBefore(int32_t index) const;
 
-    NumberStringBuilder &clear();
+    FormattedStringBuilder &clear();
 
     int32_t appendCodePoint(UChar32 codePoint, Field field, UErrorCode &status);
 
@@ -81,19 +99,19 @@ class U_I18N_API NumberStringBuilder : public UMemory {
     int32_t splice(int32_t startThis, int32_t endThis,  const UnicodeString &unistr,
                    int32_t startOther, int32_t endOther, Field field, UErrorCode& status);
 
-    int32_t append(const NumberStringBuilder &other, UErrorCode &status);
+    int32_t append(const FormattedStringBuilder &other, UErrorCode &status);
 
-    int32_t insert(int32_t index, const NumberStringBuilder &other, UErrorCode &status);
+    int32_t insert(int32_t index, const FormattedStringBuilder &other, UErrorCode &status);
 
     void writeTerminator(UErrorCode& status);
 
     /**
-     * Gets a "safe" UnicodeString that can be used even after the NumberStringBuilder is destructed.
+     * Gets a "safe" UnicodeString that can be used even after the FormattedStringBuilder is destructed.
      * */
     UnicodeString toUnicodeString() const;
 
     /**
-     * Gets an "unsafe" UnicodeString that is valid only as long as the NumberStringBuilder is alive and
+     * Gets an "unsafe" UnicodeString that is valid only as long as the FormattedStringBuilder is alive and
      * unchanged. Slightly faster than toUnicodeString().
      */
     const UnicodeString toTempUnicodeString() const;
@@ -102,13 +120,7 @@ class U_I18N_API NumberStringBuilder : public UMemory {
 
     const char16_t *chars() const;
 
-    bool contentEquals(const NumberStringBuilder &other) const;
-
-    bool nextFieldPosition(FieldPosition& fp, UErrorCode& status) const;
-
-    void getAllFieldPositions(FieldPositionIteratorHandler& fpih, UErrorCode& status) const;
-
-    bool nextPosition(ConstrainedFieldPosition& cfpos, Field numericField, UErrorCode& status) const;
+    bool contentEquals(const FormattedStringBuilder &other) const;
 
     bool containsField(Field field) const;
 
@@ -145,17 +157,50 @@ class U_I18N_API NumberStringBuilder : public UMemory {
 
     int32_t remove(int32_t index, int32_t count);
 
-    static bool isIntOrGroup(Field field);
+    friend class FormattedValueStringBuilderImpl;
+};
 
-    static bool isNumericField(Field field);
+/**
+ * Helper functions for dealing with the Field typedef, which stores fields
+ * in a compressed format.
+ */
+class StringBuilderFieldUtils {
+public:
+    struct CategoryFieldPair {
+        int32_t category;
+        int32_t field;
+    };
 
-    int32_t trimBack(int32_t limit) const;
+    /** 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);
+    }
 
-    int32_t trimFront(int32_t start) const;
+    /** 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;
+    }
+
+    static inline bool isNumericField(FormattedStringBuilder::Field field) {
+        int8_t category = field >> 4;
+        return category == 0 || category == UFIELD_CATEGORY_NUMBER;
+    }
 };
 
-} // namespace impl
-} // namespace number
 U_NAMESPACE_END
 
 
index ee15ed9dfd0f7e583fe37d09dd5dd822887b072d..9aab36a52fecda4eda978713c39a05f3009fd497 100644 (file)
@@ -18,7 +18,7 @@
 #include "fphdlimp.h"
 #include "util.h"
 #include "uvectr32.h"
-#include "number_stringbuilder.h"
+#include "formatted_string_builder.h"
 
 
 /**
@@ -67,7 +67,9 @@ typedef enum UCFPosConstraintType {
 U_NAMESPACE_BEGIN
 
 
-/** Implementation using FieldPositionHandler to accept fields. */
+/**
+ * Implementation of FormattedValue using FieldPositionHandler to accept fields.
+ */
 class FormattedValueFieldPositionIteratorImpl : public UMemory, public FormattedValue {
 public:
 
@@ -112,12 +114,21 @@ private:
 };
 
 
-class FormattedValueNumberStringBuilderImpl : public UMemory, public FormattedValue {
+/**
+ * Implementation of FormattedValue based on FormattedStringBuilder.
+ *
+ * The implementation currently revolves around numbers and number fields.
+ * However, it can be generalized in the future when there is a need.
+ *
+ * @author sffc (Shane Carr)
+ */
+// Exported as U_I18N_API for tests
+class U_I18N_API FormattedValueStringBuilderImpl : public UMemory, public FormattedValue {
 public:
 
-    FormattedValueNumberStringBuilderImpl(number::impl::Field numericField);
+    FormattedValueStringBuilderImpl(FormattedStringBuilder::Field numericField);
 
-    virtual ~FormattedValueNumberStringBuilderImpl();
+    virtual ~FormattedValueStringBuilderImpl();
 
     // Implementation of FormattedValue (const):
 
@@ -126,17 +137,25 @@ public:
     Appendable& appendTo(Appendable& appendable, UErrorCode& status) const U_OVERRIDE;
     UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const U_OVERRIDE;
 
-    inline number::impl::NumberStringBuilder& getStringRef() {
+    // Additional helper functions:
+    UBool nextFieldPosition(FieldPosition& fp, UErrorCode& status) const;
+    void getAllFieldPositions(FieldPositionIteratorHandler& fpih, UErrorCode& status) const;
+    inline FormattedStringBuilder& getStringRef() {
         return fString;
     }
-
-    inline const number::impl::NumberStringBuilder& getStringRef() const {
+    inline const FormattedStringBuilder& getStringRef() const {
         return fString;
     }
 
 private:
-    number::impl::NumberStringBuilder fString;
-    number::impl::Field fNumericField;
+    FormattedStringBuilder fString;
+    FormattedStringBuilder::Field fNumericField;
+
+    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 1fbecf25ac6bb609c7884ca5d12d3af92e610c6f..ca28f222813afc67031ed76fef3a3d41661b7e7a 100644 (file)
 // Other independent implementations should go into their own cpp file for
 // better dependency modularization.
 
+#include "unicode/ustring.h"
 #include "formattedval_impl.h"
+#include "number_types.h"
+#include "formatted_string_builder.h"
+#include "number_utils.h"
+#include "static_unicode_sets.h"
 
 U_NAMESPACE_BEGIN
 
 
-FormattedValueNumberStringBuilderImpl::FormattedValueNumberStringBuilderImpl(number::impl::Field numericField)
+typedef FormattedStringBuilder::Field Field;
+
+
+FormattedValueStringBuilderImpl::FormattedValueStringBuilderImpl(Field numericField)
         : fNumericField(numericField) {
 }
 
-FormattedValueNumberStringBuilderImpl::~FormattedValueNumberStringBuilderImpl() {
+FormattedValueStringBuilderImpl::~FormattedValueStringBuilderImpl() {
 }
 
 
-UnicodeString FormattedValueNumberStringBuilderImpl::toString(UErrorCode&) const {
+UnicodeString FormattedValueStringBuilderImpl::toString(UErrorCode&) const {
     return fString.toUnicodeString();
 }
 
-UnicodeString FormattedValueNumberStringBuilderImpl::toTempString(UErrorCode&) const {
+UnicodeString FormattedValueStringBuilderImpl::toTempString(UErrorCode&) const {
     return fString.toTempUnicodeString();
 }
 
-Appendable& FormattedValueNumberStringBuilderImpl::appendTo(Appendable& appendable, UErrorCode&) const {
+Appendable& FormattedValueStringBuilderImpl::appendTo(Appendable& appendable, UErrorCode&) const {
     appendable.appendString(fString.chars(), fString.length());
     return appendable;
 }
 
-UBool FormattedValueNumberStringBuilderImpl::nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const {
+UBool FormattedValueStringBuilderImpl::nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const {
     // NOTE: MSVC sometimes complains when implicitly converting between bool and UBool
-    return fString.nextPosition(cfpos, fNumericField, status) ? TRUE : FALSE;
+    return nextPositionImpl(cfpos, fNumericField, status) ? TRUE : FALSE;
+}
+
+UBool FormattedValueStringBuilderImpl::nextFieldPosition(FieldPosition& fp, UErrorCode& status) const {
+    int32_t rawField = fp.getField();
+
+    if (rawField == FieldPosition::DONT_CARE) {
+        return FALSE;
+    }
+
+    if (rawField < 0 || rawField >= UNUM_FIELD_COUNT) {
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return FALSE;
+    }
+
+    ConstrainedFieldPosition cfpos;
+    cfpos.constrainField(UFIELD_CATEGORY_NUMBER, rawField);
+    cfpos.setState(UFIELD_CATEGORY_NUMBER, rawField, fp.getBeginIndex(), fp.getEndIndex());
+    if (nextPositionImpl(cfpos, 0, status)) {
+        fp.setBeginIndex(cfpos.getStart());
+        fp.setEndIndex(cfpos.getLimit());
+        return TRUE;
+    }
+
+    // Special case: fraction should start after integer if fraction is not present
+    if (rawField == UNUM_FRACTION_FIELD && fp.getEndIndex() == 0) {
+        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) {
+                inside = true;
+            } else if (inside) {
+                break;
+            }
+        }
+        fp.setBeginIndex(i - fString.fZero);
+        fp.setEndIndex(i - fString.fZero);
+    }
+
+    return FALSE;
+}
+
+void FormattedValueStringBuilderImpl::getAllFieldPositions(FieldPositionIteratorHandler& fpih,
+                                               UErrorCode& status) const {
+    ConstrainedFieldPosition cfpos;
+    while (nextPositionImpl(cfpos, 0, 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;
+
+bool FormattedValueStringBuilderImpl::nextPositionImpl(ConstrainedFieldPosition& cfpos, Field numericField, UErrorCode& /*status*/) const {
+    auto numericCAF = StringBuilderFieldUtils::expand(numericField);
+    int32_t fieldStart = -1;
+    Field currField = UNUM_FIELD_COUNT;
+    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 != _field) {
+                int32_t end = i - fString.fZero;
+                // Grouping separators can be whitespace; don't throw them out!
+                if (currField != UNUM_GROUPING_SEPARATOR_FIELD) {
+                    end = trimBack(i - fString.fZero);
+                }
+                if (end <= fieldStart) {
+                    // Entire field position is ignorable; skip.
+                    fieldStart = -1;
+                    currField = UNUM_FIELD_COUNT;
+                    i--;  // look at this index again
+                    continue;
+                }
+                int32_t start = fieldStart;
+                if (currField != UNUM_GROUPING_SEPARATOR_FIELD) {
+                    start = trimFront(start);
+                }
+                auto caf = StringBuilderFieldUtils::expand(currField);
+                cfpos.setState(caf.category, caf.field, start, end);
+                return true;
+            }
+            continue;
+        }
+        // Special case: coalesce the INTEGER if we are pointing at the end of the INTEGER.
+        if (cfpos.matchesField(UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD)
+                && i > fString.fZero
+                // don't return the same field twice in a row:
+                && i - fString.fZero > cfpos.getLimit()
+                && isIntOrGroup(fString.getFieldPtr()[i - 1])
+                && !isIntOrGroup(_field)) {
+            int j = i - 1;
+            for (; j >= fString.fZero && isIntOrGroup(fString.getFieldPtr()[j]); j--) {}
+            cfpos.setState(
+                UFIELD_CATEGORY_NUMBER,
+                UNUM_INTEGER_FIELD,
+                j - fString.fZero + 1,
+                i - fString.fZero);
+            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)
+                && 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)) {
+            int j = i - 1;
+            for (; j >= fString.fZero && isNumericField(fString.getFieldPtr()[j]); j--) {}
+            cfpos.setState(
+                numericCAF.category,
+                numericCAF.field,
+                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;
+        }
+        // Case 2: no field starting at this position.
+        if (_field == UNUM_FIELD_COUNT || _field == kEndField) {
+            continue;
+        }
+        // Case 3: check for field starting at this position
+        auto caf = StringBuilderFieldUtils::expand(_field);
+        if (cfpos.matchesField(caf.category, caf.field)) {
+            fieldStart = i - fString.fZero;
+            currField = _field;
+        }
+    }
+
+    U_ASSERT(currField == UNUM_FIELD_COUNT);
+    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);
+}
+
+int32_t FormattedValueStringBuilderImpl::trimBack(int32_t limit) const {
+    return unisets::get(unisets::DEFAULT_IGNORABLES)->spanBack(
+        fString.getCharPtr() + fString.fZero,
+        limit,
+        USET_SPAN_CONTAINED);
+}
+
+int32_t FormattedValueStringBuilderImpl::trimFront(int32_t start) const {
+    return start + unisets::get(unisets::DEFAULT_IGNORABLES)->span(
+        fString.getCharPtr() + fString.fZero + start,
+        fString.fLength - start,
+        USET_SPAN_CONTAINED);
 }
 
 
index d2264c1afa6fa306264895a17269076d855ce1ad..49ddc792ad8a789468e3c5148a7d43197b798875 100644 (file)
     <ClCompile Include="number_patternstring.cpp" />
     <ClCompile Include="number_rounding.cpp" />
     <ClCompile Include="number_scientific.cpp" />
-    <ClCompile Include="number_stringbuilder.cpp" />
+    <ClCompile Include="formatted_string_builder.cpp" />
     <ClCompile Include="number_utils.cpp" />
     <ClCompile Include="number_mapper.cpp" />
     <ClCompile Include="number_multiplier.cpp" />
     <ClCompile Include="number_currencysymbols.cpp" />
     <ClCompile Include="number_skeletons.cpp" />
     <ClCompile Include="number_capi.cpp" />
-    <ClCompile Include="numparse_stringsegment.cpp" />
+    <ClCompile Include="string_segment.cpp" />
     <ClCompile Include="numparse_parsednumber.cpp" />
     <ClCompile Include="numparse_impl.cpp" />
     <ClCompile Include="numparse_symbols.cpp" />
     <ClInclude Include="number_patternstring.h" />
     <ClInclude Include="number_roundingutils.h" />
     <ClInclude Include="number_scientific.h" />
-    <ClInclude Include="number_stringbuilder.h" />
+    <ClInclude Include="formatted_string_builder.h" />
     <ClInclude Include="number_types.h" />
     <ClInclude Include="number_utypes.h" />
     <ClInclude Include="number_utils.h" />
     <ClInclude Include="number_multiplier.h" />
     <ClInclude Include="number_currencysymbols.h" />
     <ClInclude Include="number_skeletons.h" />
-    <ClInclude Include="numparse_stringsegment.h" />
+    <ClInclude Include="string_segment.h" />
     <ClInclude Include="numparse_impl.h" />
     <ClInclude Include="numparse_symbols.h" />
     <ClInclude Include="numparse_decimal.h" />
index 5cf379952d881349ee481a8b3a2fa4687ccdffb8..cb393c695b4ad9a6155e0d759e77062108db89c2 100644 (file)
     <ClCompile Include="number_scientific.cpp">
       <Filter>formatting</Filter>
     </ClCompile>
-    <ClCompile Include="number_stringbuilder.cpp">
+    <ClCompile Include="formatted_string_builder.cpp">
       <Filter>formatting</Filter>
     </ClCompile>
     <ClCompile Include="number_utils.cpp">
     <ClCompile Include="number_capi.cpp">
       <Filter>formatting</Filter>
     </ClCompile>
-    <ClCompile Include="numparse_stringsegment.cpp">
+    <ClCompile Include="string_segment.cpp">
       <Filter>formatting</Filter>
     </ClCompile>
     <ClCompile Include="numparse_parsednumber.cpp">
     <ClInclude Include="number_scientific.h">
       <Filter>formatting</Filter>
     </ClInclude>
-    <ClInclude Include="number_stringbuilder.h">
+    <ClInclude Include="formatted_string_builder.h">
       <Filter>formatting</Filter>
     </ClInclude>
     <ClInclude Include="number_types.h">
     <ClInclude Include="number_skeletons.h">
       <Filter>formatting</Filter>
     </ClInclude>
-    <ClInclude Include="numparse_stringsegment.h">
+    <ClInclude Include="string_segment.h">
       <Filter>formatting</Filter>
     </ClInclude>
     <ClInclude Include="numparse_impl.h">
index 4a62c1948051561ead64ccc52d8b88d42c8db450..7580e2a4cb6f4436632d86fb98111bb7d80bb7d0 100644 (file)
     <ClCompile Include="number_patternstring.cpp" />
     <ClCompile Include="number_rounding.cpp" />
     <ClCompile Include="number_scientific.cpp" />
-    <ClCompile Include="number_stringbuilder.cpp" />
+    <ClCompile Include="formatted_string_builder.cpp" />
     <ClCompile Include="number_utils.cpp" />
     <ClCompile Include="number_mapper.cpp" />
     <ClCompile Include="number_multiplier.cpp" />
     <ClCompile Include="number_currencysymbols.cpp" />
     <ClCompile Include="number_skeletons.cpp" />
     <ClCompile Include="number_capi.cpp" />
-    <ClCompile Include="numparse_stringsegment.cpp" />
+    <ClCompile Include="string_segment.cpp" />
     <ClCompile Include="numparse_parsednumber.cpp" />
     <ClCompile Include="numparse_impl.cpp" />
     <ClCompile Include="numparse_symbols.cpp" />
     <ClInclude Include="number_patternstring.h" />
     <ClInclude Include="number_roundingutils.h" />
     <ClInclude Include="number_scientific.h" />
-    <ClInclude Include="number_stringbuilder.h" />
+    <ClInclude Include="formatted_string_builder.h" />
     <ClInclude Include="number_types.h" />
     <ClInclude Include="number_utypes.h" />
     <ClInclude Include="number_utils.h" />
     <ClInclude Include="number_multiplier.h" />
     <ClInclude Include="number_currencysymbols.h" />
     <ClInclude Include="number_skeletons.h" />
-    <ClInclude Include="numparse_stringsegment.h" />
+    <ClInclude Include="string_segment.h" />
     <ClInclude Include="numparse_impl.h" />
     <ClInclude Include="numparse_symbols.h" />
     <ClInclude Include="numparse_decimal.h" />
index 3eb9c59bf4909006bcd724c7f8b38ac16a105b4c..3b1b42fe353a96abf21527ffa3da8b9a83228784 100644 (file)
@@ -156,7 +156,7 @@ Field AffixUtils::getFieldForType(AffixPatternType type) {
 }
 
 int32_t
-AffixUtils::unescape(const UnicodeString &affixPattern, NumberStringBuilder &output, int32_t position,
+AffixUtils::unescape(const UnicodeString &affixPattern, FormattedStringBuilder &output, int32_t position,
                      const SymbolProvider &provider, Field field, UErrorCode &status) {
     int32_t length = 0;
     AffixTag tag;
index f011a54b316166879d818c5b65c9d8e7787dcbfd..5cfde61ffd0ca2c1591fb9e1252439705d95fc8b 100644 (file)
@@ -11,7 +11,7 @@
 #include "number_types.h"
 #include "unicode/stringpiece.h"
 #include "unicode/unistr.h"
-#include "number_stringbuilder.h"
+#include "formatted_string_builder.h"
 #include "unicode/uniset.h"
 
 U_NAMESPACE_BEGIN namespace number {
@@ -134,16 +134,16 @@ class U_I18N_API AffixUtils {
     /**
      * Executes the unescape state machine. Replaces the unquoted characters "-", "+", "%", "‰", and
      * "¤" with the corresponding symbols provided by the {@link SymbolProvider}, and inserts the
-     * result into the NumberStringBuilder at the requested location.
+     * result into the FormattedStringBuilder at the requested location.
      *
      * <p>Example input: "'-'¤x"; example output: "-$x"
      *
      * @param affixPattern The original string to be unescaped.
-     * @param output The NumberStringBuilder to mutate with the result.
-     * @param position The index into the NumberStringBuilder to insert the string.
+     * @param output The FormattedStringBuilder to mutate with the result.
+     * @param position The index into the FormattedStringBuilder to insert the string.
      * @param provider An object to generate locale symbols.
      */
-    static int32_t unescape(const UnicodeString& affixPattern, NumberStringBuilder& output,
+    static int32_t unescape(const UnicodeString& affixPattern, FormattedStringBuilder& output,
                             int32_t position, const SymbolProvider& provider, Field field,
                             UErrorCode& status);
 
index 9d3ea69f578e1eb8757f08b27d76cad9d676d2e0..974dfba3c19bd3f2ac15613d6dbf6e38258119cb 100644 (file)
@@ -62,12 +62,12 @@ UnicodeString& LocalizedNumberFormatterAsFormat::format(const Formattable& obj,
     // always return first occurrence:
     pos.setBeginIndex(0);
     pos.setEndIndex(0);
-    bool found = data.getStringRef().nextFieldPosition(pos, status);
+    bool found = data.nextFieldPosition(pos, status);
     if (found && appendTo.length() != 0) {
         pos.setBeginIndex(pos.getBeginIndex() + appendTo.length());
         pos.setEndIndex(pos.getEndIndex() + appendTo.length());
     }
-    appendTo.append(data.getStringRef().toTempUnicodeString());
+    appendTo.append(data.toTempString(status));
     return appendTo;
 }
 
@@ -84,10 +84,10 @@ UnicodeString& LocalizedNumberFormatterAsFormat::format(const Formattable& obj,
     if (U_FAILURE(status)) {
         return appendTo;
     }
-    appendTo.append(data.getStringRef().toTempUnicodeString());
+    appendTo.append(data.toTempString(status));
     if (posIter != nullptr) {
         FieldPositionIteratorHandler fpih(posIter, status);
-        data.getStringRef().getAllFieldPositions(fpih, status);
+        data.getAllFieldPositions(fpih, status);
     }
     return appendTo;
 }
index 09e0905609eb302b6e833d73d4f101fbac97f02a..bd49a121013f4598cf80dcc37fa2a20cf5a9eea8 100644 (file)
@@ -696,7 +696,7 @@ void LocalizedNumberFormatter::formatImpl(impl::UFormattedNumberData* results, U
 
 void LocalizedNumberFormatter::getAffixImpl(bool isPrefix, bool isNegative, UnicodeString& result,
                                             UErrorCode& status) const {
-    NumberStringBuilder string;
+    FormattedStringBuilder string;
     auto signum = static_cast<int8_t>(isNegative ? -1 : 1);
     // Always return affixes for plural form OTHER.
     static const StandardPlural::Form plural = StandardPlural::OTHER;
index 08b833beb7ad2e29a1e22775e46bc36a3ad24267..8741af39df123e86d9bd914e392cf33e958f60ad 100644 (file)
@@ -72,7 +72,7 @@ NumberFormatterImpl::NumberFormatterImpl(const MacroProps& macros, UErrorCode& s
 }
 
 int32_t NumberFormatterImpl::formatStatic(const MacroProps& macros, DecimalQuantity& inValue,
-                                       NumberStringBuilder& outString, UErrorCode& status) {
+                                       FormattedStringBuilder& outString, UErrorCode& status) {
     NumberFormatterImpl impl(macros, false, status);
     MicroProps& micros = impl.preProcessUnsafe(inValue, status);
     if (U_FAILURE(status)) { return 0; }
@@ -83,7 +83,7 @@ int32_t NumberFormatterImpl::formatStatic(const MacroProps& macros, DecimalQuant
 
 int32_t NumberFormatterImpl::getPrefixSuffixStatic(const MacroProps& macros, int8_t signum,
                                                    StandardPlural::Form plural,
-                                                   NumberStringBuilder& outString, UErrorCode& status) {
+                                                   FormattedStringBuilder& outString, UErrorCode& status) {
     NumberFormatterImpl impl(macros, false, status);
     return impl.getPrefixSuffixUnsafe(signum, plural, outString, status);
 }
@@ -93,7 +93,7 @@ int32_t NumberFormatterImpl::getPrefixSuffixStatic(const MacroProps& macros, int
 // The "unsafe" method simply re-uses fMicros, eliminating the extra copy operation.
 // See MicroProps::processQuantity() for details.
 
-int32_t NumberFormatterImpl::format(DecimalQuantity& inValue, NumberStringBuilder& outString,
+int32_t NumberFormatterImpl::format(DecimalQuantity& inValue, FormattedStringBuilder& outString,
                                 UErrorCode& status) const {
     MicroProps micros;
     preProcess(inValue, micros, status);
@@ -130,7 +130,7 @@ MicroProps& NumberFormatterImpl::preProcessUnsafe(DecimalQuantity& inValue, UErr
 }
 
 int32_t NumberFormatterImpl::getPrefixSuffix(int8_t signum, StandardPlural::Form plural,
-                                             NumberStringBuilder& outString, UErrorCode& status) const {
+                                             FormattedStringBuilder& outString, UErrorCode& status) const {
     if (U_FAILURE(status)) { return 0; }
     // #13453: DecimalFormat wants the affixes from the pattern only (modMiddle, aka pattern modifier).
     // Safe path: use fImmutablePatternModifier.
@@ -141,7 +141,7 @@ int32_t NumberFormatterImpl::getPrefixSuffix(int8_t signum, StandardPlural::Form
 }
 
 int32_t NumberFormatterImpl::getPrefixSuffixUnsafe(int8_t signum, StandardPlural::Form plural,
-                                                   NumberStringBuilder& outString, UErrorCode& status) {
+                                                   FormattedStringBuilder& outString, UErrorCode& status) {
     if (U_FAILURE(status)) { return 0; }
     // #13453: DecimalFormat wants the affixes from the pattern only (modMiddle, aka pattern modifier).
     // Unsafe path: use fPatternModifier.
@@ -430,7 +430,7 @@ NumberFormatterImpl::resolvePluralRules(const PluralRules* rulesPtr, const Local
     return fRules.getAlias();
 }
 
-int32_t NumberFormatterImpl::writeAffixes(const MicroProps& micros, NumberStringBuilder& string,
+int32_t NumberFormatterImpl::writeAffixes(const MicroProps& micros, FormattedStringBuilder& string,
                                           int32_t start, int32_t end, UErrorCode& status) {
     // Always apply the inner modifier (which is "strong").
     int32_t length = micros.modInner->apply(string, start, end, status);
@@ -445,7 +445,7 @@ int32_t NumberFormatterImpl::writeAffixes(const MicroProps& micros, NumberString
 }
 
 int32_t NumberFormatterImpl::writeNumber(const MicroProps& micros, DecimalQuantity& quantity,
-                                         NumberStringBuilder& string, int32_t index,
+                                         FormattedStringBuilder& string, int32_t index,
                                          UErrorCode& status) {
     int32_t length = 0;
     if (quantity.isInfinite()) {
@@ -487,7 +487,7 @@ int32_t NumberFormatterImpl::writeNumber(const MicroProps& micros, DecimalQuanti
 }
 
 int32_t NumberFormatterImpl::writeIntegerDigits(const MicroProps& micros, DecimalQuantity& quantity,
-                                                NumberStringBuilder& string, int32_t index,
+                                                FormattedStringBuilder& string, int32_t index,
                                                 UErrorCode& status) {
     int length = 0;
     int integerCount = quantity.getUpperDisplayMagnitude() + 1;
@@ -513,7 +513,7 @@ int32_t NumberFormatterImpl::writeIntegerDigits(const MicroProps& micros, Decima
 }
 
 int32_t NumberFormatterImpl::writeFractionDigits(const MicroProps& micros, DecimalQuantity& quantity,
-                                                 NumberStringBuilder& string, int32_t index,
+                                                 FormattedStringBuilder& string, int32_t index,
                                                  UErrorCode& status) {
     int length = 0;
     int fractionCount = -quantity.getLowerDisplayMagnitude();
index fd8708c532e13196cd69c7507a99db4a8ffd5d8f..44753c0392f58fda533f7833d6ce5c35b9bd9a9b 100644 (file)
@@ -8,7 +8,7 @@
 #define __NUMBER_FORMATIMPL_H__
 
 #include "number_types.h"
-#include "number_stringbuilder.h"
+#include "formatted_string_builder.h"
 #include "number_patternstring.h"
 #include "number_utils.h"
 #include "number_patternmodifier.h"
@@ -35,7 +35,7 @@ class NumberFormatterImpl : public UMemory {
      * Builds and evaluates an "unsafe" MicroPropsGenerator, which is cheaper but can be used only once.
      */
     static int32_t
-    formatStatic(const MacroProps &macros, DecimalQuantity &inValue, NumberStringBuilder &outString,
+    formatStatic(const MacroProps &macros, DecimalQuantity &inValue, FormattedStringBuilder &outString,
                  UErrorCode &status);
 
     /**
@@ -45,13 +45,13 @@ class NumberFormatterImpl : public UMemory {
      *         the prefix length.
      */
     static int32_t getPrefixSuffixStatic(const MacroProps& macros, int8_t signum,
-                                         StandardPlural::Form plural, NumberStringBuilder& outString,
+                                         StandardPlural::Form plural, FormattedStringBuilder& outString,
                                          UErrorCode& status);
 
     /**
      * Evaluates the "safe" MicroPropsGenerator created by "fromMacros".
      */
-    int32_t format(DecimalQuantity& inValue, NumberStringBuilder& outString, UErrorCode& status) const;
+    int32_t format(DecimalQuantity& inValue, FormattedStringBuilder& outString, UErrorCode& status) const;
 
     /**
      * Like format(), but saves the result into an output MicroProps without additional processing.
@@ -61,7 +61,7 @@ class NumberFormatterImpl : public UMemory {
     /**
      * Like getPrefixSuffixStatic() but uses the safe compiled object.
      */
-    int32_t getPrefixSuffix(int8_t signum, StandardPlural::Form plural, NumberStringBuilder& outString,
+    int32_t getPrefixSuffix(int8_t signum, StandardPlural::Form plural, FormattedStringBuilder& outString,
                             UErrorCode& status) const;
 
     const MicroProps& getRawMicroProps() const {
@@ -73,12 +73,12 @@ class NumberFormatterImpl : public UMemory {
      * This method formats only the main number, not affixes.
      */
     static int32_t writeNumber(const MicroProps& micros, DecimalQuantity& quantity,
-                               NumberStringBuilder& string, int32_t index, UErrorCode& status);
+                               FormattedStringBuilder& string, int32_t index, UErrorCode& status);
 
     /**
      * Adds the affixes.  Intended to be called immediately after formatNumber.
      */
-    static int32_t writeAffixes(const MicroProps& micros, NumberStringBuilder& string, int32_t start,
+    static int32_t writeAffixes(const MicroProps& micros, FormattedStringBuilder& string, int32_t start,
                                 int32_t end, UErrorCode& status);
 
   private:
@@ -110,7 +110,7 @@ class NumberFormatterImpl : public UMemory {
     MicroProps& preProcessUnsafe(DecimalQuantity &inValue, UErrorCode &status);
 
     int32_t getPrefixSuffixUnsafe(int8_t signum, StandardPlural::Form plural,
-                                  NumberStringBuilder& outString, UErrorCode& status);
+                                  FormattedStringBuilder& outString, UErrorCode& status);
 
     /**
      * If rulesPtr is non-null, return it.  Otherwise, return a PluralRules owned by this object for the
@@ -136,11 +136,11 @@ class NumberFormatterImpl : public UMemory {
     macrosToMicroGenerator(const MacroProps &macros, bool safe, UErrorCode &status);
 
     static int32_t
-    writeIntegerDigits(const MicroProps &micros, DecimalQuantity &quantity, NumberStringBuilder &string,
+    writeIntegerDigits(const MicroProps &micros, DecimalQuantity &quantity, FormattedStringBuilder &string,
                        int32_t index, UErrorCode &status);
 
     static int32_t
-    writeFractionDigits(const MicroProps &micros, DecimalQuantity &quantity, NumberStringBuilder &string,
+    writeFractionDigits(const MicroProps &micros, DecimalQuantity &quantity, FormattedStringBuilder &string,
                         int32_t index, UErrorCode &status);
 };
 
index 1fcbe7b9b79301de84a0bd9fc1a6816b19105b95..aa6cf57d2351e1c6a50d2bafadf27aa462d33492 100644 (file)
@@ -69,7 +69,7 @@ AdoptingModifierStore::~AdoptingModifierStore()  {
 }
 
 
-int32_t ConstantAffixModifier::apply(NumberStringBuilder &output, int leftIndex, int rightIndex,
+int32_t ConstantAffixModifier::apply(FormattedStringBuilder &output, int leftIndex, int rightIndex,
                                      UErrorCode &status) const {
     // Insert the suffix first since inserting the prefix will change the rightIndex
     int length = output.insert(rightIndex, fSuffix, fField, status);
@@ -154,7 +154,7 @@ SimpleModifier::SimpleModifier()
         : fField(UNUM_FIELD_COUNT), fStrong(false), fPrefixLength(0), fSuffixLength(0) {
 }
 
-int32_t SimpleModifier::apply(NumberStringBuilder &output, int leftIndex, int rightIndex,
+int32_t SimpleModifier::apply(FormattedStringBuilder &output, int leftIndex, int rightIndex,
                               UErrorCode &status) const {
     return formatAsPrefixSuffix(output, leftIndex, rightIndex, status);
 }
@@ -203,7 +203,7 @@ bool SimpleModifier::semanticallyEquivalent(const Modifier& other) const {
 
 
 int32_t
-SimpleModifier::formatAsPrefixSuffix(NumberStringBuilder &result, int32_t startIndex, int32_t endIndex,
+SimpleModifier::formatAsPrefixSuffix(FormattedStringBuilder &result, int32_t startIndex, int32_t endIndex,
                                      UErrorCode &status) const {
     if (fSuffixOffset == -1 && fPrefixLength + fSuffixLength > 0) {
         // There is no argument for the inner number; overwrite the entire segment with our string.
@@ -227,7 +227,7 @@ SimpleModifier::formatAsPrefixSuffix(NumberStringBuilder &result, int32_t startI
 
 
 int32_t
-SimpleModifier::formatTwoArgPattern(const SimpleFormatter& compiled, NumberStringBuilder& result,
+SimpleModifier::formatTwoArgPattern(const SimpleFormatter& compiled, FormattedStringBuilder& result,
                                     int32_t index, int32_t* outPrefixLength, int32_t* outSuffixLength,
                                     Field field, UErrorCode& status) {
     const UnicodeString& compiledPattern = compiled.compiledPattern;
@@ -284,7 +284,7 @@ SimpleModifier::formatTwoArgPattern(const SimpleFormatter& compiled, NumberStrin
 }
 
 
-int32_t ConstantMultiFieldModifier::apply(NumberStringBuilder &output, int leftIndex, int rightIndex,
+int32_t ConstantMultiFieldModifier::apply(FormattedStringBuilder &output, int leftIndex, int rightIndex,
                                           UErrorCode &status) const {
     int32_t length = output.insert(leftIndex, fPrefix, status);
     if (fOverwrite) {
@@ -333,8 +333,8 @@ bool ConstantMultiFieldModifier::semanticallyEquivalent(const Modifier& other) c
 }
 
 
-CurrencySpacingEnabledModifier::CurrencySpacingEnabledModifier(const NumberStringBuilder &prefix,
-                                                               const NumberStringBuilder &suffix,
+CurrencySpacingEnabledModifier::CurrencySpacingEnabledModifier(const FormattedStringBuilder &prefix,
+                                                               const FormattedStringBuilder &suffix,
                                                                bool overwrite,
                                                                bool strong,
                                                                const DecimalFormatSymbols &symbols,
@@ -374,7 +374,7 @@ CurrencySpacingEnabledModifier::CurrencySpacingEnabledModifier(const NumberStrin
     }
 }
 
-int32_t CurrencySpacingEnabledModifier::apply(NumberStringBuilder &output, int leftIndex, int rightIndex,
+int32_t CurrencySpacingEnabledModifier::apply(FormattedStringBuilder &output, int leftIndex, int rightIndex,
                                               UErrorCode &status) const {
     // Currency spacing logic
     int length = 0;
@@ -395,7 +395,7 @@ int32_t CurrencySpacingEnabledModifier::apply(NumberStringBuilder &output, int l
 }
 
 int32_t
-CurrencySpacingEnabledModifier::applyCurrencySpacing(NumberStringBuilder &output, int32_t prefixStart,
+CurrencySpacingEnabledModifier::applyCurrencySpacing(FormattedStringBuilder &output, int32_t prefixStart,
                                                      int32_t prefixLen, int32_t suffixStart,
                                                      int32_t suffixLen,
                                                      const DecimalFormatSymbols &symbols,
@@ -414,7 +414,7 @@ CurrencySpacingEnabledModifier::applyCurrencySpacing(NumberStringBuilder &output
 }
 
 int32_t
-CurrencySpacingEnabledModifier::applyCurrencySpacingAffix(NumberStringBuilder &output, int32_t index,
+CurrencySpacingEnabledModifier::applyCurrencySpacingAffix(FormattedStringBuilder &output, int32_t index,
                                                           EAffix affix,
                                                           const DecimalFormatSymbols &symbols,
                                                           UErrorCode &status) {
index 495128bb149dcff43fa1e257a5a9ba58e33cb6c3..5c13c873463433892a8c25cd51b2a5e7e5f41ac2 100644 (file)
@@ -12,7 +12,7 @@
 #include "unicode/uniset.h"
 #include "unicode/simpleformatter.h"
 #include "standardplural.h"
-#include "number_stringbuilder.h"
+#include "formatted_string_builder.h"
 #include "number_types.h"
 
 U_NAMESPACE_BEGIN namespace number {
@@ -28,7 +28,7 @@ class U_I18N_API ConstantAffixModifier : public Modifier, public UObject {
                           bool strong)
             : fPrefix(prefix), fSuffix(suffix), fField(field), fStrong(strong) {}
 
-    int32_t apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
+    int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
                   UErrorCode &status) const U_OVERRIDE;
 
     int32_t getPrefixLength() const U_OVERRIDE;
@@ -64,7 +64,7 @@ class U_I18N_API SimpleModifier : public Modifier, public UMemory {
     // Default constructor for LongNameHandler.h
     SimpleModifier();
 
-    int32_t apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
+    int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
                   UErrorCode &status) const U_OVERRIDE;
 
     int32_t getPrefixLength() const U_OVERRIDE;
@@ -81,7 +81,7 @@ class U_I18N_API SimpleModifier : public Modifier, public UMemory {
 
     /**
      * TODO: This belongs in SimpleFormatterImpl. The only reason I haven't moved it there yet is because
-     * NumberStringBuilder is an internal class and SimpleFormatterImpl feels like it should not depend on it.
+     * FormattedStringBuilder is an internal class and SimpleFormatterImpl feels like it should not depend on it.
      *
      * <p>
      * Formats a value that is already stored inside the StringBuilder <code>result</code> between the indices
@@ -100,22 +100,22 @@ class U_I18N_API SimpleModifier : public Modifier, public UMemory {
      * @return The number of characters (UTF-16 code points) that were added to the StringBuilder.
      */
     int32_t
-    formatAsPrefixSuffix(NumberStringBuilder& result, int32_t startIndex, int32_t endIndex,
+    formatAsPrefixSuffix(FormattedStringBuilder& result, int32_t startIndex, int32_t endIndex,
                          UErrorCode& status) const;
 
     /**
      * TODO: Like above, this belongs with the rest of the SimpleFormatterImpl code.
-     * I put it here so that the SimpleFormatter uses in NumberStringBuilder are near each other.
+     * I put it here so that the SimpleFormatter uses in FormattedStringBuilder are near each other.
      *
      * <p>
-     * Applies the compiled two-argument pattern to the NumberStringBuilder.
+     * Applies the compiled two-argument pattern to the FormattedStringBuilder.
      *
      * <p>
      * This method is optimized for the case where the prefix and suffix are often empty, such as
      * in the range pattern like "{0}-{1}".
      */
     static int32_t
-    formatTwoArgPattern(const SimpleFormatter& compiled, NumberStringBuilder& result,
+    formatTwoArgPattern(const SimpleFormatter& compiled, FormattedStringBuilder& result,
                         int32_t index, int32_t* outPrefixLength, int32_t* outSuffixLength,
                         Field field, UErrorCode& status);
 
@@ -131,13 +131,13 @@ class U_I18N_API SimpleModifier : public Modifier, public UMemory {
 
 /**
  * An implementation of {@link Modifier} that allows for multiple types of fields in the same modifier. Constructed
- * based on the contents of two {@link NumberStringBuilder} instances (one for the prefix, one for the suffix).
+ * based on the contents of two {@link FormattedStringBuilder} instances (one for the prefix, one for the suffix).
  */
 class U_I18N_API ConstantMultiFieldModifier : public Modifier, public UMemory {
   public:
     ConstantMultiFieldModifier(
-            const NumberStringBuilder &prefix,
-            const NumberStringBuilder &suffix,
+            const FormattedStringBuilder &prefix,
+            const FormattedStringBuilder &suffix,
             bool overwrite,
             bool strong,
             const Modifier::Parameters parameters)
@@ -148,8 +148,8 @@ class U_I18N_API ConstantMultiFieldModifier : public Modifier, public UMemory {
         fParameters(parameters) {}
 
     ConstantMultiFieldModifier(
-            const NumberStringBuilder &prefix,
-            const NumberStringBuilder &suffix,
+            const FormattedStringBuilder &prefix,
+            const FormattedStringBuilder &suffix,
             bool overwrite,
             bool strong)
       : fPrefix(prefix),
@@ -157,7 +157,7 @@ class U_I18N_API ConstantMultiFieldModifier : public Modifier, public UMemory {
         fOverwrite(overwrite),
         fStrong(strong) {}
 
-    int32_t apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
+    int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
                   UErrorCode &status) const U_OVERRIDE;
 
     int32_t getPrefixLength() const U_OVERRIDE;
@@ -173,10 +173,10 @@ class U_I18N_API ConstantMultiFieldModifier : public Modifier, public UMemory {
     bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
 
   protected:
-    // NOTE: In Java, these are stored as array pointers. In C++, the NumberStringBuilder is stored by
+    // NOTE: In Java, these are stored as array pointers. In C++, the FormattedStringBuilder is stored by
     // value and is treated internally as immutable.
-    NumberStringBuilder fPrefix;
-    NumberStringBuilder fSuffix;
+    FormattedStringBuilder fPrefix;
+    FormattedStringBuilder fSuffix;
     bool fOverwrite;
     bool fStrong;
     Modifier::Parameters fParameters;
@@ -187,19 +187,19 @@ class U_I18N_API CurrencySpacingEnabledModifier : public ConstantMultiFieldModif
   public:
     /** Safe code path */
     CurrencySpacingEnabledModifier(
-            const NumberStringBuilder &prefix,
-            const NumberStringBuilder &suffix,
+            const FormattedStringBuilder &prefix,
+            const FormattedStringBuilder &suffix,
             bool overwrite,
             bool strong,
             const DecimalFormatSymbols &symbols,
             UErrorCode &status);
 
-    int32_t apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
+    int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
                   UErrorCode &status) const U_OVERRIDE;
 
     /** Unsafe code path */
     static int32_t
-    applyCurrencySpacing(NumberStringBuilder &output, int32_t prefixStart, int32_t prefixLen,
+    applyCurrencySpacing(FormattedStringBuilder &output, int32_t prefixStart, int32_t prefixLen,
                          int32_t suffixStart, int32_t suffixLen, const DecimalFormatSymbols &symbols,
                          UErrorCode &status);
 
@@ -218,7 +218,7 @@ class U_I18N_API CurrencySpacingEnabledModifier : public ConstantMultiFieldModif
     };
 
     /** Unsafe code path */
-    static int32_t applyCurrencySpacingAffix(NumberStringBuilder &output, int32_t index, EAffix affix,
+    static int32_t applyCurrencySpacingAffix(FormattedStringBuilder &output, int32_t index, EAffix affix,
                                              const DecimalFormatSymbols &symbols, UErrorCode &status);
 
     static UnicodeSet
@@ -234,7 +234,7 @@ class U_I18N_API EmptyModifier : public Modifier, public UMemory {
   public:
     explicit EmptyModifier(bool isStrong) : fStrong(isStrong) {}
 
-    int32_t apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
+    int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
                   UErrorCode &status) const U_OVERRIDE {
         (void)output;
         (void)leftIndex;
index 1e86f2f983366a73dd1e1109d4f52fd22335f22a..888a9f254634d667c38547c96ff6b86068ce5c8b 100644 (file)
@@ -19,8 +19,7 @@ UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(FormattedNumber)
 
 UBool FormattedNumber::nextFieldPosition(FieldPosition& fieldPosition, UErrorCode& status) const {
     UPRV_FORMATTED_VALUE_METHOD_GUARD(FALSE)
-    // NOTE: MSVC sometimes complains when implicitly converting between bool and UBool
-    return fData->getStringRef().nextFieldPosition(fieldPosition, status) ? TRUE : FALSE;
+    return fData->nextFieldPosition(fieldPosition, status);
 }
 
 void FormattedNumber::getAllFieldPositions(FieldPositionIterator& iterator, UErrorCode& status) const {
@@ -31,7 +30,7 @@ void FormattedNumber::getAllFieldPositions(FieldPositionIterator& iterator, UErr
 void FormattedNumber::getAllFieldPositionsImpl(FieldPositionIteratorHandler& fpih,
                                                UErrorCode& status) const {
     UPRV_FORMATTED_VALUE_METHOD_GUARD()
-    fData->getStringRef().getAllFieldPositions(fpih, status);
+    fData->getAllFieldPositions(fpih, status);
 }
 
 void FormattedNumber::getDecimalQuantity(impl::DecimalQuantity& output, UErrorCode& status) const {
index 31684d7208b6068583ae5747852af97762dc6c6d..c68a9875b2055f18fb23606161dd3453c8f5e103 100644 (file)
@@ -7,7 +7,7 @@
 
 #include "unicode/numberformatter.h"
 #include "number_types.h"
-#include "number_stringbuilder.h"
+#include "formatted_string_builder.h"
 #include "number_decimfmtprops.h"
 
 using namespace icu;
@@ -17,7 +17,7 @@ using namespace icu::number::impl;
 namespace {
 
 int32_t
-addPaddingHelper(UChar32 paddingCp, int32_t requiredPadding, NumberStringBuilder &string, int32_t index,
+addPaddingHelper(UChar32 paddingCp, int32_t requiredPadding, FormattedStringBuilder &string, int32_t index,
                  UErrorCode &status) {
     for (int32_t i = 0; i < requiredPadding; i++) {
         // TODO: If appending to the end, this will cause actual insertion operations. Improve.
@@ -60,7 +60,7 @@ Padder Padder::forProperties(const DecimalFormatProperties& properties) {
 }
 
 int32_t Padder::padAndApply(const Modifier &mod1, const Modifier &mod2,
-                            NumberStringBuilder &string, int32_t leftIndex, int32_t rightIndex,
+                            FormattedStringBuilder &string, int32_t leftIndex, int32_t rightIndex,
                             UErrorCode &status) const {
     int32_t modLength = mod1.getCodePointCount() + mod2.getCodePointCount();
     int32_t requiredPadding = fWidth - modLength - string.codePointCount();
index 75de439f3ed2e16ec5dfccb572c0892075f07547..8f3af2a54522ee9a9585ee6e0ea7b1f21aae78ab 100644 (file)
@@ -108,8 +108,8 @@ MutablePatternModifier::createImmutableAndChain(const MicroPropsGenerator* paren
 }
 
 ConstantMultiFieldModifier* MutablePatternModifier::createConstantModifier(UErrorCode& status) {
-    NumberStringBuilder a;
-    NumberStringBuilder b;
+    FormattedStringBuilder a;
+    FormattedStringBuilder b;
     insertPrefix(a, 0, status);
     insertSuffix(b, 0, status);
     if (fPatternInfo->hasCurrencySign()) {
@@ -170,7 +170,7 @@ void MutablePatternModifier::processQuantity(DecimalQuantity& fq, MicroProps& mi
     micros.modMiddle = this;
 }
 
-int32_t MutablePatternModifier::apply(NumberStringBuilder& output, int32_t leftIndex, int32_t rightIndex,
+int32_t MutablePatternModifier::apply(FormattedStringBuilder& output, int32_t leftIndex, int32_t rightIndex,
                                       UErrorCode& status) const {
     // The unsafe code path performs self-mutation, so we need a const_cast.
     // This method needs to be const because it overrides a const method in the parent class.
@@ -248,13 +248,13 @@ bool MutablePatternModifier::semanticallyEquivalent(const Modifier& other) const
     UPRV_UNREACHABLE;
 }
 
-int32_t MutablePatternModifier::insertPrefix(NumberStringBuilder& sb, int position, UErrorCode& status) {
+int32_t MutablePatternModifier::insertPrefix(FormattedStringBuilder& sb, int position, UErrorCode& status) {
     prepareAffix(true);
     int32_t length = AffixUtils::unescape(currentAffix, sb, position, *this, fField, status);
     return length;
 }
 
-int32_t MutablePatternModifier::insertSuffix(NumberStringBuilder& sb, int position, UErrorCode& status) {
+int32_t MutablePatternModifier::insertSuffix(FormattedStringBuilder& sb, int position, UErrorCode& status) {
     prepareAffix(false);
     int32_t length = AffixUtils::unescape(currentAffix, sb, position, *this, fField, status);
     return length;
index 27e293b64ce50fa77c16b3227cf1b22d4852933d..59ea02fe99ce52560663f5347b88d7dc818f7546 100644 (file)
@@ -184,7 +184,7 @@ class U_I18N_API MutablePatternModifier
 
     void processQuantity(DecimalQuantity &, MicroProps &micros, UErrorCode &status) const U_OVERRIDE;
 
-    int32_t apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
+    int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
                   UErrorCode &status) const U_OVERRIDE;
 
     int32_t getPrefixLength() const U_OVERRIDE;
@@ -240,17 +240,17 @@ class U_I18N_API MutablePatternModifier
      * CREATES A NEW HEAP OBJECT; THE CALLER GETS OWNERSHIP.
      *
      * @param a
-     *            A working NumberStringBuilder object; passed from the outside to prevent the need to create many new
+     *            A working FormattedStringBuilder object; passed from the outside to prevent the need to create many new
      *            instances if this method is called in a loop.
      * @param b
-     *            Another working NumberStringBuilder object.
+     *            Another working FormattedStringBuilder object.
      * @return The constant modifier object.
      */
     ConstantMultiFieldModifier *createConstantModifier(UErrorCode &status);
 
-    int32_t insertPrefix(NumberStringBuilder &sb, int position, UErrorCode &status);
+    int32_t insertPrefix(FormattedStringBuilder &sb, int position, UErrorCode &status);
 
-    int32_t insertSuffix(NumberStringBuilder &sb, int position, UErrorCode &status);
+    int32_t insertSuffix(FormattedStringBuilder &sb, int position, UErrorCode &status);
 
     void prepareAffix(bool isPrefix);
 };
index 7fab29c36bdc702c48a0639e9e801f39a86982e7..6fb4c19b03d54a5c86161babf1b55abf906f1c18 100644 (file)
@@ -8,7 +8,7 @@
 #include <cstdlib>
 #include "number_scientific.h"
 #include "number_utils.h"
-#include "number_stringbuilder.h"
+#include "formatted_string_builder.h"
 #include "unicode/unum.h"
 #include "number_microprops.h"
 
@@ -36,7 +36,7 @@ void ScientificModifier::set(int32_t exponent, const ScientificHandler *handler)
     fHandler = handler;
 }
 
-int32_t ScientificModifier::apply(NumberStringBuilder &output, int32_t /*leftIndex*/, int32_t rightIndex,
+int32_t ScientificModifier::apply(FormattedStringBuilder &output, int32_t /*leftIndex*/, int32_t rightIndex,
                                   UErrorCode &status) const {
     // FIXME: Localized exponent separator location.
     int i = rightIndex;
index e377bd941efaeb07ac7d9cdc00cd519cb443d3e5..1c9ce1efa80a3f408a2f6599fbb1545d26efca17 100644 (file)
@@ -21,7 +21,7 @@ class U_I18N_API ScientificModifier : public UMemory, public Modifier {
 
     void set(int32_t exponent, const ScientificHandler *handler);
 
-    int32_t apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
+    int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
                   UErrorCode &status) const U_OVERRIDE;
 
     int32_t getPrefixLength() const U_OVERRIDE;
index 7e06cab009b0c6b3ffe03fbeaae842bdf17aa051..c65a393215dc0d08925cc76eeec93eee5176f375 100644 (file)
@@ -20,6 +20,7 @@
 #include "unicode/numberformatter.h"
 #include "uinvchar.h"
 #include "charstr.h"
+#include "string_segment.h"
 
 using namespace icu;
 using namespace icu::number;
index bc228bd0d7408e5176a23fd3a7d63baf0360b638..59af771928fbd0faa696ffe2119b50b56dc22d0b 100644 (file)
 #include "number_types.h"
 #include "numparse_types.h"
 #include "unicode/ucharstrie.h"
+#include "string_segment.h"
 
-using icu::numparse::impl::StringSegment;
-
-U_NAMESPACE_BEGIN namespace number {
+U_NAMESPACE_BEGIN
+namespace number {
 namespace impl {
 
 // Forward-declaration
index 225d1e577504900747b057169003c8f5e544f5ca..5aeead73e700ace0032b00f858ef937cffd761c9 100644 (file)
 #include "unicode/platform.h"
 #include "unicode/uniset.h"
 #include "standardplural.h"
+#include "formatted_string_builder.h"
 
-U_NAMESPACE_BEGIN namespace number {
+U_NAMESPACE_BEGIN
+namespace number {
 namespace impl {
 
-// Typedef several enums for brevity and for easier comparison to Java.
+// For convenience and historical reasons, import the Field typedef to the namespace.
+typedef FormattedStringBuilder::Field Field;
 
-// Convention: bottom 4 bits for field, top 4 bits for field category.
-// 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 "NumFieldUtils" in number_utils.h
-typedef uint8_t Field;
+// Typedef several enums for brevity and for easier comparison to Java.
 
 typedef UNumberFormatRoundingMode RoundingMode;
 
@@ -49,7 +48,6 @@ static constexpr char16_t kFallbackPaddingString[] = u" ";
 class Modifier;
 class MutablePatternModifier;
 class DecimalQuantity;
-class NumberStringBuilder;
 class ModifierStore;
 struct MicroProps;
 
@@ -160,7 +158,7 @@ class U_I18N_API Modifier {
      *            formatted.
      * @return The number of characters (UTF-16 code units) that were added to the string builder.
      */
-    virtual int32_t apply(NumberStringBuilder& output, int leftIndex, int rightIndex,
+    virtual int32_t apply(FormattedStringBuilder& output, int leftIndex, int rightIndex,
                           UErrorCode& status) const = 0;
 
     /**
index 203dec6d83b92b0d808721957746cc2ef886a628..93195f080b2787bde8b8058f2e11f4a2adfe2ba1 100644 (file)
@@ -17,6 +17,7 @@
 #include "number_roundingutils.h"
 #include "decNumber.h"
 #include "charstr.h"
+#include "formatted_string_builder.h"
 
 U_NAMESPACE_BEGIN
 
@@ -32,52 +33,10 @@ enum CldrPatternStyle {
     CLDR_PATTERN_STYLE_COUNT,
 };
 
-
-/**
- * Helper functions for dealing with the Field typedef, which stores fields
- * in a compressed format.
- */
-class NumFieldUtils {
-public:
-    struct CategoryFieldPair {
-        int32_t category;
-        int32_t field;
-    };
-
-    /** Compile-time function to construct a Field from a category and a field */
-    template <int32_t category, int32_t field>
-    static constexpr Field compress() {
-        static_assert(category != 0, "cannot use Undefined category in NumFieldUtils");
-        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);
-    }
-
-    /** Runtime inline function to unpack the category and field from the Field */
-    static inline CategoryFieldPair expand(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;
-    }
-
-    static inline bool isNumericField(Field field) {
-        int8_t category = field >> 4;
-        return category == 0 || category == UFIELD_CATEGORY_NUMBER;
-    }
-};
-
 // Namespace for naked functions
 namespace utils {
 
-inline int32_t insertDigitFromSymbols(NumberStringBuilder& output, int32_t index, int8_t digit,
+inline int32_t insertDigitFromSymbols(FormattedStringBuilder& output, int32_t index, int8_t digit,
                                       const DecimalFormatSymbols& symbols, Field field,
                                       UErrorCode& status) {
     if (symbols.getCodePointZero() != -1) {
index 88b493cbc254c9ce68e7153a71adcc5fb6ceeef5..6dbe5bee68fb71354b5bcf44b948dba93ad72696 100644 (file)
@@ -10,7 +10,7 @@
 #include "unicode/numberformatter.h"
 #include "number_types.h"
 #include "number_decimalquantity.h"
-#include "number_stringbuilder.h"
+#include "formatted_string_builder.h"
 #include "formattedval_impl.h"
 
 U_NAMESPACE_BEGIN namespace number {
@@ -31,9 +31,9 @@ const DecimalQuantity* validateUFormattedNumberToDecimalQuantity(
  * The DecimalQuantity is not currently being used by FormattedNumber, but at some point it could be used
  * to add a toDecNumber() or similar method.
  */
-class UFormattedNumberData : public FormattedValueNumberStringBuilderImpl {
+class UFormattedNumberData : public FormattedValueStringBuilderImpl {
 public:
-    UFormattedNumberData() : FormattedValueNumberStringBuilderImpl(0) {}
+    UFormattedNumberData() : FormattedValueStringBuilderImpl(0) {}
     virtual ~UFormattedNumberData();
 
     DecimalQuantity quantity;
index 6e00d9f6be19abb6401559461e43c515574801e6..6dc30d224146d12012092a8d944e6d1795c9742a 100644 (file)
@@ -13,6 +13,7 @@
 #include "numparse_affixes.h"
 #include "numparse_utils.h"
 #include "number_utils.h"
+#include "string_segment.h"
 
 using namespace icu;
 using namespace icu::numparse;
index 19253da805f0bfce3c6401d6c6de6fd7d1a5c3ce..2f7e1ab28d1d22907ad07e195273058a702d571d 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "numparse_types.h"
 #include "numparse_compositions.h"
+#include "string_segment.h"
 #include "unicode/uniset.h"
 
 using namespace icu;
index 598ace56533c36ab8ee64934bc470d98b4e3414d..6b53a73edf3b85ad425e264a214577019751f6b1 100644 (file)
@@ -14,6 +14,7 @@
 #include "ucurrimp.h"
 #include "unicode/errorcode.h"
 #include "numparse_utils.h"
+#include "string_segment.h"
 
 using namespace icu;
 using namespace icu::numparse;
index b120c5c6ad2f91f35ea1d40a98d6b72d0b5ba393..cf1e8156726d01c35ebac9107c50d318c4f67c31 100644 (file)
@@ -16,6 +16,7 @@
 #include "unicode/uchar.h"
 #include "putilimp.h"
 #include "number_decimalquantity.h"
+#include "string_segment.h"
 
 using namespace icu;
 using namespace icu::numparse;
index 7d5f0b6f0bd07b5a36ec39ab0d295254cbbc4711..380d9aa4c6428972976f0b1c1216109ad2954c6d 100644 (file)
@@ -18,6 +18,7 @@
 #include "unicode/localpointer.h"
 #include "numparse_validators.h"
 #include "number_multiplier.h"
+#include "string_segment.h"
 
 U_NAMESPACE_BEGIN
 
index 3145f718dc26b56dcc1390055d69a64dc711fa1c..6485d17fd03f2ce58aa2f5cd5e388d6ba70d93ba 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "numparse_types.h"
 #include "number_decimalquantity.h"
+#include "string_segment.h"
 #include "putilimp.h"
 #include <cmath>
 
index de38957440817cdcffdd5a952b8a38b3f1b5089c..b83b693f750807992a42657449146c89004e7857 100644 (file)
@@ -12,6 +12,7 @@
 #include "numparse_types.h"
 #include "numparse_scientific.h"
 #include "static_unicode_sets.h"
+#include "string_segment.h"
 
 using namespace icu;
 using namespace icu::numparse;
diff --git a/icu4c/source/i18n/numparse_stringsegment.h b/icu4c/source/i18n/numparse_stringsegment.h
deleted file mode 100644 (file)
index 7a84444..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-// Â© 2018 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html
-
-#include "unicode/utypes.h"
-
-#if !UCONFIG_NO_FORMATTING
-#ifndef __NUMPARSE_STRINGSEGMENT_H__
-#define __NUMPARSE_STRINGSEGMENT_H__
-
-#include "numparse_types.h"
-#include "number_types.h"
-#include "unicode/unistr.h"
-
-U_NAMESPACE_BEGIN
-namespace numparse {
-namespace impl {
-
-
-} // namespace impl
-} // namespace numparse
-U_NAMESPACE_END
-
-#endif //__NUMPARSE_STRINGSEGMENT_H__
-#endif /* #if !UCONFIG_NO_FORMATTING */
index e0daab9374f8b1b8ec0e357829160b433d3d6d18..bf14c711f05081de00cfb03f34cccf4017fe6f4a 100644 (file)
@@ -12,6 +12,7 @@
 #include "numparse_types.h"
 #include "numparse_symbols.h"
 #include "numparse_utils.h"
+#include "string_segment.h"
 
 using namespace icu;
 using namespace icu::numparse;
index 0fd70faca991ff27c10659fbd1aa5597dadb1d1f..a6bfe68f5129d62daefe8b7912bb26405f7a76b7 100644 (file)
@@ -9,12 +9,13 @@
 
 #include "unicode/uobject.h"
 #include "number_decimalquantity.h"
+#include "string_segment.h"
 
-U_NAMESPACE_BEGIN namespace numparse {
+U_NAMESPACE_BEGIN
+namespace numparse {
 namespace impl {
 
 // Forward-declarations
-class StringSegment;
 class ParsedNumber;
 
 typedef int32_t result_flags_t;
@@ -169,115 +170,6 @@ class U_I18N_API ParsedNumber {
 };
 
 
-/**
- * A mutable class allowing for a String with a variable offset and length. The charAt, length, and
- * subSequence methods all operate relative to the fixed offset into the String.
- *
- * @author sffc
- */
-// Exported as U_I18N_API for tests
-class U_I18N_API StringSegment : public UMemory {
-  public:
-    StringSegment(const UnicodeString& str, bool ignoreCase);
-
-    int32_t getOffset() const;
-
-    void setOffset(int32_t start);
-
-    /**
-     * Equivalent to <code>setOffset(getOffset()+delta)</code>.
-     *
-     * <p>
-     * This method is usually called by a Matcher to register that a char was consumed. If the char is
-     * strong (it usually is, except for things like whitespace), follow this with a call to
-     * {@link ParsedNumber#setCharsConsumed}. For more information on strong chars, see that method.
-     */
-    void adjustOffset(int32_t delta);
-
-    /**
-     * Adjusts the offset by the width of the current code point, either 1 or 2 chars.
-     */
-    void adjustOffsetByCodePoint();
-
-    void setLength(int32_t length);
-
-    void resetLength();
-
-    int32_t length() const;
-
-    char16_t charAt(int32_t index) const;
-
-    UChar32 codePointAt(int32_t index) const;
-
-    UnicodeString toUnicodeString() const;
-
-    const UnicodeString toTempUnicodeString() const;
-
-    /**
-     * Returns the first code point in the string segment, or -1 if the string starts with an invalid
-     * code point.
-     *
-     * <p>
-     * <strong>Important:</strong> Most of the time, you should use {@link #matches}, which handles case
-     * folding logic, instead of this method.
-     */
-    UChar32 getCodePoint() const;
-
-    /**
-     * Returns true if the first code point of this StringSegment equals the given code point.
-     *
-     * <p>
-     * This method will perform case folding if case folding is enabled for the parser.
-     */
-    bool startsWith(UChar32 otherCp) const;
-
-    /**
-     * Returns true if the first code point of this StringSegment is in the given UnicodeSet.
-     */
-    bool startsWith(const UnicodeSet& uniset) const;
-
-    /**
-     * Returns true if there is at least one code point of overlap between this StringSegment and the
-     * given UnicodeString.
-     */
-    bool startsWith(const UnicodeString& other) const;
-
-    /**
-     * Returns the length of the prefix shared by this StringSegment and the given CharSequence. For
-     * example, if this string segment is "aab", and the char sequence is "aac", this method returns 2,
-     * since the first 2 characters are the same.
-     *
-     * <p>
-     * This method only returns offsets along code point boundaries.
-     *
-     * <p>
-     * This method will perform case folding if case folding was enabled in the constructor.
-     *
-     * <p>
-     * IMPORTANT: The given UnicodeString must not be empty! It is the caller's responsibility to check.
-     */
-    int32_t getCommonPrefixLength(const UnicodeString& other);
-
-    /**
-     * Like {@link #getCommonPrefixLength}, but never performs case folding, even if case folding is
-     * enabled for the parser.
-     */
-    int32_t getCaseSensitivePrefixLength(const UnicodeString& other);
-
-    bool operator==(const UnicodeString& other) const;
-
-  private:
-    const UnicodeString& fStr;
-    int32_t fStart;
-    int32_t fEnd;
-    bool fFoldCase;
-
-    int32_t getPrefixLengthInternal(const UnicodeString& other, bool foldCase);
-
-    static bool codePointsEqual(UChar32 cp1, UChar32 cp2, bool foldCase);
-};
-
-
 /**
  * The core interface implemented by all matchers used for number parsing.
  *
index 079d5194b03bcbccc536d88b5333fde8900c2ec1..a788108ae637c662650b733e7ae5f982c8b2be95 100644 (file)
@@ -381,7 +381,7 @@ UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(FormattedNumberRange)
 UBool FormattedNumberRange::nextFieldPosition(FieldPosition& fieldPosition, UErrorCode& status) const {
     UPRV_FORMATTED_VALUE_METHOD_GUARD(FALSE)
     // NOTE: MSVC sometimes complains when implicitly converting between bool and UBool
-    return fData->getStringRef().nextFieldPosition(fieldPosition, status) ? TRUE : FALSE;
+    return fData->nextFieldPosition(fieldPosition, status);
 }
 
 void FormattedNumberRange::getAllFieldPositions(FieldPositionIterator& iterator, UErrorCode& status) const {
@@ -392,7 +392,7 @@ void FormattedNumberRange::getAllFieldPositions(FieldPositionIterator& iterator,
 void FormattedNumberRange::getAllFieldPositionsImpl(
         FieldPositionIteratorHandler& fpih, UErrorCode& status) const {
     UPRV_FORMATTED_VALUE_METHOD_GUARD()
-    fData->getStringRef().getAllFieldPositions(fpih, status);
+    fData->getAllFieldPositions(fpih, status);
 }
 
 UnicodeString FormattedNumberRange::getFirstDecimal(UErrorCode& status) const {
index 05eb2b84de3d871bb522e7bcd6da530c2746ed7b..7d732b31ec177a0e03459cb3e0194c7719006eae 100644 (file)
@@ -397,7 +397,7 @@ void NumberRangeFormatterImpl::formatRange(UFormattedNumberRangeData& data,
             break;
     }
 
-    NumberStringBuilder& string = data.getStringRef();
+    FormattedStringBuilder& string = data.getStringRef();
     int32_t lengthPrefix = 0;
     int32_t length1 = 0;
     int32_t lengthInfix = 0;
index dc25dd4d67bfebf3e6005d540a8209dc7605494e..f88e300913642d9ceeab78e4ecb352e4aedda6a4 100644 (file)
@@ -13,7 +13,7 @@
 #include "number_types.h"
 #include "number_decimalquantity.h"
 #include "number_formatimpl.h"
-#include "number_stringbuilder.h"
+#include "formatted_string_builder.h"
 #include "formattedval_impl.h"
 
 U_NAMESPACE_BEGIN namespace number {
@@ -29,9 +29,9 @@ namespace impl {
  * Possible magic number: 0x46445200
  * Reads in ASCII as "FDR" (FormatteDnumberRange with room at the end)
  */
-class UFormattedNumberRangeData : public FormattedValueNumberStringBuilderImpl {
+class UFormattedNumberRangeData : public FormattedValueStringBuilderImpl {
 public:
-    UFormattedNumberRangeData() : FormattedValueNumberStringBuilderImpl(0) {}
+    UFormattedNumberRangeData() : FormattedValueStringBuilderImpl(0) {}
     virtual ~UFormattedNumberRangeData();
 
     DecimalQuantity quantity1;
index 9182f9e7d379a84f47ed11c5f283a4dbe3118343..b8c26c4ab5fe0de60139f6f2ab13babd25abf024 100644 (file)
@@ -26,7 +26,7 @@
 #include "uassert.h"
 #include "number_decimalquantity.h"
 #include "number_utypes.h"
-#include "number_stringbuilder.h"
+#include "formatted_string_builder.h"
 
 U_NAMESPACE_BEGIN
 
@@ -180,7 +180,7 @@ void QuantityFormatter::formatAndSelect(
         double quantity,
         const NumberFormat& fmt,
         const PluralRules& rules,
-        number::impl::NumberStringBuilder& output,
+        FormattedStringBuilder& output,
         StandardPlural::Form& pluralForm,
         UErrorCode& status) {
     UnicodeString pluralKeyword;
index 046eec7509ecb07b8d136c9b1b02c1e6369363d5..daaef4f060acdb1c99bb33038e2369e5ac7b9972 100644 (file)
@@ -26,12 +26,7 @@ class PluralRules;
 class NumberFormat;
 class Formattable;
 class FieldPosition;
-
-namespace number {
-namespace impl {
-class NumberStringBuilder;
-}
-}
+class FormattedStringBuilder;
 
 /**
  * A plural aware formatter that is good for expressing a single quantity and
@@ -129,7 +124,7 @@ public:
 
     /**
      * Formats a quantity and selects its plural form. The output is appended
-     * to a NumberStringBuilder in order to retain field information.
+     * to a FormattedStringBuilder in order to retain field information.
      *
      * @param quantity The number to format.
      * @param fmt The formatter to use to format the number.
@@ -144,7 +139,7 @@ public:
             double quantity,
             const NumberFormat& fmt,
             const PluralRules& rules,
-            number::impl::NumberStringBuilder& output,
+            FormattedStringBuilder& output,
             StandardPlural::Form& pluralForm,
             UErrorCode& status);
 
index 2b58e47c2578a51d7e11e47e4d68a3b2115695bd..fd54bf0c35ab956e7981a2acee9520bf269b67a3 100644 (file)
@@ -43,7 +43,7 @@
 #include "standardplural.h"
 #include "unifiedcache.h"
 #include "util.h"
-#include "number_stringbuilder.h"
+#include "formatted_string_builder.h"
 #include "number_utypes.h"
 #include "number_modifiers.h"
 #include "formattedval_impl.h"
@@ -725,14 +725,14 @@ const RelativeDateTimeCacheData *LocaleCacheKey<RelativeDateTimeCacheData>::crea
 
 
 static constexpr number::impl::Field kRDTNumericField
-    = number::impl::NumFieldUtils::compress<UFIELD_CATEGORY_RELATIVE_DATETIME, UDAT_REL_NUMERIC_FIELD>();
+    = StringBuilderFieldUtils::compress<UFIELD_CATEGORY_RELATIVE_DATETIME, UDAT_REL_NUMERIC_FIELD>();
 
 static constexpr number::impl::Field kRDTLiteralField
-    = number::impl::NumFieldUtils::compress<UFIELD_CATEGORY_RELATIVE_DATETIME, UDAT_REL_LITERAL_FIELD>();
+    = StringBuilderFieldUtils::compress<UFIELD_CATEGORY_RELATIVE_DATETIME, UDAT_REL_LITERAL_FIELD>();
 
-class FormattedRelativeDateTimeData : public FormattedValueNumberStringBuilderImpl {
+class FormattedRelativeDateTimeData : public FormattedValueStringBuilderImpl {
 public:
-    FormattedRelativeDateTimeData() : FormattedValueNumberStringBuilderImpl(kRDTNumericField) {}
+    FormattedRelativeDateTimeData() : FormattedValueStringBuilderImpl(kRDTNumericField) {}
     virtual ~FormattedRelativeDateTimeData();
 };
 
similarity index 96%
rename from icu4c/source/i18n/numparse_stringsegment.cpp
rename to icu4c/source/i18n/string_segment.cpp
index 3db4fe618a603a0043151c01af93793957c818e7..5d19ac57f5e0d144f23f99568721471ffebbb642 100644 (file)
 #define UNISTR_FROM_STRING_EXPLICIT
 
 #include "numparse_types.h"
-#include "numparse_stringsegment.h"
+#include "string_segment.h"
 #include "putilimp.h"
 #include "unicode/utf16.h"
 #include "unicode/uniset.h"
 
-using namespace icu;
-using namespace icu::numparse;
-using namespace icu::numparse::impl;
+U_NAMESPACE_BEGIN
 
 
 StringSegment::StringSegment(const UnicodeString& str, bool ignoreCase)
@@ -143,4 +141,5 @@ bool StringSegment::operator==(const UnicodeString& other) const {
 }
 
 
+U_NAMESPACE_END
 #endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/icu4c/source/i18n/string_segment.h b/icu4c/source/i18n/string_segment.h
new file mode 100644 (file)
index 0000000..b581f7e
--- /dev/null
@@ -0,0 +1,134 @@
+// Â© 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+#ifndef __NUMPARSE_STRINGSEGMENT_H__
+#define __NUMPARSE_STRINGSEGMENT_H__
+
+#include "unicode/unistr.h"
+#include "unicode/uniset.h"
+
+U_NAMESPACE_BEGIN
+
+
+/**
+ * A mutable UnicodeString wrapper with a variable offset and length and
+ * support for case folding. The charAt, length, and subSequence methods all
+ * operate relative to the fixed offset into the UnicodeString.
+ *
+ * Intended to be useful for parsing.
+ *
+ * CAUTION: Since this class is mutable, it must not be used anywhere that an
+ * immutable object is required, like in a cache or as the key of a hash map.
+ *
+ * @author sffc (Shane Carr)
+ */
+// Exported as U_I18N_API for tests
+class U_I18N_API StringSegment : public UMemory {
+  public:
+    StringSegment(const UnicodeString& str, bool ignoreCase);
+
+    int32_t getOffset() const;
+
+    void setOffset(int32_t start);
+
+    /**
+     * Equivalent to <code>setOffset(getOffset()+delta)</code>.
+     *
+     * <p>
+     * This method is usually called by a Matcher to register that a char was consumed. If the char is
+     * strong (it usually is, except for things like whitespace), follow this with a call to
+     * {@link ParsedNumber#setCharsConsumed}. For more information on strong chars, see that method.
+     */
+    void adjustOffset(int32_t delta);
+
+    /**
+     * Adjusts the offset by the width of the current code point, either 1 or 2 chars.
+     */
+    void adjustOffsetByCodePoint();
+
+    void setLength(int32_t length);
+
+    void resetLength();
+
+    int32_t length() const;
+
+    char16_t charAt(int32_t index) const;
+
+    UChar32 codePointAt(int32_t index) const;
+
+    UnicodeString toUnicodeString() const;
+
+    const UnicodeString toTempUnicodeString() const;
+
+    /**
+     * Returns the first code point in the string segment, or -1 if the string starts with an invalid
+     * code point.
+     *
+     * <p>
+     * <strong>Important:</strong> Most of the time, you should use {@link #startsWith}, which handles case
+     * folding logic, instead of this method.
+     */
+    UChar32 getCodePoint() const;
+
+    /**
+     * Returns true if the first code point of this StringSegment equals the given code point.
+     *
+     * <p>
+     * This method will perform case folding if case folding is enabled for the parser.
+     */
+    bool startsWith(UChar32 otherCp) const;
+
+    /**
+     * Returns true if the first code point of this StringSegment is in the given UnicodeSet.
+     */
+    bool startsWith(const UnicodeSet& uniset) const;
+
+    /**
+     * Returns true if there is at least one code point of overlap between this StringSegment and the
+     * given UnicodeString.
+     */
+    bool startsWith(const UnicodeString& other) const;
+
+    /**
+     * Returns the length of the prefix shared by this StringSegment and the given UnicodeString. For
+     * example, if this string segment is "aab", and the char sequence is "aac", this method returns 2,
+     * since the first 2 characters are the same.
+     *
+     * <p>
+     * This method only returns offsets along code point boundaries.
+     *
+     * <p>
+     * This method will perform case folding if case folding was enabled in the constructor.
+     *
+     * <p>
+     * IMPORTANT: The given UnicodeString must not be empty! It is the caller's responsibility to check.
+     */
+    int32_t getCommonPrefixLength(const UnicodeString& other);
+
+    /**
+     * Like {@link #getCommonPrefixLength}, but never performs case folding, even if case folding is
+     * enabled for the parser.
+     */
+    int32_t getCaseSensitivePrefixLength(const UnicodeString& other);
+
+    bool operator==(const UnicodeString& other) const;
+
+  private:
+    const UnicodeString& fStr;
+    int32_t fStart;
+    int32_t fEnd;
+    bool fFoldCase;
+
+    int32_t getPrefixLengthInternal(const UnicodeString& other, bool foldCase);
+
+    static bool codePointsEqual(UChar32 cp1, UChar32 cp2, bool foldCase);
+};
+
+
+U_NAMESPACE_END
+
+#endif //__NUMPARSE_STRINGSEGMENT_H__
+#endif /* #if !UCONFIG_NO_FORMATTING */
index 4fd6830518d91123af6b115cba6e94ad036a3d7b..5144ea98c6c08fc91a65c2fa0423017b8b897a8d 100644 (file)
@@ -85,6 +85,7 @@ U_NAMESPACE_BEGIN
 // Forward declarations:
 class IFixedDecimal;
 class FieldPositionIteratorHandler;
+class FormattedStringBuilder;
 
 namespace numparse {
 namespace impl {
@@ -142,7 +143,6 @@ class MultiplierProducer;
 class RoundingImpl;
 class ScientificHandler;
 class Modifier;
-class NumberStringBuilder;
 class AffixPatternProvider;
 class NumberPropertyMapper;
 struct DecimalFormatProperties;
@@ -1343,7 +1343,7 @@ class U_I18N_API Padder : public UMemory {
     }
 
     int32_t padAndApply(const impl::Modifier &mod1, const impl::Modifier &mod2,
-                        impl::NumberStringBuilder &string, int32_t leftIndex, int32_t rightIndex,
+                        FormattedStringBuilder &string, int32_t leftIndex, int32_t rightIndex,
                         UErrorCode &status) const;
 
     // To allow MacroProps/MicroProps to initialize empty instances:
index 466e6427f957d6ac210bf5671dfed644e44480e8..f7404a0528b8399a8cbeee7b230b896c9048d3c0 100644 (file)
@@ -932,7 +932,9 @@ group: double_conversion
     platform
 
 group: number_representation
-    number_decimalquantity.o number_stringbuilder.o numparse_stringsegment.o number_utils.o
+    number_decimalquantity.o string_segment.o number_utils.o
+    # TODO(ICU-20429) Move formatted_string_builder to its own unit.
+    formatted_string_builder.o
   deps
     decnumber double_conversion
     # for trimming whitespace around fields
index b4cf918ec48cb26c7f1ed537ed454e4f1c38109b..3a7c75413b44e35fc64f350da4c5c0bbc681dd4f 100644 (file)
@@ -64,10 +64,10 @@ scientificnumberformattertest.o datadrivennumberformattestsuite.o \
 numberformattesttuple.o pluralmaptest.o \
 numbertest_affixutils.o numbertest_api.o numbertest_decimalquantity.o \
 numbertest_modifiers.o numbertest_patternmodifier.o numbertest_patternstring.o \
-numbertest_stringbuilder.o numbertest_stringsegment.o \
+string_segment_test.o \
 numbertest_parse.o numbertest_doubleconversion.o numbertest_skeletons.o \
 static_unisets_test.o numfmtdatadriventest.o numbertest_range.o erarulestest.o \
-formattedvaluetest.o
+formattedvaluetest.o formatted_string_builder_test.o
 
 DEPS = $(OBJECTS:.o=.d)
 
similarity index 81%
rename from icu4c/source/test/intltest/numbertest_stringbuilder.cpp
rename to icu4c/source/test/intltest/formatted_string_builder_test.cpp
index eaf9a7a4d5fd8e9a2c5555851bdd1575c48c4f06..9da402fb2fd41bc7bc051e2680ca17547ba8bbdb 100644 (file)
@@ -6,7 +6,26 @@
 #if !UCONFIG_NO_FORMATTING
 
 #include "putilimp.h"
-#include "numbertest.h"
+#include "intltest.h"
+#include "formatted_string_builder.h"
+#include "formattedval_impl.h"
+
+
+class FormattedStringBuilderTest : public IntlTest {
+  public:
+    void testInsertAppendUnicodeString();
+    void testSplice();
+    void testInsertAppendCodePoint();
+    void testCopy();
+    void testFields();
+    void testUnlimitedCapacity();
+    void testCodePoints();
+
+    void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par = 0);
+
+  private:
+    void assertEqualsImpl(const UnicodeString &a, const FormattedStringBuilder &b);
+};
 
 static const char16_t *EXAMPLE_STRINGS[] = {
         u"",
@@ -17,9 +36,9 @@ static const char16_t *EXAMPLE_STRINGS[] = {
         u"with combining characters like ðŸ‡¦ðŸ‡§ðŸ‡¨ðŸ‡©",
         u"A very very very very very very very very very very long string to force heap"};
 
-void NumberStringBuilderTest::runIndexedTest(int32_t index, UBool exec, const char *&name, char *) {
+void FormattedStringBuilderTest::runIndexedTest(int32_t index, UBool exec, const char *&name, char *) {
     if (exec) {
-        logln("TestSuite NumberStringBuilderTest: ");
+        logln("TestSuite FormattedStringBuilderTest: ");
     }
     TESTCASE_AUTO_BEGIN;
         TESTCASE_AUTO(testInsertAppendUnicodeString);
@@ -32,14 +51,14 @@ void NumberStringBuilderTest::runIndexedTest(int32_t index, UBool exec, const ch
     TESTCASE_AUTO_END;
 }
 
-void NumberStringBuilderTest::testInsertAppendUnicodeString() {
+void FormattedStringBuilderTest::testInsertAppendUnicodeString() {
     UErrorCode status = U_ZERO_ERROR;
     UnicodeString sb1;
-    NumberStringBuilder sb2;
+    FormattedStringBuilder sb2;
     for (const char16_t* strPtr : EXAMPLE_STRINGS) {
         UnicodeString str(strPtr);
 
-        NumberStringBuilder sb3;
+        FormattedStringBuilder sb3;
         sb1.append(str);
         // Note: UNUM_FIELD_COUNT is like passing null in Java
         sb2.append(str, UNUM_FIELD_COUNT, status);
@@ -50,7 +69,7 @@ void NumberStringBuilderTest::testInsertAppendUnicodeString() {
         assertEqualsImpl(str, sb3);
 
         UnicodeString sb4;
-        NumberStringBuilder sb5;
+        FormattedStringBuilder sb5;
         sb4.append(u"😇");
         sb4.append(str);
         sb4.append(u"xx");
@@ -68,7 +87,7 @@ void NumberStringBuilderTest::testInsertAppendUnicodeString() {
         assertEqualsImpl(sb4, sb5);
 
         UnicodeString sb4cp(sb4);
-        NumberStringBuilder sb5cp(sb5);
+        FormattedStringBuilder sb5cp(sb5);
         sb4.append(sb4cp);
         sb5.append(sb5cp, status);
         assertSuccess("Appending again to sb5", status);
@@ -76,7 +95,7 @@ void NumberStringBuilderTest::testInsertAppendUnicodeString() {
     }
 }
 
-void NumberStringBuilderTest::testSplice() {
+void FormattedStringBuilderTest::testSplice() {
     static const struct TestCase {
         const char16_t* input;
         const int32_t startThis;
@@ -94,7 +113,7 @@ void NumberStringBuilderTest::testSplice() {
 
     UErrorCode status = U_ZERO_ERROR;
     UnicodeString sb1;
-    NumberStringBuilder sb2;
+    FormattedStringBuilder sb2;
     for (auto cas : cases) {
         for (const char16_t* replacementPtr : EXAMPLE_STRINGS) {
             UnicodeString replacement(replacementPtr);
@@ -125,14 +144,14 @@ void NumberStringBuilderTest::testSplice() {
     }
 }
 
-void NumberStringBuilderTest::testInsertAppendCodePoint() {
+void FormattedStringBuilderTest::testInsertAppendCodePoint() {
     static const UChar32 cases[] = {
             0, 1, 60, 127, 128, 0x7fff, 0x8000, 0xffff, 0x10000, 0x1f000, 0x10ffff};
     UErrorCode status = U_ZERO_ERROR;
     UnicodeString sb1;
-    NumberStringBuilder sb2;
+    FormattedStringBuilder sb2;
     for (UChar32 cas : cases) {
-        NumberStringBuilder sb3;
+        FormattedStringBuilder sb3;
         sb1.append(cas);
         sb2.appendCodePoint(cas, UNUM_FIELD_COUNT, status);
         assertSuccess("Appending to sb2", status);
@@ -147,7 +166,7 @@ void NumberStringBuilderTest::testInsertAppendCodePoint() {
                 sb3.charAt(0));
 
         UnicodeString sb4;
-        NumberStringBuilder sb5;
+        FormattedStringBuilder sb5;
         sb4.append(u"😇xx");
         sb4.insert(2, cas);
         sb5.append(u"😇xx", UNUM_FIELD_COUNT, status);
@@ -158,13 +177,13 @@ void NumberStringBuilderTest::testInsertAppendCodePoint() {
     }
 }
 
-void NumberStringBuilderTest::testCopy() {
+void FormattedStringBuilderTest::testCopy() {
     UErrorCode status = U_ZERO_ERROR;
     for (UnicodeString str : EXAMPLE_STRINGS) {
-        NumberStringBuilder sb1;
+        FormattedStringBuilder sb1;
         sb1.append(str, UNUM_FIELD_COUNT, status);
         assertSuccess("Appending to sb1 first time", status);
-        NumberStringBuilder sb2(sb1);
+        FormattedStringBuilder sb2(sb1);
         assertTrue("Content should equal itself", sb1.contentEquals(sb2));
 
         sb1.append("12345", UNUM_FIELD_COUNT, status);
@@ -173,25 +192,28 @@ void NumberStringBuilderTest::testCopy() {
     }
 }
 
-void NumberStringBuilderTest::testFields() {
+void FormattedStringBuilderTest::testFields() {
     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) {
-        NumberStringBuilder sb;
+        FormattedValueStringBuilderImpl sbi(0);
+        FormattedStringBuilder& sb = sbi.getStringRef();
         sb.append(str, UNUM_FIELD_COUNT, status);
         assertSuccess("Appending to sb", status);
         sb.append(str, 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", (Field) UNUM_FIELD_COUNT, sb.fieldAt(i));
-            assertEquals("Currency field second", (Field) UNUM_CURRENCY_FIELD, sb.fieldAt(i + str.length()));
+            assertEquals("Null field first",
+                (FormattedStringBuilder::Field) UNUM_FIELD_COUNT, sb.fieldAt(i));
+            assertEquals("Currency field second",
+                (FormattedStringBuilder::Field) UNUM_CURRENCY_FIELD, sb.fieldAt(i + str.length()));
         }
 
         // Very basic FieldPosition test. More robust tests happen in NumberFormatTest.
         // Let NumberFormatTest also take care of FieldPositionIterator material.
         FieldPosition fp(UNUM_CURRENCY_FIELD);
-        sb.nextFieldPosition(fp, status);
+        sbi.nextFieldPosition(fp, status);
         assertSuccess("Populating the FieldPosition", status);
         assertEquals("Currency start position", str.length(), fp.getBeginIndex());
         assertEquals("Currency end position", str.length() * 2, fp.getEndIndex());
@@ -200,17 +222,17 @@ void NumberStringBuilderTest::testFields() {
             sb.insertCodePoint(2, 100, UNUM_INTEGER_FIELD, status);
             assertSuccess("Inserting code point into sb", status);
             assertEquals("New length", str.length() * 2 + 1, sb.length());
-            assertEquals("Integer field", (Field) UNUM_INTEGER_FIELD, sb.fieldAt(2));
+            assertEquals("Integer field", (FormattedStringBuilder::Field) UNUM_INTEGER_FIELD, sb.fieldAt(2));
         }
 
-        NumberStringBuilder old(sb);
+        FormattedStringBuilder old(sb);
         sb.append(old, status);
         assertSuccess("Appending to myself", status);
         int32_t numNull = 0;
         int32_t numCurr = 0;
         int32_t numInt = 0;
         for (int32_t i = 0; i < sb.length(); i++) {
-            Field field = sb.fieldAt(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) {
                 numNull++;
@@ -228,9 +250,9 @@ void NumberStringBuilderTest::testFields() {
     }
 }
 
-void NumberStringBuilderTest::testUnlimitedCapacity() {
+void FormattedStringBuilderTest::testUnlimitedCapacity() {
     UErrorCode status = U_ZERO_ERROR;
-    NumberStringBuilder builder;
+    FormattedStringBuilder builder;
     // The builder should never fail upon repeated appends.
     for (int i = 0; i < 1000; i++) {
         UnicodeString message("Iteration #");
@@ -242,9 +264,9 @@ void NumberStringBuilderTest::testUnlimitedCapacity() {
     }
 }
 
-void NumberStringBuilderTest::testCodePoints() {
+void FormattedStringBuilderTest::testCodePoints() {
     UErrorCode status = U_ZERO_ERROR;
-    NumberStringBuilder nsb;
+    FormattedStringBuilder nsb;
     assertEquals("First is -1 on empty string", -1, nsb.getFirstCodePoint());
     assertEquals("Last is -1 on empty string", -1, nsb.getLastCodePoint());
     assertEquals("Length is 0 on empty string", 0, nsb.codePointCount());
@@ -268,7 +290,7 @@ void NumberStringBuilderTest::testCodePoints() {
     assertEquals("Code point count is 2", 2, nsb.codePointCount());
 }
 
-void NumberStringBuilderTest::assertEqualsImpl(const UnicodeString &a, const NumberStringBuilder &b) {
+void FormattedStringBuilderTest::assertEqualsImpl(const UnicodeString &a, const FormattedStringBuilder &b) {
     // TODO: Why won't this compile without the IntlTest:: qualifier?
     IntlTest::assertEquals("Lengths should be the same", a.length(), b.length());
     IntlTest::assertEquals("Code point counts should be the same", a.countChar32(), b.codePointCount());
@@ -285,4 +307,9 @@ void NumberStringBuilderTest::assertEqualsImpl(const UnicodeString &a, const Num
     }
 }
 
+
+extern IntlTest *createFormattedStringBuilderTest() {
+    return new FormattedStringBuilderTest();
+}
+
 #endif /* #if !UCONFIG_NO_FORMATTING */
index 5e82ef3bdc77d9fc1b28fe66981478ea703ea24d..2129cfbd6b127e87a8e1f4a5bf0d219e06304bd2 100644 (file)
     </ClCompile>
     <ClCompile Include="dtptngts.cpp" />
     <ClCompile Include="fldset.cpp" />
+    <ClCompile Include="formatted_string_builder_test.cpp" />
     <ClCompile Include="genderinfotest.cpp" />
     <ClCompile Include="incaltst.cpp" />
     <ClCompile Include="itformat.cpp" />
     <ClCompile Include="numbertest_modifiers.cpp" />
     <ClCompile Include="numbertest_patternmodifier.cpp" />
     <ClCompile Include="numbertest_patternstring.cpp" />
-    <ClCompile Include="numbertest_stringbuilder.cpp" />
-    <ClCompile Include="numbertest_stringsegment.cpp" />
+    <ClCompile Include="string_segment_test.cpp" />
     <ClCompile Include="numbertest_parse.cpp" />
     <ClCompile Include="numbertest_doubleconversion.cpp" />
     <ClCompile Include="numbertest_skeletons.cpp" />
index bed26bcbbded27e4df0a5be91331be71dfbad789..945f73729c1153cb1525be067b3e65f72d034946 100644 (file)
     <ClCompile Include="fldset.cpp">
       <Filter>formatting</Filter>
     </ClCompile>
+    <ClCompile Include="formatted_string_builder_test.cpp">
+      <Filter>formatting</Filter>
+    </ClCompile>
     <ClCompile Include="genderinfotest.cpp">
       <Filter>formatting</Filter>
     </ClCompile>
     <ClCompile Include="numbertest_patternstring.cpp">
       <Filter>formatting</Filter>
     </ClCompile>
-    <ClCompile Include="numbertest_stringbuilder.cpp">
-      <Filter>formatting</Filter>
-    </ClCompile>
-    <ClCompile Include="numbertest_stringsegment.cpp">
+    <ClCompile Include="string_segment_test.cpp">
       <Filter>formatting</Filter>
     </ClCompile>
     <ClCompile Include="numbertest_parse.cpp">
index 1c993fc2a87c59c3f1cd8cd1f296a7682ca94bfd..870728a9a0a90b4b94ef37d6c43cbe3f1ae5978f 100644 (file)
@@ -72,6 +72,8 @@ extern IntlTest *createMeasureFormatTest();
 extern IntlTest *createNumberFormatSpecificationTest();
 extern IntlTest *createScientificNumberFormatterTest();
 extern IntlTest *createFormattedValueTest();
+extern IntlTest *createFormattedStringBuilderTest();
+extern IntlTest *createStringSegmentTest();
 
 
 #define TESTCLASS(id, TestClass)          \
@@ -227,6 +229,24 @@ void IntlTestFormat::runIndexedTest( int32_t index, UBool exec, const char* &nam
             callTest(*test, par);
           }
           break;
+        case 54:
+          name = "FormattedStringBuilderTest";
+          if (exec) {
+            logln("FormattedStringBuilderTest test---");
+            logln((UnicodeString)"");
+            LocalPointer<IntlTest> test(createFormattedStringBuilderTest());
+            callTest(*test, par);
+          }
+          break;
+        case 55:
+          name = "StringSegmentTest";
+          if (exec) {
+            logln("StringSegmentTest test---");
+            logln((UnicodeString)"");
+            LocalPointer<IntlTest> test(createStringSegmentTest());
+            callTest(*test, par);
+          }
+          break;
         default: name = ""; break; //needed to end loop
     }
     if (exec) {
index 1ea3ee8aea5b4964d894d62c551cf03041627a44..d139bc0c388041a0bf9e39b98883af25f3262473 100644 (file)
@@ -6,11 +6,11 @@
 #if !UCONFIG_NO_FORMATTING
 #pragma once
 
-#include "number_stringbuilder.h"
+#include "formatted_string_builder.h"
 #include "intltest.h"
 #include "itformat.h"
 #include "number_affixutils.h"
-#include "numparse_stringsegment.h"
+#include "string_segment.h"
 #include "numrange_impl.h"
 #include "unicode/locid.h"
 #include "unicode/numberformatter.h"
@@ -174,7 +174,7 @@ class ModifiersTest : public IntlTest {
                               UnicodeString expectedChars, UnicodeString expectedFields,
                               UErrorCode &status);
 
-    void assertModifierEquals(const Modifier &mod, NumberStringBuilder &sb, int32_t expectedPrefixLength,
+    void assertModifierEquals(const Modifier &mod, FormattedStringBuilder &sb, int32_t expectedPrefixLength,
                               bool expectedStrong, UnicodeString expectedChars,
                               UnicodeString expectedFields, UErrorCode &status);
 };
@@ -204,33 +204,6 @@ class PatternStringTest : public IntlTest {
   private:
 };
 
-class NumberStringBuilderTest : public IntlTest {
-  public:
-    void testInsertAppendUnicodeString();
-    void testSplice();
-    void testInsertAppendCodePoint();
-    void testCopy();
-    void testFields();
-    void testUnlimitedCapacity();
-    void testCodePoints();
-
-    void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par = 0);
-
-  private:
-    void assertEqualsImpl(const UnicodeString &a, const NumberStringBuilder &b);
-};
-
-class StringSegmentTest : public IntlTest {
-  public:
-    void testOffset();
-    void testLength();
-    void testCharAt();
-    void testGetCodePoint();
-    void testCommonPrefixLength();
-
-    void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par = 0);
-};
-
 class NumberParserTest : public IntlTest {
   public:
     void testBasic();
@@ -340,12 +313,10 @@ class NumberTest : public IntlTest {
         TESTCLASS(3, ModifiersTest);
         TESTCLASS(4, PatternModifierTest);
         TESTCLASS(5, PatternStringTest);
-        TESTCLASS(6, NumberStringBuilderTest);
-        TESTCLASS(7, DoubleConversionTest);
-        TESTCLASS(8, StringSegmentTest);
-        TESTCLASS(9, NumberParserTest);
-        TESTCLASS(10, NumberSkeletonTest);
-        TESTCLASS(11, NumberRangeFormatterTest);
+        TESTCLASS(6, DoubleConversionTest);
+        TESTCLASS(7, NumberParserTest);
+        TESTCLASS(8, NumberSkeletonTest);
+        TESTCLASS(9, NumberRangeFormatterTest);
         default: name = ""; break; // needed to end loop
         }
     }
index eefded648abc24e594c6b79b9cf911811715436a..7f29ad19903baa47130fc6e30bd0a2fc93594595 100644 (file)
@@ -217,7 +217,7 @@ void AffixUtilsTest::testUnescapeWithSymbolProvider() {
     NumericSymbolProvider provider;
 
     UErrorCode status = U_ZERO_ERROR;
-    NumberStringBuilder sb;
+    FormattedStringBuilder sb;
     for (auto& cas : cases) {
         UnicodeString input(cas[0]);
         UnicodeString expected(cas[1]);
@@ -239,7 +239,7 @@ void AffixUtilsTest::testUnescapeWithSymbolProvider() {
 
 UnicodeString AffixUtilsTest::unescapeWithDefaults(const SymbolProvider &defaultProvider,
                                                           UnicodeString input, UErrorCode &status) {
-    NumberStringBuilder nsb;
+    FormattedStringBuilder nsb;
     int32_t length = AffixUtils::unescape(input, nsb, 0, defaultProvider, UNUM_FIELD_COUNT, status);
     assertEquals("Return value of unescape", nsb.length(), length);
     return nsb.toUnicodeString();
index 52f4f49475120c4e2909c7f8e596b2c05d1f6b12..90144ad1c64acd4746598334eddf9a8f73caca9d 100644 (file)
@@ -7,7 +7,7 @@
 
 #include "putilimp.h"
 #include "intltest.h"
-#include "number_stringbuilder.h"
+#include "formatted_string_builder.h"
 #include "number_modifiers.h"
 #include "numbertest.h"
 
@@ -36,8 +36,8 @@ void ModifiersTest::testConstantAffixModifier() {
 
 void ModifiersTest::testConstantMultiFieldModifier() {
     UErrorCode status = U_ZERO_ERROR;
-    NumberStringBuilder prefix;
-    NumberStringBuilder suffix;
+    FormattedStringBuilder prefix;
+    FormattedStringBuilder suffix;
     ConstantMultiFieldModifier mod1(prefix, suffix, false, true);
     assertModifierEquals(mod1, 0, true, u"|", u"n", status);
     assertSuccess("Spot 1", status);
@@ -87,7 +87,7 @@ void ModifiersTest::testSimpleModifier() {
 
         // Test strange insertion positions
         for (int32_t j = 0; j < NUM_OUTPUTS; j++) {
-            NumberStringBuilder output;
+            FormattedStringBuilder output;
             output.append(outputs[j].baseString, UNUM_FIELD_COUNT, status);
             mod.apply(output, outputs[j].leftIndex, outputs[j].rightIndex, status);
             UnicodeString expected = expecteds[j][i];
@@ -105,8 +105,8 @@ void ModifiersTest::testCurrencySpacingEnabledModifier() {
         return;
     }
 
-    NumberStringBuilder prefix;
-    NumberStringBuilder suffix;
+    FormattedStringBuilder prefix;
+    FormattedStringBuilder suffix;
     CurrencySpacingEnabledModifier mod1(prefix, suffix, false, true, symbols, status);
     assertSuccess("Spot 2", status);
     assertModifierEquals(mod1, 0, true, u"|", u"n", status);
@@ -120,15 +120,15 @@ void ModifiersTest::testCurrencySpacingEnabledModifier() {
     assertSuccess("Spot 6", status);
 
     // Test the default currency spacing rules
-    NumberStringBuilder sb;
+    FormattedStringBuilder sb;
     sb.append("123", UNUM_INTEGER_FIELD, status);
     assertSuccess("Spot 7", status);
-    NumberStringBuilder sb1(sb);
+    FormattedStringBuilder sb1(sb);
     assertModifierEquals(mod2, sb1, 3, true, u"USD\u00A0123", u"$$$niii", status);
     assertSuccess("Spot 8", status);
 
     // Compare with the unsafe code path
-    NumberStringBuilder sb2(sb);
+    FormattedStringBuilder sb2(sb);
     sb2.insert(0, "USD", UNUM_CURRENCY_FIELD, status);
     assertSuccess("Spot 9", status);
     CurrencySpacingEnabledModifier::applyCurrencySpacing(sb2, 0, 3, 6, 0, symbols, status);
@@ -149,14 +149,14 @@ void ModifiersTest::testCurrencySpacingEnabledModifier() {
 void ModifiersTest::assertModifierEquals(const Modifier &mod, int32_t expectedPrefixLength,
                                          bool expectedStrong, UnicodeString expectedChars,
                                          UnicodeString expectedFields, UErrorCode &status) {
-    NumberStringBuilder sb;
+    FormattedStringBuilder sb;
     sb.appendCodePoint('|', UNUM_FIELD_COUNT, status);
     assertModifierEquals(
             mod, sb, expectedPrefixLength, expectedStrong, expectedChars, expectedFields, status);
 
 }
 
-void ModifiersTest::assertModifierEquals(const Modifier &mod, NumberStringBuilder &sb,
+void ModifiersTest::assertModifierEquals(const Modifier &mod, FormattedStringBuilder &sb,
                                          int32_t expectedPrefixLength, bool expectedStrong,
                                          UnicodeString expectedChars, UnicodeString expectedFields,
                                          UErrorCode &status) {
@@ -171,7 +171,7 @@ void ModifiersTest::assertModifierEquals(const Modifier &mod, NumberStringBuilde
     }
 
     UnicodeString debugString;
-    debugString.append(u"<NumberStringBuilder [");
+    debugString.append(u"<FormattedStringBuilder [");
     debugString.append(expectedChars);
     debugString.append(u"] [");
     debugString.append(expectedFields);
index ba382a65615dd6c7efa92b08f62332f859a090c5..e557dcf4b29001de8374eccec3559723d9a367b4 100644 (file)
@@ -99,7 +99,7 @@ void PatternModifierTest::testPatternWithNoPlaceholder() {
     mod.setNumberProperties(1, StandardPlural::Form::COUNT);
 
     // Unsafe Code Path
-    NumberStringBuilder nsb;
+    FormattedStringBuilder nsb;
     nsb.append(u"x123y", UNUM_FIELD_COUNT, status);
     assertSuccess("Spot 3", status);
     mod.apply(nsb, 1, 4, status);
@@ -141,21 +141,21 @@ void PatternModifierTest::testMutableEqualsImmutable() {
     DecimalQuantity fq;
     fq.setToInt(1);
 
-    NumberStringBuilder nsb1;
+    FormattedStringBuilder nsb1;
     MicroProps micros1;
     mod.addToChain(&micros1);
     mod.processQuantity(fq, micros1, status);
     micros1.modMiddle->apply(nsb1, 0, 0, status);
     assertSuccess("Spot 3", status);
 
-    NumberStringBuilder nsb2;
+    FormattedStringBuilder nsb2;
     MicroProps micros2;
     LocalPointer<ImmutablePatternModifier> immutable(mod.createImmutable(status));
     immutable->applyToMicros(micros2, fq, status);
     micros2.modMiddle->apply(nsb2, 0, 0, status);
     assertSuccess("Spot 4", status);
 
-    NumberStringBuilder nsb3;
+    FormattedStringBuilder nsb3;
     MicroProps micros3;
     mod.addToChain(&micros3);
     mod.setPatternAttributes(UNUM_SIGN_ALWAYS, false);
@@ -168,14 +168,14 @@ void PatternModifierTest::testMutableEqualsImmutable() {
 }
 
 UnicodeString PatternModifierTest::getPrefix(const MutablePatternModifier &mod, UErrorCode &status) {
-    NumberStringBuilder nsb;
+    FormattedStringBuilder nsb;
     mod.apply(nsb, 0, 0, status);
     int32_t prefixLength = mod.getPrefixLength();
     return UnicodeString(nsb.toUnicodeString(), 0, prefixLength);
 }
 
 UnicodeString PatternModifierTest::getSuffix(const MutablePatternModifier &mod, UErrorCode &status) {
-    NumberStringBuilder nsb;
+    FormattedStringBuilder nsb;
     mod.apply(nsb, 0, 0, status);
     int32_t prefixLength = mod.getPrefixLength();
     return UnicodeString(nsb.toUnicodeString(), prefixLength, nsb.length() - prefixLength);
similarity index 91%
rename from icu4c/source/test/intltest/numbertest_stringsegment.cpp
rename to icu4c/source/test/intltest/string_segment_test.cpp
index dc5774fd3a7dd70bd388a83107aa9aafd967bebd..0548d9ad928dfb0c246994c159c31f942378f8aa 100644 (file)
@@ -5,8 +5,19 @@
 
 #if !UCONFIG_NO_FORMATTING
 
-#include "numbertest.h"
-#include "numparse_stringsegment.h"
+#include "string_segment.h"
+#include "intltest.h"
+
+class StringSegmentTest : public IntlTest {
+  public:
+    void testOffset();
+    void testLength();
+    void testCharAt();
+    void testGetCodePoint();
+    void testCommonPrefixLength();
+
+    void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par = 0);
+};
 
 static const char16_t* SAMPLE_STRING = u"📻 radio ðŸ“»";
 
@@ -101,4 +112,9 @@ void StringSegmentTest::testCommonPrefixLength() {
     assertEquals("", 0, segment.getCommonPrefixLength(u"foo"));
 }
 
+
+extern IntlTest *createStringSegmentTest() {
+    return new StringSegmentTest();
+}
+
 #endif
similarity index 64%
rename from icu4j/main/classes/core/src/com/ibm/icu/impl/number/NumberStringBuilder.java
rename to icu4j/main/classes/core/src/com/ibm/icu/impl/FormattedStringBuilder.java
index 60a5467022fb456f1028c2b986e418ce5f123fa9..ca3cb187bda9c5a8e3cdee1450e37a42715f239e 100644 (file)
@@ -1,22 +1,17 @@
 // Â© 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package com.ibm.icu.impl.number;
+package com.ibm.icu.impl;
 
-import java.text.AttributedCharacterIterator;
-import java.text.AttributedString;
-import java.text.FieldPosition;
 import java.text.Format.Field;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 
-import com.ibm.icu.impl.StaticUnicodeSets;
-import com.ibm.icu.text.ConstrainedFieldPosition;
+// NumberFormat is imported only for the toDebugString() implementation.
 import com.ibm.icu.text.NumberFormat;
-import com.ibm.icu.text.UnicodeSet;
 
 /**
- * A StringBuilder optimized for number formatting. It implements the following key features beyond a
+ * A StringBuilder optimized for formatting. It implements the following key features beyond a
  * normal JDK StringBuilder:
  *
  * <ol>
@@ -24,33 +19,37 @@ import com.ibm.icu.text.UnicodeSet;
  * <li>Keeps tracks of Fields in an efficient manner.
  * <li>String operations are fast-pathed to code point operations when possible.
  * </ol>
+ *
+ * See also FormattedValueStringBuilderImpl.
+ *
+ * @author sffc (Shane Carr)
  */
-public class NumberStringBuilder implements CharSequence {
+public class FormattedStringBuilder implements CharSequence {
 
-    /** A constant, empty NumberStringBuilder. Do NOT call mutative operations on this. */
-    public static final NumberStringBuilder EMPTY = new NumberStringBuilder();
+    /** A constant, empty FormattedStringBuilder. Do NOT call mutative operations on this. */
+    public static final FormattedStringBuilder EMPTY = new FormattedStringBuilder();
 
-    private char[] chars;
-    private Field[] fields;
-    private int zero;
-    private int length;
+    char[] chars;
+    Field[] fields;
+    int zero;
+    int length;
 
-    public NumberStringBuilder() {
+    public FormattedStringBuilder() {
         this(40);
     }
 
-    public NumberStringBuilder(int capacity) {
+    public FormattedStringBuilder(int capacity) {
         chars = new char[capacity];
         fields = new Field[capacity];
         zero = capacity / 2;
         length = 0;
     }
 
-    public NumberStringBuilder(NumberStringBuilder source) {
+    public FormattedStringBuilder(FormattedStringBuilder source) {
         copyFrom(source);
     }
 
-    public void copyFrom(NumberStringBuilder source) {
+    public void copyFrom(FormattedStringBuilder source) {
         chars = Arrays.copyOf(source.chars, source.chars.length);
         fields = Arrays.copyOf(source.fields, source.fields.length);
         zero = source.zero;
@@ -101,7 +100,7 @@ public class NumberStringBuilder implements CharSequence {
         return Character.codePointBefore(chars, zero + index, zero);
     }
 
-    public NumberStringBuilder clear() {
+    public FormattedStringBuilder clear() {
         zero = getCapacity() / 2;
         length = 0;
         return this;
@@ -237,20 +236,20 @@ public class NumberStringBuilder implements CharSequence {
     }
 
     /**
-     * Appends the contents of another {@link NumberStringBuilder} to the end of this instance.
+     * Appends the contents of another {@link FormattedStringBuilder} to the end of this instance.
      *
-     * @return The number of chars added, which is the length of the other {@link NumberStringBuilder}.
+     * @return The number of chars added, which is the length of the other {@link FormattedStringBuilder}.
      */
-    public int append(NumberStringBuilder other) {
+    public int append(FormattedStringBuilder other) {
         return insert(length, other);
     }
 
     /**
-     * Inserts the contents of another {@link NumberStringBuilder} into this instance at the given index.
+     * Inserts the contents of another {@link FormattedStringBuilder} into this instance at the given index.
      *
-     * @return The number of chars added, which is the length of the other {@link NumberStringBuilder}.
+     * @return The number of chars added, which is the length of the other {@link FormattedStringBuilder}.
      */
-    public int insert(int index, NumberStringBuilder other) {
+    public int insert(int index, FormattedStringBuilder other) {
         if (this == other) {
             throw new IllegalArgumentException("Cannot call insert/append on myself");
         }
@@ -365,14 +364,14 @@ public class NumberStringBuilder implements CharSequence {
         return chars.length;
     }
 
-    /** Note: this returns a NumberStringBuilder. Do not return publicly. */
+    /** Note: this returns a FormattedStringBuilder. Do not return publicly. */
     @Override
     @Deprecated
     public CharSequence subSequence(int start, int end) {
         assert start >= 0;
         assert end <= length;
         assert end >= start;
-        NumberStringBuilder other = new NumberStringBuilder(this);
+        FormattedStringBuilder other = new FormattedStringBuilder(this);
         other.zero = zero + start;
         other.length = end - start;
         return other;
@@ -420,20 +419,22 @@ public class NumberStringBuilder implements CharSequence {
      *
      * <p>
      * For example, if the string is "-12.345", the debug string will be something like
-     * "&lt;NumberStringBuilder [-123.45] [-iii.ff]&gt;"
+     * "&lt;FormattedStringBuilder [-123.45] [-iii.ff]&gt;"
      *
      * @return A string for debugging purposes.
      */
     public String toDebugString() {
         StringBuilder sb = new StringBuilder();
-        sb.append("<NumberStringBuilder [");
+        sb.append("<FormattedStringBuilder [");
         sb.append(this.toString());
         sb.append("] [");
         for (int i = zero; i < zero + length; i++) {
             if (fields[i] == null) {
                 sb.append('n');
-            } else {
+            } else if (fieldToDebugChar.containsKey(fields[i])) {
                 sb.append(fieldToDebugChar.get(fields[i]));
+            } else {
+                sb.append('?');
             }
         }
         sb.append("]>");
@@ -475,7 +476,7 @@ public class NumberStringBuilder implements CharSequence {
      *            The instance to compare.
      * @return Whether the contents of this instance is currently equal to the given instance.
      */
-    public boolean contentEquals(NumberStringBuilder other) {
+    public boolean contentEquals(FormattedStringBuilder other) {
         if (length != other.length)
             return false;
         for (int i = 0; i < length; i++) {
@@ -495,170 +496,4 @@ public class NumberStringBuilder implements CharSequence {
     public boolean equals(Object other) {
         throw new UnsupportedOperationException("Don't call #hashCode() or #equals() on a mutable.");
     }
-
-    public boolean nextFieldPosition(FieldPosition fp) {
-        java.text.Format.Field rawField = fp.getFieldAttribute();
-
-        if (rawField == null) {
-            // Backwards compatibility: read from fp.getField()
-            if (fp.getField() == NumberFormat.INTEGER_FIELD) {
-                rawField = NumberFormat.Field.INTEGER;
-            } else if (fp.getField() == NumberFormat.FRACTION_FIELD) {
-                rawField = NumberFormat.Field.FRACTION;
-            } else {
-                // No field is set
-                return false;
-            }
-        }
-
-        if (!(rawField instanceof NumberFormat.Field)) {
-            throw new IllegalArgumentException(
-                    "You must pass an instance of com.ibm.icu.text.NumberFormat.Field as your FieldPosition attribute.  You passed: "
-                            + rawField.getClass().toString());
-        }
-
-        ConstrainedFieldPosition cfpos = new ConstrainedFieldPosition();
-        cfpos.constrainField(rawField);
-        cfpos.setState(rawField, null, fp.getBeginIndex(), fp.getEndIndex());
-        if (nextPosition(cfpos, null)) {
-            fp.setBeginIndex(cfpos.getStart());
-            fp.setEndIndex(cfpos.getLimit());
-            return true;
-        }
-
-        // Special case: fraction should start after integer if fraction is not present
-        if (rawField == NumberFormat.Field.FRACTION && fp.getEndIndex() == 0) {
-            boolean inside = false;
-            int i = zero;
-            for (; i < zero + length; i++) {
-                if (isIntOrGroup(fields[i]) || fields[i] == NumberFormat.Field.DECIMAL_SEPARATOR) {
-                    inside = true;
-                } else if (inside) {
-                    break;
-                }
-            }
-            fp.setBeginIndex(i - zero);
-            fp.setEndIndex(i - zero);
-        }
-
-        return false;
-    }
-
-    public AttributedCharacterIterator toCharacterIterator(Field numericField) {
-        ConstrainedFieldPosition cfpos = new ConstrainedFieldPosition();
-        AttributedString as = new AttributedString(toString());
-        while (this.nextPosition(cfpos, numericField)) {
-            // Backwards compatibility: field value = field
-            as.addAttribute(cfpos.getField(), cfpos.getField(), cfpos.getStart(), cfpos.getLimit());
-        }
-        return as.getIterator();
-    }
-
-    static class NullField extends Field {
-        private static final long serialVersionUID = 1L;
-        static final NullField END = new NullField("end");
-        private NullField(String name) {
-            super(name);
-        }
-    }
-
-    /**
-     * Implementation of nextPosition consistent with the contract of FormattedValue.
-     *
-     * @param cfpos
-     *            The argument passed to the public API.
-     * @param numericField
-     *            Optional. If non-null, apply this field to the entire numeric portion of the string.
-     * @return See FormattedValue#nextPosition.
-     */
-    public boolean nextPosition(ConstrainedFieldPosition cfpos, Field numericField) {
-        int fieldStart = -1;
-        Field currField = null;
-        for (int i = zero + cfpos.getLimit(); i <= zero + length; i++) {
-            Field _field = (i < zero + length) ? fields[i] : NullField.END;
-            // Case 1: currently scanning a field.
-            if (currField != null) {
-                if (currField != _field) {
-                    int end = i - zero;
-                    // Grouping separators can be whitespace; don't throw them out!
-                    if (currField != NumberFormat.Field.GROUPING_SEPARATOR) {
-                        end = trimBack(end);
-                    }
-                    if (end <= fieldStart) {
-                        // Entire field position is ignorable; skip.
-                        fieldStart = -1;
-                        currField = null;
-                        i--;  // look at this index again
-                        continue;
-                    }
-                    int start = fieldStart;
-                    if (currField != NumberFormat.Field.GROUPING_SEPARATOR) {
-                        start = trimFront(start);
-                    }
-                    cfpos.setState(currField, null, start, end);
-                    return true;
-                }
-                continue;
-            }
-            // Special case: coalesce the INTEGER if we are pointing at the end of the INTEGER.
-            if (cfpos.matchesField(NumberFormat.Field.INTEGER, null)
-                    && i > zero
-                    // don't return the same field twice in a row:
-                    && i - zero > cfpos.getLimit()
-                    && isIntOrGroup(fields[i - 1])
-                    && !isIntOrGroup(_field)) {
-                int j = i - 1;
-                for (; j >= zero && isIntOrGroup(fields[j]); j--) {}
-                cfpos.setState(NumberFormat.Field.INTEGER, null, j - zero + 1, i - zero);
-                return true;
-            }
-            // Special case: coalesce NUMERIC if we are pointing at the end of the NUMERIC.
-            if (numericField != null
-                    && cfpos.matchesField(numericField, null)
-                    && i > zero
-                    // don't return the same field twice in a row:
-                    && (i - zero > cfpos.getLimit() || cfpos.getField() != numericField)
-                    && isNumericField(fields[i - 1])
-                    && !isNumericField(_field)) {
-                int j = i - 1;
-                for (; j >= zero && isNumericField(fields[j]); j--) {}
-                cfpos.setState(numericField, null, j - zero + 1, i - zero);
-                return true;
-            }
-            // Special case: skip over INTEGER; will be coalesced later.
-            if (_field == NumberFormat.Field.INTEGER) {
-                _field = null;
-            }
-            // Case 2: no field starting at this position.
-            if (_field == null || _field == NullField.END) {
-                continue;
-            }
-            // Case 3: check for field starting at this position
-            if (cfpos.matchesField(_field, null)) {
-                fieldStart = i - zero;
-                currField = _field;
-            }
-        }
-
-        assert currField == null;
-        return false;
-    }
-
-    private static boolean isIntOrGroup(Field field) {
-        return field == NumberFormat.Field.INTEGER || field == NumberFormat.Field.GROUPING_SEPARATOR;
-    }
-
-    private static boolean isNumericField(Field field) {
-        return field == null || NumberFormat.Field.class.isAssignableFrom(field.getClass());
-    }
-
-    private int trimBack(int limit) {
-        return StaticUnicodeSets.get(StaticUnicodeSets.Key.DEFAULT_IGNORABLES)
-                .spanBack(this, limit, UnicodeSet.SpanCondition.CONTAINED);
-    }
-
-    private int trimFront(int start) {
-        return StaticUnicodeSets.get(StaticUnicodeSets.Key.DEFAULT_IGNORABLES)
-                .span(this, start, UnicodeSet.SpanCondition.CONTAINED);
-    }
 }
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/FormattedValueStringBuilderImpl.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/FormattedValueStringBuilderImpl.java
new file mode 100644 (file)
index 0000000..8bfe7a5
--- /dev/null
@@ -0,0 +1,193 @@
+// Â© 2019 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html#License
+package com.ibm.icu.impl;
+
+import java.text.AttributedCharacterIterator;
+import java.text.AttributedString;
+import java.text.FieldPosition;
+import java.text.Format.Field;
+
+import com.ibm.icu.text.ConstrainedFieldPosition;
+import com.ibm.icu.text.NumberFormat;
+import com.ibm.icu.text.UnicodeSet;
+
+/**
+ * Implementation of FormattedValue based on FormattedStringBuilder.
+ *
+ * The implementation currently revolves around numbers and number fields.
+ * However, it can be generalized in the future when there is a need.
+ *
+ * In C++, this implements FormattedValue. In Java, it is a stateless
+ * collection of static functions to avoid having to use nested objects.
+ *
+ * @author sffc (Shane Carr)
+ */
+public class FormattedValueStringBuilderImpl {
+
+
+    public static boolean nextFieldPosition(FormattedStringBuilder self, FieldPosition fp) {
+        java.text.Format.Field rawField = fp.getFieldAttribute();
+
+        if (rawField == null) {
+            // Backwards compatibility: read from fp.getField()
+            if (fp.getField() == NumberFormat.INTEGER_FIELD) {
+                rawField = NumberFormat.Field.INTEGER;
+            } else if (fp.getField() == NumberFormat.FRACTION_FIELD) {
+                rawField = NumberFormat.Field.FRACTION;
+            } else {
+                // No field is set
+                return false;
+            }
+        }
+
+        if (!(rawField instanceof NumberFormat.Field)) {
+            throw new IllegalArgumentException(
+                    "You must pass an instance of com.ibm.icu.text.NumberFormat.Field as your FieldPosition attribute.  You passed: "
+                            + rawField.getClass().toString());
+        }
+
+        ConstrainedFieldPosition cfpos = new ConstrainedFieldPosition();
+        cfpos.constrainField(rawField);
+        cfpos.setState(rawField, null, fp.getBeginIndex(), fp.getEndIndex());
+        if (nextPosition(self, cfpos, null)) {
+            fp.setBeginIndex(cfpos.getStart());
+            fp.setEndIndex(cfpos.getLimit());
+            return true;
+        }
+
+        // Special case: fraction should start after integer if fraction is not present
+        if (rawField == NumberFormat.Field.FRACTION && fp.getEndIndex() == 0) {
+            boolean inside = false;
+            int i = self.zero;
+            for (; i < self.zero + self.length; i++) {
+                if (isIntOrGroup(self.fields[i]) || self.fields[i] == NumberFormat.Field.DECIMAL_SEPARATOR) {
+                    inside = true;
+                } else if (inside) {
+                    break;
+                }
+            }
+            fp.setBeginIndex(i - self.zero);
+            fp.setEndIndex(i - self.zero);
+        }
+
+        return false;
+    }
+
+    public static AttributedCharacterIterator toCharacterIterator(FormattedStringBuilder self, Field numericField) {
+        ConstrainedFieldPosition cfpos = new ConstrainedFieldPosition();
+        AttributedString as = new AttributedString(self.toString());
+        while (nextPosition(self, cfpos, numericField)) {
+            // Backwards compatibility: field value = field
+            as.addAttribute(cfpos.getField(), cfpos.getField(), cfpos.getStart(), cfpos.getLimit());
+        }
+        return as.getIterator();
+    }
+
+    static class NullField extends Field {
+        private static final long serialVersionUID = 1L;
+        static final NullField END = new NullField("end");
+        private NullField(String name) {
+            super(name);
+        }
+    }
+
+    /**
+     * Implementation of nextPosition consistent with the contract of FormattedValue.
+     *
+     * @param cfpos
+     *            The argument passed to the public API.
+     * @param numericField
+     *            Optional. If non-null, apply this field to the entire numeric portion of the string.
+     * @return See FormattedValue#nextPosition.
+     */
+    public static boolean nextPosition(FormattedStringBuilder self, ConstrainedFieldPosition cfpos, Field numericField) {
+        int fieldStart = -1;
+        Field currField = null;
+        for (int i = self.zero + cfpos.getLimit(); i <= self.zero + self.length; i++) {
+            Field _field = (i < self.zero + self.length) ? self.fields[i] : NullField.END;
+            // Case 1: currently scanning a field.
+            if (currField != null) {
+                if (currField != _field) {
+                    int end = i - self.zero;
+                    // Grouping separators can be whitespace; don't throw them out!
+                    if (currField != NumberFormat.Field.GROUPING_SEPARATOR) {
+                        end = trimBack(self, end);
+                    }
+                    if (end <= fieldStart) {
+                        // Entire field position is ignorable; skip.
+                        fieldStart = -1;
+                        currField = null;
+                        i--;  // look at this index again
+                        continue;
+                    }
+                    int start = fieldStart;
+                    if (currField != NumberFormat.Field.GROUPING_SEPARATOR) {
+                        start = trimFront(self, start);
+                    }
+                    cfpos.setState(currField, null, start, end);
+                    return true;
+                }
+                continue;
+            }
+            // Special case: coalesce the INTEGER if we are pointing at the end of the INTEGER.
+            if (cfpos.matchesField(NumberFormat.Field.INTEGER, null)
+                    && i > self.zero
+                    // don't return the same field twice in a row:
+                    && i - self.zero > cfpos.getLimit()
+                    && isIntOrGroup(self.fields[i - 1])
+                    && !isIntOrGroup(_field)) {
+                int j = i - 1;
+                for (; j >= self.zero && isIntOrGroup(self.fields[j]); j--) {}
+                cfpos.setState(NumberFormat.Field.INTEGER, null, j - self.zero + 1, i - self.zero);
+                return true;
+            }
+            // Special case: coalesce NUMERIC if we are pointing at the end of the NUMERIC.
+            if (numericField != null
+                    && cfpos.matchesField(numericField, null)
+                    && i > self.zero
+                    // don't return the same field twice in a row:
+                    && (i - self.zero > cfpos.getLimit() || cfpos.getField() != numericField)
+                    && isNumericField(self.fields[i - 1])
+                    && !isNumericField(_field)) {
+                int j = i - 1;
+                for (; j >= self.zero && isNumericField(self.fields[j]); j--) {}
+                cfpos.setState(numericField, null, j - self.zero + 1, i - self.zero);
+                return true;
+            }
+            // Special case: skip over INTEGER; will be coalesced later.
+            if (_field == NumberFormat.Field.INTEGER) {
+                _field = null;
+            }
+            // Case 2: no field starting at this position.
+            if (_field == null || _field == NullField.END) {
+                continue;
+            }
+            // Case 3: check for field starting at this position
+            if (cfpos.matchesField(_field, null)) {
+                fieldStart = i - self.zero;
+                currField = _field;
+            }
+        }
+
+        assert currField == null;
+        return false;
+    }
+
+    private static boolean isIntOrGroup(Field field) {
+        return field == NumberFormat.Field.INTEGER || field == NumberFormat.Field.GROUPING_SEPARATOR;
+    }
+
+    private static boolean isNumericField(Field field) {
+        return field == null || NumberFormat.Field.class.isAssignableFrom(field.getClass());
+    }
+
+    private static int trimBack(FormattedStringBuilder self, int limit) {
+        return StaticUnicodeSets.get(StaticUnicodeSets.Key.DEFAULT_IGNORABLES)
+                .spanBack(self, limit, UnicodeSet.SpanCondition.CONTAINED);
+    }
+
+    private static int trimFront(FormattedStringBuilder self, int start) {
+        return StaticUnicodeSets.get(StaticUnicodeSets.Key.DEFAULT_IGNORABLES)
+                .span(self, start, UnicodeSet.SpanCondition.CONTAINED);
+    }
+}
index 7ccf083ed61b48f9d24d1c54120820b1a1fe88b4..ce3f66792689f3494aa9a531d6ed61ea1e0a7ad8 100644 (file)
@@ -6,14 +6,16 @@ import com.ibm.icu.lang.UCharacter;
 import com.ibm.icu.text.UnicodeSet;
 
 /**
- * A mutable String wrapper with a variable offset and length and support for case folding.
- * <p>
- * The charAt, length, and subSequence methods all operate relative to the fixed offset into the String.
- * <p>
- * CAUTION: Since this class is mutable, it must not be used anywhere that an immutable object is
- * required, like in a cache or as the key of a hash map.
+ * A mutable String wrapper with a variable offset and length and
+ * support for case folding. The charAt, length, and subSequence methods all
+ * operate relative to the fixed offset into the String.
  *
- * @author sffc
+ * Intended to be useful for parsing.
+ *
+ * CAUTION: Since this class is mutable, it must not be used anywhere that an
+ * immutable object is required, like in a cache or as the key of a hash map.
+ *
+ * @author sffc (Shane Carr)
  */
 public class StringSegment implements CharSequence {
     private final String str;
index efb41bce61af112645b1104a4dc2e2f1491a3d5f..ca79325259c4ab7ecd04912372ea86cd835123df 100644 (file)
@@ -2,6 +2,7 @@
 // License & terms of use: http://www.unicode.org/copyright.html#License
 package com.ibm.icu.impl.number;
 
+import com.ibm.icu.impl.FormattedStringBuilder;
 import com.ibm.icu.text.NumberFormat;
 import com.ibm.icu.text.UnicodeSet;
 
@@ -290,7 +291,7 @@ public class AffixUtils {
     /**
      * Executes the unescape state machine. Replaces the unquoted characters "-", "+", "%", "‰", and "¤"
      * with the corresponding symbols provided by the {@link SymbolProvider}, and inserts the result into
-     * the NumberStringBuilder at the requested location.
+     * the FormattedStringBuilder at the requested location.
      *
      * <p>
      * Example input: "'-'¤x"; example output: "-$x"
@@ -298,16 +299,16 @@ public class AffixUtils {
      * @param affixPattern
      *            The original string to be unescaped.
      * @param output
-     *            The NumberStringBuilder to mutate with the result.
+     *            The FormattedStringBuilder to mutate with the result.
      * @param position
-     *            The index into the NumberStringBuilder to insert the the string.
+     *            The index into the FormattedStringBuilder to insert the the string.
      * @param provider
      *            An object to generate locale symbols.
      * @return The length of the string added to affixPattern.
      */
     public static int unescape(
             CharSequence affixPattern,
-            NumberStringBuilder output,
+            FormattedStringBuilder output,
             int position,
             SymbolProvider provider,
             NumberFormat.Field field) {
index c82d50d7e01353133223f12ebd9ceaec2743c23f..92498513dfa2c04aa6920db6db1e7442cd72b3ac 100644 (file)
@@ -4,6 +4,8 @@ package com.ibm.icu.impl.number;
 
 import java.text.Format.Field;
 
+import com.ibm.icu.impl.FormattedStringBuilder;
+
 /**
  * The canonical implementation of {@link Modifier}, containing a prefix and suffix string.
  */
@@ -52,7 +54,7 @@ public class ConstantAffixModifier implements Modifier {
     }
 
     @Override
-    public int apply(NumberStringBuilder output, int leftIndex, int rightIndex) {
+    public int apply(FormattedStringBuilder output, int leftIndex, int rightIndex) {
         // Insert the suffix first since inserting the prefix will change the rightIndex
         int length = output.insert(rightIndex, suffix, field);
         length += output.insert(leftIndex, prefix, field);
index 673296005a8c23626be9aeabb33bed85e661e0c2..39d57c4618d38e59eaac396e8831930b19a7a8f7 100644 (file)
@@ -5,14 +5,16 @@ package com.ibm.icu.impl.number;
 import java.text.Format.Field;
 import java.util.Arrays;
 
+import com.ibm.icu.impl.FormattedStringBuilder;
+
 /**
  * An implementation of {@link Modifier} that allows for multiple types of fields in the same modifier.
- * Constructed based on the contents of two {@link NumberStringBuilder} instances (one for the prefix,
+ * Constructed based on the contents of two {@link FormattedStringBuilder} instances (one for the prefix,
  * one for the suffix).
  */
 public class ConstantMultiFieldModifier implements Modifier {
 
-    // NOTE: In Java, these are stored as array pointers. In C++, the NumberStringBuilder is stored by
+    // NOTE: In Java, these are stored as array pointers. In C++, the FormattedStringBuilder is stored by
     // value and is treated internally as immutable.
     protected final char[] prefixChars;
     protected final char[] suffixChars;
@@ -25,16 +27,16 @@ public class ConstantMultiFieldModifier implements Modifier {
     private final Parameters parameters;
 
     public ConstantMultiFieldModifier(
-            NumberStringBuilder prefix,
-            NumberStringBuilder suffix,
+            FormattedStringBuilder prefix,
+            FormattedStringBuilder suffix,
             boolean overwrite,
             boolean strong) {
         this(prefix, suffix, overwrite, strong, null);
     }
 
     public ConstantMultiFieldModifier(
-            NumberStringBuilder prefix,
-            NumberStringBuilder suffix,
+            FormattedStringBuilder prefix,
+            FormattedStringBuilder suffix,
             boolean overwrite,
             boolean strong,
             Parameters parameters) {
@@ -48,7 +50,7 @@ public class ConstantMultiFieldModifier implements Modifier {
     }
 
     @Override
-    public int apply(NumberStringBuilder output, int leftIndex, int rightIndex) {
+    public int apply(FormattedStringBuilder output, int leftIndex, int rightIndex) {
         int length = output.insert(leftIndex, prefixChars, prefixFields);
         if (overwrite) {
             length += output.splice(leftIndex + length, rightIndex + length, "", 0, 0, null);
@@ -109,7 +111,7 @@ public class ConstantMultiFieldModifier implements Modifier {
 
     @Override
     public String toString() {
-        NumberStringBuilder temp = new NumberStringBuilder();
+        FormattedStringBuilder temp = new FormattedStringBuilder();
         apply(temp, 0, 0);
         int prefixLength = getPrefixLength();
         return String.format("<ConstantMultiFieldModifier prefix:'%s' suffix:'%s'>",
index 61c04c53a4a24752dc1d4d36e94ddac0a4b7a0dd..e0f3be3fb05b4dd3ef0a73e3f6b4462b02df7251 100644 (file)
@@ -4,6 +4,7 @@ package com.ibm.icu.impl.number;
 
 import java.text.Format.Field;
 
+import com.ibm.icu.impl.FormattedStringBuilder;
 import com.ibm.icu.text.DecimalFormatSymbols;
 import com.ibm.icu.text.NumberFormat;
 import com.ibm.icu.text.UnicodeSet;
@@ -30,8 +31,8 @@ public class CurrencySpacingEnabledModifier extends ConstantMultiFieldModifier {
 
     /** Safe code path */
     public CurrencySpacingEnabledModifier(
-            NumberStringBuilder prefix,
-            NumberStringBuilder suffix,
+            FormattedStringBuilder prefix,
+            FormattedStringBuilder suffix,
             boolean overwrite,
             boolean strong,
             DecimalFormatSymbols symbols) {
@@ -73,7 +74,7 @@ public class CurrencySpacingEnabledModifier extends ConstantMultiFieldModifier {
 
     /** Safe code path */
     @Override
-    public int apply(NumberStringBuilder output, int leftIndex, int rightIndex) {
+    public int apply(FormattedStringBuilder output, int leftIndex, int rightIndex) {
         // Currency spacing logic
         int length = 0;
         if (rightIndex - leftIndex > 0
@@ -96,7 +97,7 @@ public class CurrencySpacingEnabledModifier extends ConstantMultiFieldModifier {
 
     /** Unsafe code path */
     public static int applyCurrencySpacing(
-            NumberStringBuilder output,
+            FormattedStringBuilder output,
             int prefixStart,
             int prefixLen,
             int suffixStart,
@@ -117,7 +118,7 @@ public class CurrencySpacingEnabledModifier extends ConstantMultiFieldModifier {
 
     /** Unsafe code path */
     private static int applyCurrencySpacingAffix(
-            NumberStringBuilder output,
+            FormattedStringBuilder output,
             int index,
             byte affix,
             DecimalFormatSymbols symbols) {
index f3f4635fedb70d351339fc56afbd8e4c6b49bf5a..cc56329d1d3b807712882fd164929958bdd2b0f4 100644 (file)
@@ -4,6 +4,7 @@ package com.ibm.icu.impl.number;
 
 import java.text.Format.Field;
 
+import com.ibm.icu.impl.FormattedStringBuilder;
 import com.ibm.icu.impl.StandardPlural;
 
 /**
@@ -29,7 +30,7 @@ public interface Modifier {
      *            number is being formatted.
      * @return The number of characters (UTF-16 code units) that were added to the string builder.
      */
-    public int apply(NumberStringBuilder output, int leftIndex, int rightIndex);
+    public int apply(FormattedStringBuilder output, int leftIndex, int rightIndex);
 
     /**
      * Gets the length of the prefix. This information can be used in combination with {@link #apply} to
index b1c1e9a0ee71b1a1d0d12307403b4d57c026fdba..67f79b9ecc7212a7d2d9113e1ad5c5b0656b6646 100644 (file)
@@ -2,6 +2,7 @@
 // License & terms of use: http://www.unicode.org/copyright.html#License
 package com.ibm.icu.impl.number;
 
+import com.ibm.icu.impl.FormattedStringBuilder;
 import com.ibm.icu.impl.StandardPlural;
 import com.ibm.icu.impl.number.AffixUtils.SymbolProvider;
 import com.ibm.icu.number.NumberFormatter.SignDisplay;
@@ -167,8 +168,8 @@ public class MutablePatternModifier implements Modifier, SymbolProvider, MicroPr
      * @return An immutable that supports both positive and negative numbers.
      */
     public ImmutablePatternModifier createImmutableAndChain(MicroPropsGenerator parent) {
-        NumberStringBuilder a = new NumberStringBuilder();
-        NumberStringBuilder b = new NumberStringBuilder();
+        FormattedStringBuilder a = new FormattedStringBuilder();
+        FormattedStringBuilder b = new FormattedStringBuilder();
         if (needsPlurals()) {
             // Slower path when we require the plural keyword.
             AdoptingModifierStore pm = new AdoptingModifierStore();
@@ -200,15 +201,15 @@ public class MutablePatternModifier implements Modifier, SymbolProvider, MicroPr
      * spacing support if required.
      *
      * @param a
-     *            A working NumberStringBuilder object; passed from the outside to prevent the need to
+     *            A working FormattedStringBuilder object; passed from the outside to prevent the need to
      *            create many new instances if this method is called in a loop.
      * @param b
-     *            Another working NumberStringBuilder object.
+     *            Another working FormattedStringBuilder object.
      * @return The constant modifier object.
      */
     private ConstantMultiFieldModifier createConstantModifier(
-            NumberStringBuilder a,
-            NumberStringBuilder b) {
+            FormattedStringBuilder a,
+            FormattedStringBuilder b) {
         insertPrefix(a.clear(), 0);
         insertSuffix(b.clear(), 0);
         if (patternInfo.hasCurrencySign()) {
@@ -280,7 +281,7 @@ public class MutablePatternModifier implements Modifier, SymbolProvider, MicroPr
     }
 
     @Override
-    public int apply(NumberStringBuilder output, int leftIndex, int rightIndex) {
+    public int apply(FormattedStringBuilder output, int leftIndex, int rightIndex) {
         int prefixLen = insertPrefix(output, leftIndex);
         int suffixLen = insertSuffix(output, rightIndex + prefixLen);
         // If the pattern had no decimal stem body (like #,##0.00), overwrite the value.
@@ -341,13 +342,13 @@ public class MutablePatternModifier implements Modifier, SymbolProvider, MicroPr
         return false;
     }
 
-    private int insertPrefix(NumberStringBuilder sb, int position) {
+    private int insertPrefix(FormattedStringBuilder sb, int position) {
         prepareAffix(true);
         int length = AffixUtils.unescape(currentAffix, sb, position, this, field);
         return length;
     }
 
-    private int insertSuffix(NumberStringBuilder sb, int position) {
+    private int insertSuffix(FormattedStringBuilder sb, int position) {
         prepareAffix(false);
         int length = AffixUtils.unescape(currentAffix, sb, position, this, field);
         return length;
index 97a310900dac47b0ff6afc55b8212dd3e77958b0..ccbf871ae990928af3162bbda985f1a0e342870c 100644 (file)
@@ -2,6 +2,8 @@
 // License & terms of use: http://www.unicode.org/copyright.html#License
 package com.ibm.icu.impl.number;
 
+import com.ibm.icu.impl.FormattedStringBuilder;
+
 public class Padder {
     public static final String FALLBACK_PADDING_STRING = "\u0020"; // i.e. a space
 
@@ -79,7 +81,7 @@ public class Padder {
     public int padAndApply(
             Modifier mod1,
             Modifier mod2,
-            NumberStringBuilder string,
+            FormattedStringBuilder string,
             int leftIndex,
             int rightIndex) {
         int modLength = mod1.getCodePointCount() + mod2.getCodePointCount();
@@ -114,7 +116,7 @@ public class Padder {
     private static int addPaddingHelper(
             String paddingString,
             int requiredPadding,
-            NumberStringBuilder string,
+            FormattedStringBuilder string,
             int index) {
         for (int i = 0; i < requiredPadding; i++) {
             // TODO: If appending to the end, this will cause actual insertion operations. Improve.
index 26cb275c5f7db41c37f3f548be7628dc685c7e3a..6241848a259a8a0b6ac751afadde139e98125f3f 100644 (file)
@@ -4,6 +4,7 @@ package com.ibm.icu.impl.number;
 
 import java.text.Format.Field;
 
+import com.ibm.icu.impl.FormattedStringBuilder;
 import com.ibm.icu.impl.SimpleFormatterImpl;
 import com.ibm.icu.impl.number.range.PrefixInfixSuffixLengthHelper;
 import com.ibm.icu.util.ICUException;
@@ -65,7 +66,7 @@ public class SimpleModifier implements Modifier {
     }
 
     @Override
-    public int apply(NumberStringBuilder output, int leftIndex, int rightIndex) {
+    public int apply(FormattedStringBuilder output, int leftIndex, int rightIndex) {
         return formatAsPrefixSuffix(output, leftIndex, rightIndex);
     }
 
@@ -138,7 +139,7 @@ public class SimpleModifier implements Modifier {
      * @return The number of characters (UTF-16 code points) that were added to the StringBuilder.
      */
     public int formatAsPrefixSuffix(
-            NumberStringBuilder result,
+            FormattedStringBuilder result,
             int startIndex,
             int endIndex) {
         if (suffixOffset == -1) {
@@ -161,16 +162,16 @@ public class SimpleModifier implements Modifier {
 
     /**
      * TODO: Like above, this belongs with the rest of the SimpleFormatterImpl code.
-     * I put it here so that the SimpleFormatter uses in NumberStringBuilder are near each other.
+     * I put it here so that the SimpleFormatter uses in FormattedStringBuilder are near each other.
      *
      * <p>
-     * Applies the compiled two-argument pattern to the NumberStringBuilder.
+     * Applies the compiled two-argument pattern to the FormattedStringBuilder.
      *
      * <p>
      * This method is optimized for the case where the prefix and suffix are often empty, such as
      * in the range pattern like "{0}-{1}".
      */
-    public static void formatTwoArgPattern(String compiledPattern, NumberStringBuilder result, int index, PrefixInfixSuffixLengthHelper h,
+    public static void formatTwoArgPattern(String compiledPattern, FormattedStringBuilder result, int index, PrefixInfixSuffixLengthHelper h,
             Field field) {
         int argLimit = SimpleFormatterImpl.getArgumentLimit(compiledPattern);
         if (argLimit != 2) {
index 4fda533b43495763d6988061e07b2c8dde1f0ea4..c6071445c24bad95677c36b6bcba79b027254a95 100644 (file)
@@ -7,9 +7,10 @@ import java.text.AttributedCharacterIterator;
 import java.text.FieldPosition;
 import java.util.Arrays;
 
+import com.ibm.icu.impl.FormattedStringBuilder;
+import com.ibm.icu.impl.FormattedValueStringBuilderImpl;
 import com.ibm.icu.impl.Utility;
 import com.ibm.icu.impl.number.DecimalQuantity;
-import com.ibm.icu.impl.number.NumberStringBuilder;
 import com.ibm.icu.text.ConstrainedFieldPosition;
 import com.ibm.icu.text.FormattedValue;
 import com.ibm.icu.text.PluralRules.IFixedDecimal;
@@ -25,10 +26,10 @@ import com.ibm.icu.text.PluralRules.IFixedDecimal;
  * @see NumberFormatter
  */
 public class FormattedNumber implements FormattedValue {
-    final NumberStringBuilder string;
+    final FormattedStringBuilder string;
     final DecimalQuantity fq;
 
-    FormattedNumber(NumberStringBuilder nsb, DecimalQuantity fq) {
+    FormattedNumber(FormattedStringBuilder nsb, DecimalQuantity fq) {
         this.string = nsb;
         this.fq = fq;
     }
@@ -96,7 +97,7 @@ public class FormattedNumber implements FormattedValue {
      */
     @Override
     public boolean nextPosition(ConstrainedFieldPosition cfpos) {
-        return string.nextPosition(cfpos, null);
+        return FormattedValueStringBuilderImpl.nextPosition(string, cfpos, null);
     }
 
     /**
@@ -107,7 +108,7 @@ public class FormattedNumber implements FormattedValue {
      */
     @Override
     public AttributedCharacterIterator toCharacterIterator() {
-        return string.toCharacterIterator(null);
+        return FormattedValueStringBuilderImpl.toCharacterIterator(string, null);
     }
 
     /**
@@ -145,7 +146,7 @@ public class FormattedNumber implements FormattedValue {
      */
     public boolean nextFieldPosition(FieldPosition fieldPosition) {
         fq.populateUFieldPosition(fieldPosition);
-        return string.nextFieldPosition(fieldPosition);
+        return FormattedValueStringBuilderImpl.nextFieldPosition(string, fieldPosition);
     }
 
     /**
@@ -179,7 +180,7 @@ public class FormattedNumber implements FormattedValue {
      */
     @Override
     public int hashCode() {
-        // NumberStringBuilder and BigDecimal are mutable, so we can't call
+        // FormattedStringBuilder and BigDecimal are mutable, so we can't call
         // #equals() or #hashCode() on them directly.
         return Arrays.hashCode(string.toCharArray())
                 ^ Arrays.hashCode(string.toFieldArray())
@@ -200,7 +201,7 @@ public class FormattedNumber implements FormattedValue {
             return false;
         if (!(other instanceof FormattedNumber))
             return false;
-        // NumberStringBuilder and BigDecimal are mutable, so we can't call
+        // FormattedStringBuilder and BigDecimal are mutable, so we can't call
         // #equals() or #hashCode() on them directly.
         FormattedNumber _other = (FormattedNumber) other;
         return Arrays.equals(string.toCharArray(), _other.string.toCharArray())
index e23a96ded2b54850aa4f2fe2f1017ba2e1148753..9992a5a015e2014ceb4e416abedee98a51e4281d 100644 (file)
@@ -8,8 +8,9 @@ import java.text.AttributedCharacterIterator;
 import java.text.FieldPosition;
 import java.util.Arrays;
 
+import com.ibm.icu.impl.FormattedStringBuilder;
+import com.ibm.icu.impl.FormattedValueStringBuilderImpl;
 import com.ibm.icu.impl.number.DecimalQuantity;
-import com.ibm.icu.impl.number.NumberStringBuilder;
 import com.ibm.icu.number.NumberRangeFormatter.RangeIdentityResult;
 import com.ibm.icu.text.ConstrainedFieldPosition;
 import com.ibm.icu.text.FormattedValue;
@@ -27,12 +28,12 @@ import com.ibm.icu.util.ICUUncheckedIOException;
  * @see NumberRangeFormatter
  */
 public class FormattedNumberRange implements FormattedValue {
-    final NumberStringBuilder string;
+    final FormattedStringBuilder string;
     final DecimalQuantity quantity1;
     final DecimalQuantity quantity2;
     final RangeIdentityResult identityResult;
 
-    FormattedNumberRange(NumberStringBuilder string, DecimalQuantity quantity1, DecimalQuantity quantity2,
+    FormattedNumberRange(FormattedStringBuilder string, DecimalQuantity quantity1, DecimalQuantity quantity2,
             RangeIdentityResult identityResult) {
         this.string = string;
         this.quantity1 = quantity1;
@@ -109,7 +110,7 @@ public class FormattedNumberRange implements FormattedValue {
      */
     @Override
     public boolean nextPosition(ConstrainedFieldPosition cfpos) {
-        return string.nextPosition(cfpos, null);
+        return FormattedValueStringBuilderImpl.nextPosition(string, cfpos, null);
     }
 
     /**
@@ -142,7 +143,7 @@ public class FormattedNumberRange implements FormattedValue {
      * @see NumberRangeFormatter
      */
     public boolean nextFieldPosition(FieldPosition fieldPosition) {
-        return string.nextFieldPosition(fieldPosition);
+        return FormattedValueStringBuilderImpl.nextFieldPosition(string, fieldPosition);
     }
 
     /**
@@ -153,7 +154,7 @@ public class FormattedNumberRange implements FormattedValue {
      */
     @Override
     public AttributedCharacterIterator toCharacterIterator() {
-        return string.toCharacterIterator(null);
+        return FormattedValueStringBuilderImpl.toCharacterIterator(string, null);
     }
 
     /**
@@ -207,7 +208,7 @@ public class FormattedNumberRange implements FormattedValue {
      */
     @Override
     public int hashCode() {
-        // NumberStringBuilder and BigDecimal are mutable, so we can't call
+        // FormattedStringBuilder and BigDecimal are mutable, so we can't call
         // #equals() or #hashCode() on them directly.
         return Arrays.hashCode(string.toCharArray()) ^ Arrays.hashCode(string.toFieldArray())
                 ^ quantity1.toBigDecimal().hashCode() ^ quantity2.toBigDecimal().hashCode();
@@ -227,7 +228,7 @@ public class FormattedNumberRange implements FormattedValue {
             return false;
         if (!(other instanceof FormattedNumberRange))
             return false;
-        // NumberStringBuilder and BigDecimal are mutable, so we can't call
+        // FormattedStringBuilder and BigDecimal are mutable, so we can't call
         // #equals() or #hashCode() on them directly.
         FormattedNumberRange _other = (FormattedNumberRange) other;
         return Arrays.equals(string.toCharArray(), _other.string.toCharArray())
index d50aeee0dc78c727ce3ddeab32fbb71ea403876a..eace5ba3f87ba7c4f8959baf22695cac7730d94b 100644 (file)
@@ -7,12 +7,12 @@ import java.text.Format;
 import java.util.Objects;
 import java.util.concurrent.atomic.AtomicLongFieldUpdater;
 
+import com.ibm.icu.impl.FormattedStringBuilder;
 import com.ibm.icu.impl.StandardPlural;
 import com.ibm.icu.impl.number.DecimalQuantity;
 import com.ibm.icu.impl.number.DecimalQuantity_DualStorageBCD;
 import com.ibm.icu.impl.number.LocalizedNumberFormatterAsFormat;
 import com.ibm.icu.impl.number.MacroProps;
-import com.ibm.icu.impl.number.NumberStringBuilder;
 import com.ibm.icu.math.BigDecimal;
 import com.ibm.icu.util.CurrencyAmount;
 import com.ibm.icu.util.Measure;
@@ -135,9 +135,9 @@ public class LocalizedNumberFormatter extends NumberFormatterSettings<LocalizedN
         return new LocalizedNumberFormatterAsFormat(this, resolve().loc);
     }
 
-    /** Helper method that creates a NumberStringBuilder and formats. */
+    /** Helper method that creates a FormattedStringBuilder and formats. */
     private FormattedNumber format(DecimalQuantity fq) {
-        NumberStringBuilder string = new NumberStringBuilder();
+        FormattedStringBuilder string = new FormattedStringBuilder();
         formatImpl(fq, string);
         return new FormattedNumber(string, fq);
     }
@@ -159,7 +159,7 @@ public class LocalizedNumberFormatter extends NumberFormatterSettings<LocalizedN
      * @deprecated ICU 60 This API is ICU internal only.
      */
     @Deprecated
-    public void formatImpl(DecimalQuantity fq, NumberStringBuilder string) {
+    public void formatImpl(DecimalQuantity fq, FormattedStringBuilder string) {
         if (computeCompiled()) {
             compiled.format(fq, string);
         } else {
@@ -174,7 +174,7 @@ public class LocalizedNumberFormatter extends NumberFormatterSettings<LocalizedN
      */
     @Deprecated
     public String getAffixImpl(boolean isPrefix, boolean isNegative) {
-        NumberStringBuilder string = new NumberStringBuilder();
+        FormattedStringBuilder string = new FormattedStringBuilder();
         byte signum = (byte) (isNegative ? -1 : 1);
         // Always return affixes for plural form OTHER.
         StandardPlural plural = StandardPlural.OTHER;
index 4adf9589d2355c047b7b00809c26439a9e7780eb..36774122ed005c2ea825d47e5ac3caecd20bc01a 100644 (file)
@@ -3,6 +3,7 @@
 package com.ibm.icu.number;
 
 import com.ibm.icu.impl.CurrencyData;
+import com.ibm.icu.impl.FormattedStringBuilder;
 import com.ibm.icu.impl.CurrencyData.CurrencyFormatInfo;
 import com.ibm.icu.impl.StandardPlural;
 import com.ibm.icu.impl.number.CompactData.CompactType;
@@ -16,7 +17,6 @@ import com.ibm.icu.impl.number.MicroProps;
 import com.ibm.icu.impl.number.MicroPropsGenerator;
 import com.ibm.icu.impl.number.MultiplierFormatHandler;
 import com.ibm.icu.impl.number.MutablePatternModifier;
-import com.ibm.icu.impl.number.NumberStringBuilder;
 import com.ibm.icu.impl.number.Padder;
 import com.ibm.icu.impl.number.PatternStringParser;
 import com.ibm.icu.impl.number.PatternStringParser.ParsedPatternInfo;
@@ -54,7 +54,7 @@ class NumberFormatterImpl {
     public static int formatStatic(
             MacroProps macros,
             DecimalQuantity inValue,
-            NumberStringBuilder outString) {
+            FormattedStringBuilder outString) {
         MicroProps micros = preProcessUnsafe(macros, inValue);
         int length = writeNumber(micros, inValue, outString, 0);
         length += writeAffixes(micros, outString, 0, length);
@@ -71,7 +71,7 @@ class NumberFormatterImpl {
             MacroProps macros,
             byte signum,
             StandardPlural plural,
-            NumberStringBuilder output) {
+            FormattedStringBuilder output) {
         MicroProps micros = new MicroProps(false);
         MicroPropsGenerator microPropsGenerator = macrosToMicroGenerator(macros, micros, false);
         return getPrefixSuffixImpl(microPropsGenerator, signum, output);
@@ -85,7 +85,7 @@ class NumberFormatterImpl {
     /**
      * Evaluates the "safe" MicroPropsGenerator created by "fromMacros".
      */
-    public int format(DecimalQuantity inValue, NumberStringBuilder outString) {
+    public int format(DecimalQuantity inValue, FormattedStringBuilder outString) {
         MicroProps micros = preProcess(inValue);
         int length = writeNumber(micros, inValue, outString, 0);
         length += writeAffixes(micros, outString, 0, length);
@@ -121,11 +121,11 @@ class NumberFormatterImpl {
         return micros;
     }
 
-    public int getPrefixSuffix(byte signum, StandardPlural plural, NumberStringBuilder output) {
+    public int getPrefixSuffix(byte signum, StandardPlural plural, FormattedStringBuilder output) {
         return getPrefixSuffixImpl(microPropsGenerator, signum, output);
     }
 
-    private static int getPrefixSuffixImpl(MicroPropsGenerator generator, byte signum, NumberStringBuilder output) {
+    private static int getPrefixSuffixImpl(MicroPropsGenerator generator, byte signum, FormattedStringBuilder output) {
         // #13453: DecimalFormat wants the affixes from the pattern only (modMiddle).
         // TODO: Clean this up, closer to C++. The pattern modifier is not as accessible as in C++.
         // Right now, ignore the plural form, run the pipeline with number 0, and get the modifier from the result.
@@ -395,7 +395,7 @@ class NumberFormatterImpl {
      */
     public static int writeAffixes(
             MicroProps micros,
-            NumberStringBuilder string,
+            FormattedStringBuilder string,
             int start,
             int end) {
         // Always apply the inner modifier (which is "strong").
@@ -416,7 +416,7 @@ class NumberFormatterImpl {
     public static int writeNumber(
             MicroProps micros,
             DecimalQuantity quantity,
-            NumberStringBuilder string,
+            FormattedStringBuilder string,
             int index) {
         int length = 0;
         if (quantity.isInfinite()) {
@@ -448,7 +448,7 @@ class NumberFormatterImpl {
     private static int writeIntegerDigits(
             MicroProps micros,
             DecimalQuantity quantity,
-            NumberStringBuilder string,
+            FormattedStringBuilder string,
             int index) {
         int length = 0;
         int integerCount = quantity.getUpperDisplayMagnitude() + 1;
@@ -479,7 +479,7 @@ class NumberFormatterImpl {
     private static int writeFractionDigits(
             MicroProps micros,
             DecimalQuantity quantity,
-            NumberStringBuilder string,
+            FormattedStringBuilder string,
             int index) {
         int length = 0;
         int fractionCount = -quantity.getLowerDisplayMagnitude();
index 8b9059bbcead6ac8487b4a110895e4c20c83210c..81f4bd57a7e20762b960f8658705a2afa416bc4e 100644 (file)
@@ -6,6 +6,7 @@ import java.util.MissingResourceException;
 
 import com.ibm.icu.impl.ICUData;
 import com.ibm.icu.impl.ICUResourceBundle;
+import com.ibm.icu.impl.FormattedStringBuilder;
 import com.ibm.icu.impl.PatternProps;
 import com.ibm.icu.impl.SimpleFormatterImpl;
 import com.ibm.icu.impl.StandardPlural;
@@ -13,7 +14,6 @@ import com.ibm.icu.impl.UResource;
 import com.ibm.icu.impl.number.DecimalQuantity;
 import com.ibm.icu.impl.number.MicroProps;
 import com.ibm.icu.impl.number.Modifier;
-import com.ibm.icu.impl.number.NumberStringBuilder;
 import com.ibm.icu.impl.number.SimpleModifier;
 import com.ibm.icu.impl.number.range.PrefixInfixSuffixLengthHelper;
 import com.ibm.icu.impl.number.range.RangeMacroProps;
@@ -152,7 +152,7 @@ class NumberRangeFormatterImpl {
     }
 
     public FormattedNumberRange format(DecimalQuantity quantity1, DecimalQuantity quantity2, boolean equalBeforeRounding) {
-        NumberStringBuilder string = new NumberStringBuilder();
+        FormattedStringBuilder string = new FormattedStringBuilder();
         MicroProps micros1 = formatterImpl1.preProcess(quantity1);
         MicroProps micros2;
         if (fSameFormatters) {
@@ -215,7 +215,7 @@ class NumberRangeFormatterImpl {
         return new FormattedNumberRange(string, quantity1, quantity2, identityResult);
     }
 
-    private void formatSingleValue(DecimalQuantity quantity1, DecimalQuantity quantity2, NumberStringBuilder string,
+    private void formatSingleValue(DecimalQuantity quantity1, DecimalQuantity quantity2, FormattedStringBuilder string,
             MicroProps micros1, MicroProps micros2) {
         if (fSameFormatters) {
             int length = NumberFormatterImpl.writeNumber(micros1, quantity1, string, 0);
@@ -226,7 +226,7 @@ class NumberRangeFormatterImpl {
 
     }
 
-    private void formatApproximately(DecimalQuantity quantity1, DecimalQuantity quantity2, NumberStringBuilder string,
+    private void formatApproximately(DecimalQuantity quantity1, DecimalQuantity quantity2, FormattedStringBuilder string,
             MicroProps micros1, MicroProps micros2) {
         if (fSameFormatters) {
             int length = NumberFormatterImpl.writeNumber(micros1, quantity1, string, 0);
@@ -240,7 +240,7 @@ class NumberRangeFormatterImpl {
         }
     }
 
-    private void formatRange(DecimalQuantity quantity1, DecimalQuantity quantity2, NumberStringBuilder string,
+    private void formatRange(DecimalQuantity quantity1, DecimalQuantity quantity2, FormattedStringBuilder string,
             MicroProps micros1, MicroProps micros2) {
         // modInner is always notation (scientific); collapsable in ALL.
         // modOuter is always units; collapsable in ALL, AUTO, and UNIT.
index e94aa9895e428ecd32300b21a2df6b8219acdf4c..f195f6e299fa9b29a08a7530fb649b44790b149f 100644 (file)
@@ -4,12 +4,12 @@ package com.ibm.icu.number;
 
 import java.text.Format.Field;
 
+import com.ibm.icu.impl.FormattedStringBuilder;
 import com.ibm.icu.impl.number.DecimalQuantity;
 import com.ibm.icu.impl.number.MicroProps;
 import com.ibm.icu.impl.number.MicroPropsGenerator;
 import com.ibm.icu.impl.number.Modifier;
 import com.ibm.icu.impl.number.MultiplierProducer;
-import com.ibm.icu.impl.number.NumberStringBuilder;
 import com.ibm.icu.impl.number.RoundingUtils;
 import com.ibm.icu.number.NumberFormatter.SignDisplay;
 import com.ibm.icu.number.Precision.SignificantRounderImpl;
@@ -256,11 +256,11 @@ public class ScientificNotation extends Notation implements Cloneable {
         }
 
         @Override
-        public int apply(NumberStringBuilder output, int leftIndex, int rightIndex) {
+        public int apply(FormattedStringBuilder output, int leftIndex, int rightIndex) {
             return doApply(exponent, output, rightIndex);
         }
 
-        private int doApply(int exponent, NumberStringBuilder output, int rightIndex) {
+        private int doApply(int exponent, FormattedStringBuilder output, int rightIndex) {
             // FIXME: Localized exponent separator location.
             int i = rightIndex;
             // Append the exponent separator and sign
@@ -291,7 +291,7 @@ public class ScientificNotation extends Notation implements Cloneable {
         }
 
         @Override
-        public int apply(NumberStringBuilder output, int leftIndex, int rightIndex) {
+        public int apply(FormattedStringBuilder output, int leftIndex, int rightIndex) {
             return handler.doApply(exponent, output, rightIndex);
         }
 
index a8e063b9ecca9aca9d7c00bc66312ad1c169d395..686d8016bc7c2feb187e324dcae2f35b6313ec21 100644 (file)
@@ -16,15 +16,16 @@ import java.util.EnumMap;
 import java.util.Locale;
 
 import com.ibm.icu.impl.CacheBase;
+import com.ibm.icu.impl.FormattedValueStringBuilderImpl;
 import com.ibm.icu.impl.ICUData;
 import com.ibm.icu.impl.ICUResourceBundle;
+import com.ibm.icu.impl.FormattedStringBuilder;
 import com.ibm.icu.impl.SimpleFormatterImpl;
 import com.ibm.icu.impl.SoftCache;
 import com.ibm.icu.impl.StandardPlural;
 import com.ibm.icu.impl.UResource;
 import com.ibm.icu.impl.number.DecimalQuantity;
 import com.ibm.icu.impl.number.DecimalQuantity_DualStorageBCD;
-import com.ibm.icu.impl.number.NumberStringBuilder;
 import com.ibm.icu.impl.number.SimpleModifier;
 import com.ibm.icu.lang.UCharacter;
 import com.ibm.icu.util.Calendar;
@@ -458,9 +459,9 @@ public final class RelativeDateTimeFormatter {
      */
     public static class FormattedRelativeDateTime implements FormattedValue {
 
-        private final NumberStringBuilder string;
+        private final FormattedStringBuilder string;
 
-        private FormattedRelativeDateTime(NumberStringBuilder string) {
+        private FormattedRelativeDateTime(FormattedStringBuilder string) {
             this.string = string;
         }
 
@@ -533,7 +534,7 @@ public final class RelativeDateTimeFormatter {
          */
         @Override
         public boolean nextPosition(ConstrainedFieldPosition cfpos) {
-            return string.nextPosition(cfpos, Field.NUMERIC);
+            return FormattedValueStringBuilderImpl.nextPosition(string, cfpos, Field.NUMERIC);
         }
 
         /**
@@ -544,7 +545,7 @@ public final class RelativeDateTimeFormatter {
          */
         @Override
         public AttributedCharacterIterator toCharacterIterator() {
-            return string.toCharacterIterator(Field.NUMERIC);
+            return FormattedValueStringBuilderImpl.toCharacterIterator(string, Field.NUMERIC);
         }
     }
 
@@ -660,7 +661,7 @@ public final class RelativeDateTimeFormatter {
      * @stable ICU 53
      */
     public String format(double quantity, Direction direction, RelativeUnit unit) {
-        NumberStringBuilder output = formatImpl(quantity, direction, unit);
+        FormattedStringBuilder output = formatImpl(quantity, direction, unit);
         return adjustForContext(output.toString());
     }
 
@@ -688,13 +689,13 @@ public final class RelativeDateTimeFormatter {
     }
 
     /** Implementation method for format and formatToValue with RelativeUnit */
-    private NumberStringBuilder formatImpl(double quantity, Direction direction, RelativeUnit unit) {
+    private FormattedStringBuilder formatImpl(double quantity, Direction direction, RelativeUnit unit) {
         if (direction != Direction.LAST && direction != Direction.NEXT) {
             throw new IllegalArgumentException("direction must be NEXT or LAST");
         }
         int pastFutureIndex = (direction == Direction.NEXT ? 1 : 0);
 
-        NumberStringBuilder output = new NumberStringBuilder();
+        FormattedStringBuilder output = new FormattedStringBuilder();
         String pluralKeyword;
         if (numberFormat instanceof DecimalFormat) {
             DecimalQuantity dq = new DecimalQuantity_DualStorageBCD(quantity);
@@ -731,7 +732,7 @@ public final class RelativeDateTimeFormatter {
      * @stable ICU 57
      */
     public String formatNumeric(double offset, RelativeDateTimeUnit unit) {
-        NumberStringBuilder output = formatNumericImpl(offset, unit);
+        FormattedStringBuilder output = formatNumericImpl(offset, unit);
         return adjustForContext(output.toString());
     }
 
@@ -759,7 +760,7 @@ public final class RelativeDateTimeFormatter {
     }
 
     /** Implementation method for formatNumeric and formatNumericToValue */
-    private NumberStringBuilder formatNumericImpl(double offset, RelativeDateTimeUnit unit) {
+    private FormattedStringBuilder formatNumericImpl(double offset, RelativeDateTimeUnit unit) {
         // TODO:
         // The full implementation of this depends on CLDR data that is not yet available,
         // see: http://unicode.org/cldr/trac/ticket/9165 Add more relative field data.
@@ -834,7 +835,7 @@ public final class RelativeDateTimeFormatter {
         if (string == null) {
             return null;
         }
-        NumberStringBuilder nsb = new NumberStringBuilder();
+        FormattedStringBuilder nsb = new FormattedStringBuilder();
         nsb.append(string, Field.LITERAL);
         return new FormattedRelativeDateTime(nsb);
     }
@@ -903,11 +904,11 @@ public final class RelativeDateTimeFormatter {
     public FormattedRelativeDateTime formatToValue(double offset, RelativeDateTimeUnit unit) {
         checkNoAdjustForContext();
         CharSequence cs = formatRelativeImpl(offset, unit);
-        NumberStringBuilder nsb;
-        if (cs instanceof NumberStringBuilder) {
-            nsb = (NumberStringBuilder) cs;
+        FormattedStringBuilder nsb;
+        if (cs instanceof FormattedStringBuilder) {
+            nsb = (FormattedStringBuilder) cs;
         } else {
-            nsb = new NumberStringBuilder();
+            nsb = new FormattedStringBuilder();
             nsb.append(cs, Field.LITERAL);
         }
         return new FormattedRelativeDateTime(nsb);
similarity index 87%
rename from icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberStringBuilderTest.java
rename to icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/FormattedStringBuilderTest.java
index c85bbfe5199a4996264bfc66914736ab2dd1e2a1..caf21627e5f518fe4f247c7ab7e7b04ea6e70609 100644 (file)
@@ -1,6 +1,6 @@
 // Â© 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package com.ibm.icu.dev.test.number;
+package com.ibm.icu.dev.test.format;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -12,11 +12,12 @@ import java.text.Format.Field;
 
 import org.junit.Test;
 
-import com.ibm.icu.impl.number.NumberStringBuilder;
+import com.ibm.icu.impl.FormattedValueStringBuilderImpl;
+import com.ibm.icu.impl.FormattedStringBuilder;
 import com.ibm.icu.text.NumberFormat;
 
 /** @author sffc */
-public class NumberStringBuilderTest {
+public class FormattedStringBuilderTest {
     private static final String[] EXAMPLE_STRINGS = {
             "",
             "xyz",
@@ -30,9 +31,9 @@ public class NumberStringBuilderTest {
     public void testInsertAppendCharSequence() {
 
         StringBuilder sb1 = new StringBuilder();
-        NumberStringBuilder sb2 = new NumberStringBuilder();
+        FormattedStringBuilder sb2 = new FormattedStringBuilder();
         for (String str : EXAMPLE_STRINGS) {
-            NumberStringBuilder sb3 = new NumberStringBuilder();
+            FormattedStringBuilder sb3 = new FormattedStringBuilder();
             sb1.append(str);
             sb2.append(str, null);
             sb3.append(str, null);
@@ -40,7 +41,7 @@ public class NumberStringBuilderTest {
             assertCharSequenceEquals(sb3, str);
 
             StringBuilder sb4 = new StringBuilder();
-            NumberStringBuilder sb5 = new NumberStringBuilder();
+            FormattedStringBuilder sb5 = new FormattedStringBuilder();
             sb4.append("😇");
             sb4.append(str);
             sb4.append("xx");
@@ -63,7 +64,7 @@ public class NumberStringBuilderTest {
             assertCharSequenceEquals(sb4, sb5);
 
             sb4.append(sb4.toString());
-            sb5.append(new NumberStringBuilder(sb5));
+            sb5.append(new FormattedStringBuilder(sb5));
             assertCharSequenceEquals(sb4, sb5);
         }
     }
@@ -82,7 +83,7 @@ public class NumberStringBuilderTest {
                 { "lorem ipsum dolor sit amet", 8, 18 } }; // 10 chars, larger than several replacements
 
         StringBuilder sb1 = new StringBuilder();
-        NumberStringBuilder sb2 = new NumberStringBuilder();
+        FormattedStringBuilder sb2 = new FormattedStringBuilder();
         for (Object[] cas : cases) {
             String input = (String) cas[0];
             int startThis = (Integer) cas[1];
@@ -117,9 +118,9 @@ public class NumberStringBuilderTest {
         int[] cases = { 0, 1, 60, 127, 128, 0x7fff, 0x8000, 0xffff, 0x10000, 0x1f000, 0x10ffff };
 
         StringBuilder sb1 = new StringBuilder();
-        NumberStringBuilder sb2 = new NumberStringBuilder();
+        FormattedStringBuilder sb2 = new FormattedStringBuilder();
         for (int cas : cases) {
-            NumberStringBuilder sb3 = new NumberStringBuilder();
+            FormattedStringBuilder sb3 = new FormattedStringBuilder();
             sb1.appendCodePoint(cas);
             sb2.appendCodePoint(cas, null);
             sb3.appendCodePoint(cas, null);
@@ -127,7 +128,7 @@ public class NumberStringBuilderTest {
             assertEquals(Character.codePointAt(sb3, 0), cas);
 
             StringBuilder sb4 = new StringBuilder();
-            NumberStringBuilder sb5 = new NumberStringBuilder();
+            FormattedStringBuilder sb5 = new FormattedStringBuilder();
             sb4.append("😇");
             sb4.appendCodePoint(cas); // Java StringBuilder has no insertCodePoint()
             sb4.append("xx");
@@ -140,9 +141,9 @@ public class NumberStringBuilderTest {
     @Test
     public void testCopy() {
         for (String str : EXAMPLE_STRINGS) {
-            NumberStringBuilder sb1 = new NumberStringBuilder();
+            FormattedStringBuilder sb1 = new FormattedStringBuilder();
             sb1.append(str, null);
-            NumberStringBuilder sb2 = new NumberStringBuilder(sb1);
+            FormattedStringBuilder sb2 = new FormattedStringBuilder(sb1);
             assertCharSequenceEquals(sb1, sb2);
             assertTrue(sb1.contentEquals(sb2));
 
@@ -155,7 +156,7 @@ public class NumberStringBuilderTest {
     @Test
     public void testFields() {
         for (String str : EXAMPLE_STRINGS) {
-            NumberStringBuilder sb = new NumberStringBuilder();
+            FormattedStringBuilder sb = new FormattedStringBuilder();
             sb.append(str, null);
             sb.append(str, NumberFormat.Field.CURRENCY);
             Field[] fields = sb.toFieldArray();
@@ -170,7 +171,7 @@ public class NumberStringBuilderTest {
             // Very basic FieldPosition test. More robust tests happen in NumberFormatTest.
             // Let NumberFormatTest also take care of AttributedCharacterIterator material.
             FieldPosition fp = new FieldPosition(NumberFormat.Field.CURRENCY);
-            sb.nextFieldPosition(fp);
+            FormattedValueStringBuilderImpl.nextFieldPosition(sb, fp);
             assertEquals(str.length(), fp.getBeginIndex());
             assertEquals(str.length() * 2, fp.getEndIndex());
 
@@ -181,7 +182,7 @@ public class NumberStringBuilderTest {
                 assertEquals(fields[2], NumberFormat.Field.INTEGER);
             }
 
-            sb.append(new NumberStringBuilder(sb));
+            sb.append(new FormattedStringBuilder(sb));
             sb.append(sb.toCharArray(), sb.toFieldArray());
             int numNull = 0;
             int numCurr = 0;
@@ -204,7 +205,7 @@ public class NumberStringBuilderTest {
             assertEquals(numNull, numCurr);
             assertEquals(str.length() > 0 ? 4 : 0, numInt);
 
-            NumberStringBuilder sb2 = new NumberStringBuilder();
+            FormattedStringBuilder sb2 = new FormattedStringBuilder();
             sb2.append(sb);
             assertTrue(sb.contentEquals(sb2));
             assertTrue(sb.contentEquals(sb2.toCharArray(), sb2.toFieldArray()));
@@ -217,7 +218,7 @@ public class NumberStringBuilderTest {
 
     @Test
     public void testUnlimitedCapacity() {
-        NumberStringBuilder builder = new NumberStringBuilder();
+        FormattedStringBuilder builder = new FormattedStringBuilder();
         // The builder should never fail upon repeated appends.
         for (int i = 0; i < 1000; i++) {
             assertEquals(builder.length(), i);
@@ -228,7 +229,7 @@ public class NumberStringBuilderTest {
 
     @Test
     public void testCodePoints() {
-        NumberStringBuilder nsb = new NumberStringBuilder();
+        FormattedStringBuilder nsb = new FormattedStringBuilder();
         assertEquals("First is -1 on empty string", -1, nsb.getFirstCodePoint());
         assertEquals("Last is -1 on empty string", -1, nsb.getLastCodePoint());
         assertEquals("Length is 0 on empty string", 0, nsb.codePointCount());
@@ -262,8 +263,8 @@ public class NumberStringBuilderTest {
         int end = Math.min(12, a.length());
         if (start != end) {
             assertCharSequenceEquals(a.subSequence(start, end), b.subSequence(start, end));
-            if (b instanceof NumberStringBuilder) {
-                NumberStringBuilder bnsb = (NumberStringBuilder) b;
+            if (b instanceof FormattedStringBuilder) {
+                FormattedStringBuilder bnsb = (FormattedStringBuilder) b;
                 assertCharSequenceEquals(a.subSequence(start, end), bnsb.subString(start, end));
             }
         }
index 5c528c620b485c546eb71c8bbd17b3f61008e423..e778170b167f43830f7f360225c5937196d1fa40 100644 (file)
@@ -7,9 +7,9 @@ import static org.junit.Assert.fail;
 
 import org.junit.Test;
 
+import com.ibm.icu.impl.FormattedStringBuilder;
 import com.ibm.icu.impl.number.AffixUtils;
 import com.ibm.icu.impl.number.AffixUtils.SymbolProvider;
-import com.ibm.icu.impl.number.NumberStringBuilder;
 import com.ibm.icu.text.UnicodeSet;
 
 public class AffixUtilsTest {
@@ -199,7 +199,7 @@ public class AffixUtilsTest {
             }
         };
 
-        NumberStringBuilder sb = new NumberStringBuilder();
+        FormattedStringBuilder sb = new FormattedStringBuilder();
         for (String[] cas : cases) {
             String input = cas[0];
             String expected = cas[1];
@@ -236,7 +236,7 @@ public class AffixUtilsTest {
     }
 
     private static String unescapeWithDefaults(String input) {
-        NumberStringBuilder nsb = new NumberStringBuilder();
+        FormattedStringBuilder nsb = new FormattedStringBuilder();
         int length = AffixUtils.unescape(input, nsb, 0, DEFAULT_SYMBOL_PROVIDER, null);
         assertEquals("Return value of unescape", nsb.length(), length);
         return nsb.toString();
index 9271d94b49ac2ddfd65710abe1da9a20aea9be04..471682a22abbbdd63754821535d2a7307c9bcce8 100644 (file)
@@ -19,10 +19,10 @@ import com.ibm.icu.dev.impl.number.DecimalQuantity_64BitBCD;
 import com.ibm.icu.dev.impl.number.DecimalQuantity_ByteArrayBCD;
 import com.ibm.icu.dev.impl.number.DecimalQuantity_SimpleStorage;
 import com.ibm.icu.dev.test.TestFmwk;
+import com.ibm.icu.impl.FormattedStringBuilder;
 import com.ibm.icu.impl.number.DecimalFormatProperties;
 import com.ibm.icu.impl.number.DecimalQuantity;
 import com.ibm.icu.impl.number.DecimalQuantity_DualStorageBCD;
-import com.ibm.icu.impl.number.NumberStringBuilder;
 import com.ibm.icu.impl.number.RoundingUtils;
 import com.ibm.icu.number.LocalizedNumberFormatter;
 import com.ibm.icu.number.NumberFormatter;
@@ -236,8 +236,8 @@ public class DecimalQuantityTest extends TestFmwk {
         for (LocalizedNumberFormatter format : formats) {
             DecimalQuantity q0 = rq0.createCopy();
             DecimalQuantity q1 = rq1.createCopy();
-            NumberStringBuilder nsb1 = new NumberStringBuilder();
-            NumberStringBuilder nsb2 = new NumberStringBuilder();
+            FormattedStringBuilder nsb1 = new FormattedStringBuilder();
+            FormattedStringBuilder nsb2 = new FormattedStringBuilder();
             format.formatImpl(q0, nsb1);
             format.formatImpl(q1, nsb2);
             String s1 = nsb1.toString();
index fee90dae83fe6134c772113f641cba5118be812f..2d4d33cb33951f832c9f32246ee8d56049c01d97 100644 (file)
@@ -7,12 +7,12 @@ import static org.junit.Assert.assertTrue;
 
 import org.junit.Test;
 
+import com.ibm.icu.impl.FormattedStringBuilder;
 import com.ibm.icu.impl.SimpleFormatterImpl;
 import com.ibm.icu.impl.number.ConstantAffixModifier;
 import com.ibm.icu.impl.number.ConstantMultiFieldModifier;
 import com.ibm.icu.impl.number.CurrencySpacingEnabledModifier;
 import com.ibm.icu.impl.number.Modifier;
-import com.ibm.icu.impl.number.NumberStringBuilder;
 import com.ibm.icu.impl.number.SimpleModifier;
 import com.ibm.icu.text.DecimalFormatSymbols;
 import com.ibm.icu.text.NumberFormat;
@@ -29,8 +29,8 @@ public class ModifierTest {
 
     @Test
     public void testConstantMultiFieldModifier() {
-        NumberStringBuilder prefix = new NumberStringBuilder();
-        NumberStringBuilder suffix = new NumberStringBuilder();
+        FormattedStringBuilder prefix = new FormattedStringBuilder();
+        FormattedStringBuilder suffix = new FormattedStringBuilder();
         Modifier mod1 = new ConstantMultiFieldModifier(prefix, suffix, false, true);
         assertModifierEquals(mod1, 0, true, "|", "n");
 
@@ -76,7 +76,7 @@ public class ModifierTest {
 
             // Test strange insertion positions
             for (int j = 0; j < outputs.length; j++) {
-                NumberStringBuilder output = new NumberStringBuilder();
+                FormattedStringBuilder output = new FormattedStringBuilder();
                 output.append((String) outputs[j][0], null);
                 mod.apply(output, (Integer) outputs[j][1], (Integer) outputs[j][2]);
                 String expected = expecteds[j][i];
@@ -89,8 +89,8 @@ public class ModifierTest {
     @Test
     public void testCurrencySpacingEnabledModifier() {
         DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(ULocale.ENGLISH);
-        NumberStringBuilder prefix = new NumberStringBuilder();
-        NumberStringBuilder suffix = new NumberStringBuilder();
+        FormattedStringBuilder prefix = new FormattedStringBuilder();
+        FormattedStringBuilder suffix = new FormattedStringBuilder();
         Modifier mod1 = new CurrencySpacingEnabledModifier(prefix, suffix, false, true, symbols);
         assertModifierEquals(mod1, 0, true, "|", "n");
 
@@ -99,13 +99,13 @@ public class ModifierTest {
         assertModifierEquals(mod2, 3, true, "USD|", "$$$n");
 
         // Test the default currency spacing rules
-        NumberStringBuilder sb = new NumberStringBuilder();
+        FormattedStringBuilder sb = new FormattedStringBuilder();
         sb.append("123", NumberFormat.Field.INTEGER);
-        NumberStringBuilder sb1 = new NumberStringBuilder(sb);
+        FormattedStringBuilder sb1 = new FormattedStringBuilder(sb);
         assertModifierEquals(mod2, sb1, 3, true, "USD\u00A0123", "$$$niii");
 
         // Compare with the unsafe code path
-        NumberStringBuilder sb2 = new NumberStringBuilder(sb);
+        FormattedStringBuilder sb2 = new FormattedStringBuilder(sb);
         sb2.insert(0, "USD", NumberFormat.Field.CURRENCY);
         CurrencySpacingEnabledModifier.applyCurrencySpacing(sb2, 0, 3, 6, 0, symbols);
         assertTrue(sb1.toDebugString() + " vs " + sb2.toDebugString(), sb1.contentEquals(sb2));
@@ -147,7 +147,7 @@ public class ModifierTest {
             boolean expectedStrong,
             String expectedChars,
             String expectedFields) {
-        NumberStringBuilder sb = new NumberStringBuilder();
+        FormattedStringBuilder sb = new FormattedStringBuilder();
         sb.appendCodePoint('|', null);
         assertModifierEquals(mod,
                 sb,
@@ -159,7 +159,7 @@ public class ModifierTest {
 
     private void assertModifierEquals(
             Modifier mod,
-            NumberStringBuilder sb,
+            FormattedStringBuilder sb,
             int expectedPrefixLength,
             boolean expectedStrong,
             String expectedChars,
@@ -173,7 +173,7 @@ public class ModifierTest {
                     sb.codePointCount() - oldCount,
                     mod.getCodePointCount());
         }
-        assertEquals("<NumberStringBuilder [" + expectedChars + "] [" + expectedFields + "]>",
+        assertEquals("<FormattedStringBuilder [" + expectedChars + "] [" + expectedFields + "]>",
                 sb.toDebugString());
     }
 }
index 5f2c13c6e0771188ea7fbc95c358a276ffc22d1c..9f8585be3fae1e1d6c74954931d78f502c74d270 100644 (file)
@@ -8,11 +8,11 @@ import static org.junit.Assert.assertTrue;
 
 import org.junit.Test;
 
+import com.ibm.icu.impl.FormattedStringBuilder;
 import com.ibm.icu.impl.number.DecimalQuantity;
 import com.ibm.icu.impl.number.DecimalQuantity_DualStorageBCD;
 import com.ibm.icu.impl.number.MicroProps;
 import com.ibm.icu.impl.number.MutablePatternModifier;
-import com.ibm.icu.impl.number.NumberStringBuilder;
 import com.ibm.icu.impl.number.PatternStringParser;
 import com.ibm.icu.number.NumberFormatter.SignDisplay;
 import com.ibm.icu.number.NumberFormatter.UnitWidth;
@@ -81,18 +81,18 @@ public class MutablePatternModifierTest {
         mod.setSymbols(DecimalFormatSymbols.getInstance(ULocale.ENGLISH), null, UnitWidth.SHORT, null);
         DecimalQuantity fq = new DecimalQuantity_DualStorageBCD(1);
 
-        NumberStringBuilder nsb1 = new NumberStringBuilder();
+        FormattedStringBuilder nsb1 = new FormattedStringBuilder();
         MicroProps micros1 = new MicroProps(false);
         mod.addToChain(micros1);
         mod.processQuantity(fq);
         micros1.modMiddle.apply(nsb1, 0, 0);
 
-        NumberStringBuilder nsb2 = new NumberStringBuilder();
+        FormattedStringBuilder nsb2 = new FormattedStringBuilder();
         MicroProps micros2 = new MicroProps(true);
         mod.createImmutable().applyToMicros(micros2, fq);
         micros2.modMiddle.apply(nsb2, 0, 0);
 
-        NumberStringBuilder nsb3 = new NumberStringBuilder();
+        FormattedStringBuilder nsb3 = new FormattedStringBuilder();
         MicroProps micros3 = new MicroProps(false);
         mod.addToChain(micros3);
         mod.setPatternAttributes(SignDisplay.ALWAYS, false);
@@ -115,7 +115,7 @@ public class MutablePatternModifierTest {
         mod.setNumberProperties(1, null);
 
         // Unsafe Code Path
-        NumberStringBuilder nsb = new NumberStringBuilder();
+        FormattedStringBuilder nsb = new FormattedStringBuilder();
         nsb.append("x123y", null);
         mod.apply(nsb, 1, 4);
         assertEquals("Unsafe Path", "xabcy", nsb.toString());
@@ -130,13 +130,13 @@ public class MutablePatternModifierTest {
     }
 
     private static String getPrefix(MutablePatternModifier mod) {
-        NumberStringBuilder nsb = new NumberStringBuilder();
+        FormattedStringBuilder nsb = new FormattedStringBuilder();
         mod.apply(nsb, 0, 0);
         return nsb.subSequence(0, mod.getPrefixLength()).toString();
     }
 
     private static String getSuffix(MutablePatternModifier mod) {
-        NumberStringBuilder nsb = new NumberStringBuilder();
+        FormattedStringBuilder nsb = new FormattedStringBuilder();
         mod.apply(nsb, 0, 0);
         return nsb.subSequence(mod.getPrefixLength(), nsb.length()).toString();
     }