ICU-20429 Renaming [Number->Formatted]StringBuilder and refactoring.
- 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
diff --git a/icu4c/source/i18n/Makefile.in b/icu4c/source/i18n/Makefile.in
index 2d00187..7487d30 100644
--- a/icu4c/source/i18n/Makefile.in
+++ b/icu4c/source/i18n/Makefile.in
@@ -103,16 +103,17 @@
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
diff --git a/icu4c/source/i18n/formatted_string_builder.cpp b/icu4c/source/i18n/formatted_string_builder.cpp
new file mode 100644
index 0000000..4ffc4c7
--- /dev/null
+++ b/icu4c/source/i18n/formatted_string_builder.cpp
@@ -0,0 +1,447 @@
+// © 2017 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "formatted_string_builder.h"
+#include "unicode/ustring.h"
+#include "unicode/utf16.h"
+
+namespace {
+
+// A version of uprv_memcpy that checks for length 0.
+// By default, uprv_memcpy requires a length of at least 1.
+inline void uprv_memcpy2(void* dest, const void* src, size_t len) {
+ if (len > 0) {
+ uprv_memcpy(dest, src, len);
+ }
+}
+
+// A version of uprv_memmove that checks for length 0.
+// By default, uprv_memmove requires a length of at least 1.
+inline void uprv_memmove2(void* dest, const void* src, size_t len) {
+ if (len > 0) {
+ uprv_memmove(dest, src, len);
+ }
+}
+
+} // namespace
+
+
+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.
+ for (int32_t i=0; i<getCapacity(); i++) {
+ getCharPtr()[i] = 1;
+ }
+#endif
+}
+
+FormattedStringBuilder::~FormattedStringBuilder() {
+ if (fUsingHeap) {
+ uprv_free(fChars.heap.ptr);
+ uprv_free(fFields.heap.ptr);
+ }
+}
+
+FormattedStringBuilder::FormattedStringBuilder(const FormattedStringBuilder &other) {
+ *this = other;
+}
+
+FormattedStringBuilder &FormattedStringBuilder::operator=(const FormattedStringBuilder &other) {
+ // Check for self-assignment
+ if (this == &other) {
+ return *this;
+ }
+
+ // Continue with deallocation and copying
+ if (fUsingHeap) {
+ uprv_free(fChars.heap.ptr);
+ uprv_free(fFields.heap.ptr);
+ fUsingHeap = false;
+ }
+
+ int32_t capacity = other.getCapacity();
+ if (capacity > DEFAULT_CAPACITY) {
+ // FIXME: uprv_malloc
+ // C++ note: malloc appears in two places: here and in prepareForInsertHelper.
+ auto newChars = static_cast<char16_t *> (uprv_malloc(sizeof(char16_t) * capacity));
+ auto newFields = static_cast<Field *>(uprv_malloc(sizeof(Field) * capacity));
+ if (newChars == nullptr || newFields == nullptr) {
+ // UErrorCode is not available; fail silently.
+ uprv_free(newChars);
+ uprv_free(newFields);
+ *this = FormattedStringBuilder(); // can't fail
+ return *this;
+ }
+
+ fUsingHeap = true;
+ fChars.heap.capacity = capacity;
+ fChars.heap.ptr = newChars;
+ fFields.heap.capacity = capacity;
+ fFields.heap.ptr = newFields;
+ }
+
+ uprv_memcpy2(getCharPtr(), other.getCharPtr(), sizeof(char16_t) * capacity);
+ uprv_memcpy2(getFieldPtr(), other.getFieldPtr(), sizeof(Field) * capacity);
+
+ fZero = other.fZero;
+ fLength = other.fLength;
+ return *this;
+}
+
+int32_t FormattedStringBuilder::length() const {
+ return fLength;
+}
+
+int32_t FormattedStringBuilder::codePointCount() const {
+ return u_countChar32(getCharPtr() + fZero, fLength);
+}
+
+UChar32 FormattedStringBuilder::getFirstCodePoint() const {
+ if (fLength == 0) {
+ return -1;
+ }
+ UChar32 cp;
+ U16_GET(getCharPtr() + fZero, 0, 0, fLength, cp);
+ return cp;
+}
+
+UChar32 FormattedStringBuilder::getLastCodePoint() const {
+ if (fLength == 0) {
+ return -1;
+ }
+ int32_t offset = fLength;
+ U16_BACK_1(getCharPtr() + fZero, 0, offset);
+ UChar32 cp;
+ U16_GET(getCharPtr() + fZero, 0, offset, fLength, cp);
+ return cp;
+}
+
+UChar32 FormattedStringBuilder::codePointAt(int32_t index) const {
+ UChar32 cp;
+ U16_GET(getCharPtr() + fZero, 0, index, fLength, cp);
+ return cp;
+}
+
+UChar32 FormattedStringBuilder::codePointBefore(int32_t index) const {
+ int32_t offset = index;
+ U16_BACK_1(getCharPtr() + fZero, 0, offset);
+ UChar32 cp;
+ U16_GET(getCharPtr() + fZero, 0, offset, fLength, cp);
+ return cp;
+}
+
+FormattedStringBuilder &FormattedStringBuilder::clear() {
+ // TODO: Reset the heap here?
+ fZero = getCapacity() / 2;
+ fLength = 0;
+ return *this;
+}
+
+int32_t FormattedStringBuilder::appendCodePoint(UChar32 codePoint, Field field, UErrorCode &status) {
+ return insertCodePoint(fLength, codePoint, field, status);
+}
+
+int32_t
+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)) {
+ return count;
+ }
+ if (count == 1) {
+ getCharPtr()[position] = (char16_t) codePoint;
+ getFieldPtr()[position] = field;
+ } else {
+ getCharPtr()[position] = U16_LEAD(codePoint);
+ getCharPtr()[position + 1] = U16_TRAIL(codePoint);
+ getFieldPtr()[position] = getFieldPtr()[position + 1] = field;
+ }
+ return count;
+}
+
+int32_t FormattedStringBuilder::append(const UnicodeString &unistr, Field field, UErrorCode &status) {
+ return insert(fLength, unistr, field, status);
+}
+
+int32_t FormattedStringBuilder::insert(int32_t index, const UnicodeString &unistr, Field field,
+ UErrorCode &status) {
+ if (unistr.length() == 0) {
+ // Nothing to insert.
+ return 0;
+ } else if (unistr.length() == 1) {
+ // Fast path: insert using insertCodePoint.
+ return insertCodePoint(index, unistr.charAt(0), field, status);
+ } else {
+ return insert(index, unistr, 0, unistr.length(), field, status);
+ }
+}
+
+int32_t
+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);
+ if (U_FAILURE(status)) {
+ return count;
+ }
+ for (int32_t i = 0; i < count; i++) {
+ getCharPtr()[position + i] = unistr.charAt(start + i);
+ getFieldPtr()[position + i] = field;
+ }
+ return count;
+}
+
+int32_t
+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;
+ int32_t count = otherLength - thisLength;
+ int32_t position;
+ if (count > 0) {
+ // Overall, chars need to be added.
+ position = prepareForInsert(startThis, count, status);
+ } else {
+ // Overall, chars need to be removed or kept the same.
+ position = remove(startThis, -count);
+ }
+ if (U_FAILURE(status)) {
+ return count;
+ }
+ for (int32_t i = 0; i < otherLength; i++) {
+ getCharPtr()[position + i] = unistr.charAt(startOther + i);
+ getFieldPtr()[position + i] = field;
+ }
+ return count;
+}
+
+int32_t FormattedStringBuilder::append(const FormattedStringBuilder &other, UErrorCode &status) {
+ return insert(fLength, other, status);
+}
+
+int32_t
+FormattedStringBuilder::insert(int32_t index, const FormattedStringBuilder &other, UErrorCode &status) {
+ if (this == &other) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ int32_t count = other.fLength;
+ if (count == 0) {
+ // Nothing to insert.
+ return 0;
+ }
+ int32_t position = prepareForInsert(index, count, status);
+ if (U_FAILURE(status)) {
+ return count;
+ }
+ for (int32_t i = 0; i < count; i++) {
+ getCharPtr()[position + i] = other.charAt(i);
+ getFieldPtr()[position + i] = other.fieldAt(i);
+ }
+ return count;
+}
+
+void FormattedStringBuilder::writeTerminator(UErrorCode& status) {
+ int32_t position = prepareForInsert(fLength, 1, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ getCharPtr()[position] = 0;
+ getFieldPtr()[position] = UNUM_FIELD_COUNT;
+ fLength--;
+}
+
+int32_t FormattedStringBuilder::prepareForInsert(int32_t index, int32_t count, UErrorCode &status) {
+ U_ASSERT(index >= 0);
+ U_ASSERT(index <= fLength);
+ U_ASSERT(count >= 0);
+ if (index == 0 && fZero - count >= 0) {
+ // Append to start
+ fZero -= count;
+ fLength += count;
+ return fZero;
+ } else if (index == fLength && fZero + fLength + count < getCapacity()) {
+ // Append to end
+ fLength += count;
+ return fZero + fLength - count;
+ } else {
+ // Move chars around and/or allocate more space
+ return prepareForInsertHelper(index, count, 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();
+ Field *oldFields = getFieldPtr();
+ if (fLength + count > oldCapacity) {
+ int32_t newCapacity = (fLength + count) * 2;
+ int32_t newZero = newCapacity / 2 - (fLength + count) / 2;
+
+ // C++ note: malloc appears in two places: here and in the assignment operator.
+ auto newChars = static_cast<char16_t *> (uprv_malloc(sizeof(char16_t) * newCapacity));
+ auto newFields = static_cast<Field *>(uprv_malloc(sizeof(Field) * newCapacity));
+ if (newChars == nullptr || newFields == nullptr) {
+ uprv_free(newChars);
+ uprv_free(newFields);
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return -1;
+ }
+
+ // First copy the prefix and then the suffix, leaving room for the new chars that the
+ // caller wants to insert.
+ // C++ note: memcpy is OK because the src and dest do not overlap.
+ uprv_memcpy2(newChars + newZero, oldChars + oldZero, sizeof(char16_t) * index);
+ uprv_memcpy2(newChars + newZero + index + count,
+ oldChars + oldZero + index,
+ sizeof(char16_t) * (fLength - index));
+ uprv_memcpy2(newFields + newZero, oldFields + oldZero, sizeof(Field) * index);
+ uprv_memcpy2(newFields + newZero + index + count,
+ oldFields + oldZero + index,
+ sizeof(Field) * (fLength - index));
+
+ if (fUsingHeap) {
+ uprv_free(oldChars);
+ uprv_free(oldFields);
+ }
+ fUsingHeap = true;
+ fChars.heap.ptr = newChars;
+ fChars.heap.capacity = newCapacity;
+ fFields.heap.ptr = newFields;
+ fFields.heap.capacity = newCapacity;
+ fZero = newZero;
+ fLength += count;
+ } else {
+ int32_t newZero = oldCapacity / 2 - (fLength + count) / 2;
+
+ // C++ note: memmove is required because src and dest may overlap.
+ // First copy the entire string to the location of the prefix, and then move the suffix
+ // to make room for the new chars that the caller wants to insert.
+ uprv_memmove2(oldChars + newZero, oldChars + oldZero, sizeof(char16_t) * fLength);
+ uprv_memmove2(oldChars + newZero + index + count,
+ oldChars + newZero + index,
+ sizeof(char16_t) * (fLength - index));
+ uprv_memmove2(oldFields + newZero, oldFields + oldZero, sizeof(Field) * fLength);
+ uprv_memmove2(oldFields + newZero + index + count,
+ oldFields + newZero + index,
+ sizeof(Field) * (fLength - index));
+
+ fZero = newZero;
+ fLength += count;
+ }
+ return fZero + index;
+}
+
+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,
+ getCharPtr() + position + count,
+ sizeof(char16_t) * (fLength - index - count));
+ uprv_memmove2(getFieldPtr() + position,
+ getFieldPtr() + position + count,
+ sizeof(Field) * (fLength - index - count));
+ fLength -= count;
+ return position;
+}
+
+UnicodeString FormattedStringBuilder::toUnicodeString() const {
+ return UnicodeString(getCharPtr() + fZero, fLength);
+}
+
+const UnicodeString FormattedStringBuilder::toTempUnicodeString() const {
+ // Readonly-alias constructor:
+ return UnicodeString(FALSE, getCharPtr() + fZero, fLength);
+}
+
+UnicodeString FormattedStringBuilder::toDebugString() const {
+ UnicodeString sb;
+ sb.append(u"<FormattedStringBuilder [", -1);
+ sb.append(toUnicodeString());
+ sb.append(u"] [", -1);
+ for (int i = 0; i < fLength; i++) {
+ if (fieldAt(i) == UNUM_FIELD_COUNT) {
+ sb.append(u'n');
+ } else {
+ char16_t c;
+ switch (fieldAt(i)) {
+ case UNUM_SIGN_FIELD:
+ c = u'-';
+ break;
+ case UNUM_INTEGER_FIELD:
+ c = u'i';
+ break;
+ case UNUM_FRACTION_FIELD:
+ c = u'f';
+ break;
+ case UNUM_EXPONENT_FIELD:
+ c = u'e';
+ break;
+ case UNUM_EXPONENT_SIGN_FIELD:
+ c = u'+';
+ break;
+ case UNUM_EXPONENT_SYMBOL_FIELD:
+ c = u'E';
+ break;
+ case UNUM_DECIMAL_SEPARATOR_FIELD:
+ c = u'.';
+ break;
+ case UNUM_GROUPING_SEPARATOR_FIELD:
+ c = u',';
+ break;
+ case UNUM_PERCENT_FIELD:
+ c = u'%';
+ break;
+ case UNUM_PERMILL_FIELD:
+ c = u'‰';
+ break;
+ case UNUM_CURRENCY_FIELD:
+ c = u'$';
+ break;
+ default:
+ c = u'?';
+ break;
+ }
+ sb.append(c);
+ }
+ }
+ sb.append(u"]>", -1);
+ return sb;
+}
+
+const char16_t *FormattedStringBuilder::chars() const {
+ return getCharPtr() + fZero;
+}
+
+bool FormattedStringBuilder::contentEquals(const FormattedStringBuilder &other) const {
+ if (fLength != other.fLength) {
+ return false;
+ }
+ for (int32_t i = 0; i < fLength; i++) {
+ if (charAt(i) != other.charAt(i) || fieldAt(i) != other.fieldAt(i)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool FormattedStringBuilder::containsField(Field field) const {
+ for (int32_t i = 0; i < fLength; i++) {
+ if (field == fieldAt(i)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/icu4c/source/i18n/formatted_string_builder.h b/icu4c/source/i18n/formatted_string_builder.h
new file mode 100644
index 0000000..cc13b66
--- /dev/null
+++ b/icu4c/source/i18n/formatted_string_builder.h
@@ -0,0 +1,209 @@
+// © 2017 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 __NUMBER_STRINGBUILDER_H__
+#define __NUMBER_STRINGBUILDER_H__
+
+
+#include <cstdint>
+#include "unicode/unum.h" // for UNUM_FIELD_COUNT
+#include "cstring.h"
+#include "uassert.h"
+#include "fphdlimp.h"
+
+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;
+
+ template<typename T>
+ union ValueOrHeapArray {
+ T value[DEFAULT_CAPACITY];
+ struct {
+ T *ptr;
+ int32_t capacity;
+ } heap;
+ };
+
+ public:
+ FormattedStringBuilder();
+
+ ~FormattedStringBuilder();
+
+ FormattedStringBuilder(const FormattedStringBuilder &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;
+
+ FormattedStringBuilder &operator=(const FormattedStringBuilder &other);
+
+ int32_t length() const;
+
+ int32_t codePointCount() const;
+
+ inline char16_t charAt(int32_t index) const {
+ U_ASSERT(index >= 0);
+ U_ASSERT(index < fLength);
+ return getCharPtr()[fZero + index];
+ }
+
+ inline Field fieldAt(int32_t index) const {
+ U_ASSERT(index >= 0);
+ U_ASSERT(index < fLength);
+ return getFieldPtr()[fZero + index];
+ }
+
+ UChar32 getFirstCodePoint() const;
+
+ UChar32 getLastCodePoint() const;
+
+ UChar32 codePointAt(int32_t index) const;
+
+ UChar32 codePointBefore(int32_t index) const;
+
+ FormattedStringBuilder &clear();
+
+ int32_t appendCodePoint(UChar32 codePoint, Field field, UErrorCode &status);
+
+ int32_t insertCodePoint(int32_t index, UChar32 codePoint, Field field, UErrorCode &status);
+
+ int32_t append(const UnicodeString &unistr, Field field, UErrorCode &status);
+
+ int32_t insert(int32_t index, const UnicodeString &unistr, Field field, UErrorCode &status);
+
+ int32_t insert(int32_t index, const UnicodeString &unistr, int32_t start, int32_t end, Field field,
+ UErrorCode &status);
+
+ 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 FormattedStringBuilder &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 FormattedStringBuilder is destructed.
+ * */
+ UnicodeString toUnicodeString() const;
+
+ /**
+ * 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;
+
+ UnicodeString toDebugString() const;
+
+ const char16_t *chars() const;
+
+ bool contentEquals(const FormattedStringBuilder &other) const;
+
+ bool containsField(Field field) const;
+
+ private:
+ bool fUsingHeap = false;
+ ValueOrHeapArray<char16_t> fChars;
+ ValueOrHeapArray<Field> fFields;
+ int32_t fZero = DEFAULT_CAPACITY / 2;
+ int32_t fLength = 0;
+
+ inline char16_t *getCharPtr() {
+ return fUsingHeap ? fChars.heap.ptr : fChars.value;
+ }
+
+ inline const char16_t *getCharPtr() const {
+ return fUsingHeap ? fChars.heap.ptr : fChars.value;
+ }
+
+ inline Field *getFieldPtr() {
+ return fUsingHeap ? fFields.heap.ptr : fFields.value;
+ }
+
+ inline const Field *getFieldPtr() const {
+ return fUsingHeap ? fFields.heap.ptr : fFields.value;
+ }
+
+ inline int32_t getCapacity() const {
+ return fUsingHeap ? fChars.heap.capacity : DEFAULT_CAPACITY;
+ }
+
+ int32_t prepareForInsert(int32_t index, int32_t count, UErrorCode &status);
+
+ int32_t prepareForInsertHelper(int32_t index, int32_t count, UErrorCode &status);
+
+ int32_t remove(int32_t index, int32_t count);
+
+ friend class FormattedValueStringBuilderImpl;
+};
+
+/**
+ * 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;
+ };
+
+ /** 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);
+ }
+
+ /** 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;
+ }
+};
+
+U_NAMESPACE_END
+
+
+#endif //__NUMBER_STRINGBUILDER_H__
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/icu4c/source/i18n/formattedval_impl.h b/icu4c/source/i18n/formattedval_impl.h
index ee15ed9..9aab36a 100644
--- a/icu4c/source/i18n/formattedval_impl.h
+++ b/icu4c/source/i18n/formattedval_impl.h
@@ -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 @@ class FormattedValueFieldPositionIteratorImpl : public UMemory, public Formatted
};
-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 @@ class FormattedValueNumberStringBuilderImpl : public UMemory, public FormattedVa
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;
};
diff --git a/icu4c/source/i18n/formattedval_sbimpl.cpp b/icu4c/source/i18n/formattedval_sbimpl.cpp
index 1fbecf2..ca28f22 100644
--- a/icu4c/source/i18n/formattedval_sbimpl.cpp
+++ b/icu4c/source/i18n/formattedval_sbimpl.cpp
@@ -9,35 +9,203 @@
// 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);
}
diff --git a/icu4c/source/i18n/i18n.vcxproj b/icu4c/source/i18n/i18n.vcxproj
index d2264c1..49ddc79 100644
--- a/icu4c/source/i18n/i18n.vcxproj
+++ b/icu4c/source/i18n/i18n.vcxproj
@@ -278,14 +278,14 @@
<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" />
@@ -541,7 +541,7 @@
<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" />
@@ -549,7 +549,7 @@
<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" />
diff --git a/icu4c/source/i18n/i18n.vcxproj.filters b/icu4c/source/i18n/i18n.vcxproj.filters
index 5cf3799..cb393c6 100644
--- a/icu4c/source/i18n/i18n.vcxproj.filters
+++ b/icu4c/source/i18n/i18n.vcxproj.filters
@@ -585,7 +585,7 @@
<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">
@@ -606,7 +606,7 @@
<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">
@@ -878,7 +878,7 @@
<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">
@@ -902,7 +902,7 @@
<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">
diff --git a/icu4c/source/i18n/i18n_uwp.vcxproj b/icu4c/source/i18n/i18n_uwp.vcxproj
index 4a62c19..7580e2a 100644
--- a/icu4c/source/i18n/i18n_uwp.vcxproj
+++ b/icu4c/source/i18n/i18n_uwp.vcxproj
@@ -385,14 +385,14 @@
<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" />
@@ -646,7 +646,7 @@
<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" />
@@ -654,7 +654,7 @@
<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" />
diff --git a/icu4c/source/i18n/number_affixutils.cpp b/icu4c/source/i18n/number_affixutils.cpp
index 3eb9c59..3b1b42f 100644
--- a/icu4c/source/i18n/number_affixutils.cpp
+++ b/icu4c/source/i18n/number_affixutils.cpp
@@ -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;
diff --git a/icu4c/source/i18n/number_affixutils.h b/icu4c/source/i18n/number_affixutils.h
index f011a54..5cfde61 100644
--- a/icu4c/source/i18n/number_affixutils.h
+++ b/icu4c/source/i18n/number_affixutils.h
@@ -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);
diff --git a/icu4c/source/i18n/number_asformat.cpp b/icu4c/source/i18n/number_asformat.cpp
index 9d3ea69..974dfba 100644
--- a/icu4c/source/i18n/number_asformat.cpp
+++ b/icu4c/source/i18n/number_asformat.cpp
@@ -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;
}
diff --git a/icu4c/source/i18n/number_fluent.cpp b/icu4c/source/i18n/number_fluent.cpp
index 09e0905..bd49a12 100644
--- a/icu4c/source/i18n/number_fluent.cpp
+++ b/icu4c/source/i18n/number_fluent.cpp
@@ -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;
diff --git a/icu4c/source/i18n/number_formatimpl.cpp b/icu4c/source/i18n/number_formatimpl.cpp
index 08b833b..8741af3 100644
--- a/icu4c/source/i18n/number_formatimpl.cpp
+++ b/icu4c/source/i18n/number_formatimpl.cpp
@@ -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();
diff --git a/icu4c/source/i18n/number_formatimpl.h b/icu4c/source/i18n/number_formatimpl.h
index fd8708c..44753c0 100644
--- a/icu4c/source/i18n/number_formatimpl.h
+++ b/icu4c/source/i18n/number_formatimpl.h
@@ -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 ¯os, DecimalQuantity &inValue, NumberStringBuilder &outString,
+ formatStatic(const MacroProps ¯os, 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 ¯os, bool safe, UErrorCode &status);
static int32_t
- writeIntegerDigits(const MicroProps µs, DecimalQuantity &quantity, NumberStringBuilder &string,
+ writeIntegerDigits(const MicroProps µs, DecimalQuantity &quantity, FormattedStringBuilder &string,
int32_t index, UErrorCode &status);
static int32_t
- writeFractionDigits(const MicroProps µs, DecimalQuantity &quantity, NumberStringBuilder &string,
+ writeFractionDigits(const MicroProps µs, DecimalQuantity &quantity, FormattedStringBuilder &string,
int32_t index, UErrorCode &status);
};
diff --git a/icu4c/source/i18n/number_modifiers.cpp b/icu4c/source/i18n/number_modifiers.cpp
index 1fcbe7b..aa6cf57 100644
--- a/icu4c/source/i18n/number_modifiers.cpp
+++ b/icu4c/source/i18n/number_modifiers.cpp
@@ -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) {
diff --git a/icu4c/source/i18n/number_modifiers.h b/icu4c/source/i18n/number_modifiers.h
index 495128b..5c13c87 100644
--- a/icu4c/source/i18n/number_modifiers.h
+++ b/icu4c/source/i18n/number_modifiers.h
@@ -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;
diff --git a/icu4c/source/i18n/number_output.cpp b/icu4c/source/i18n/number_output.cpp
index 1e86f2f..888a9f2 100644
--- a/icu4c/source/i18n/number_output.cpp
+++ b/icu4c/source/i18n/number_output.cpp
@@ -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 {
diff --git a/icu4c/source/i18n/number_padding.cpp b/icu4c/source/i18n/number_padding.cpp
index 31684d7..c68a987 100644
--- a/icu4c/source/i18n/number_padding.cpp
+++ b/icu4c/source/i18n/number_padding.cpp
@@ -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();
diff --git a/icu4c/source/i18n/number_patternmodifier.cpp b/icu4c/source/i18n/number_patternmodifier.cpp
index 75de439..8f3af2a 100644
--- a/icu4c/source/i18n/number_patternmodifier.cpp
+++ b/icu4c/source/i18n/number_patternmodifier.cpp
@@ -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;
diff --git a/icu4c/source/i18n/number_patternmodifier.h b/icu4c/source/i18n/number_patternmodifier.h
index 27e293b..59ea02f 100644
--- a/icu4c/source/i18n/number_patternmodifier.h
+++ b/icu4c/source/i18n/number_patternmodifier.h
@@ -184,7 +184,7 @@ class U_I18N_API MutablePatternModifier
void processQuantity(DecimalQuantity &, MicroProps µs, 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);
};
diff --git a/icu4c/source/i18n/number_scientific.cpp b/icu4c/source/i18n/number_scientific.cpp
index 7fab29c..6fb4c19 100644
--- a/icu4c/source/i18n/number_scientific.cpp
+++ b/icu4c/source/i18n/number_scientific.cpp
@@ -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;
diff --git a/icu4c/source/i18n/number_scientific.h b/icu4c/source/i18n/number_scientific.h
index e377bd9..1c9ce1e 100644
--- a/icu4c/source/i18n/number_scientific.h
+++ b/icu4c/source/i18n/number_scientific.h
@@ -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;
diff --git a/icu4c/source/i18n/number_skeletons.cpp b/icu4c/source/i18n/number_skeletons.cpp
index 7e06cab..c65a393 100644
--- a/icu4c/source/i18n/number_skeletons.cpp
+++ b/icu4c/source/i18n/number_skeletons.cpp
@@ -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;
diff --git a/icu4c/source/i18n/number_skeletons.h b/icu4c/source/i18n/number_skeletons.h
index bc228bd..59af771 100644
--- a/icu4c/source/i18n/number_skeletons.h
+++ b/icu4c/source/i18n/number_skeletons.h
@@ -10,10 +10,10 @@
#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
diff --git a/icu4c/source/i18n/number_stringbuilder.cpp b/icu4c/source/i18n/number_stringbuilder.cpp
deleted file mode 100644
index 03300b3..0000000
--- a/icu4c/source/i18n/number_stringbuilder.cpp
+++ /dev/null
@@ -1,599 +0,0 @@
-// © 2017 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html
-
-#include "unicode/utypes.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "number_stringbuilder.h"
-#include "static_unicode_sets.h"
-#include "unicode/utf16.h"
-#include "number_utils.h"
-
-using namespace icu;
-using namespace icu::number;
-using namespace icu::number::impl;
-
-namespace {
-
-// A version of uprv_memcpy that checks for length 0.
-// By default, uprv_memcpy requires a length of at least 1.
-inline void uprv_memcpy2(void* dest, const void* src, size_t len) {
- if (len > 0) {
- uprv_memcpy(dest, src, len);
- }
-}
-
-// A version of uprv_memmove that checks for length 0.
-// By default, uprv_memmove requires a length of at least 1.
-inline void uprv_memmove2(void* dest, const void* src, size_t len) {
- if (len > 0) {
- uprv_memmove(dest, src, len);
- }
-}
-
-} // namespace
-
-NumberStringBuilder::NumberStringBuilder() {
-#if U_DEBUG
- // Initializing the memory to non-zero helps catch some bugs that involve
- // reading from an improperly terminated string.
- for (int32_t i=0; i<getCapacity(); i++) {
- getCharPtr()[i] = 1;
- }
-#endif
-}
-
-NumberStringBuilder::~NumberStringBuilder() {
- if (fUsingHeap) {
- uprv_free(fChars.heap.ptr);
- uprv_free(fFields.heap.ptr);
- }
-}
-
-NumberStringBuilder::NumberStringBuilder(const NumberStringBuilder &other) {
- *this = other;
-}
-
-NumberStringBuilder &NumberStringBuilder::operator=(const NumberStringBuilder &other) {
- // Check for self-assignment
- if (this == &other) {
- return *this;
- }
-
- // Continue with deallocation and copying
- if (fUsingHeap) {
- uprv_free(fChars.heap.ptr);
- uprv_free(fFields.heap.ptr);
- fUsingHeap = false;
- }
-
- int32_t capacity = other.getCapacity();
- if (capacity > DEFAULT_CAPACITY) {
- // FIXME: uprv_malloc
- // C++ note: malloc appears in two places: here and in prepareForInsertHelper.
- auto newChars = static_cast<char16_t *> (uprv_malloc(sizeof(char16_t) * capacity));
- auto newFields = static_cast<Field *>(uprv_malloc(sizeof(Field) * capacity));
- if (newChars == nullptr || newFields == nullptr) {
- // UErrorCode is not available; fail silently.
- uprv_free(newChars);
- uprv_free(newFields);
- *this = NumberStringBuilder(); // can't fail
- return *this;
- }
-
- fUsingHeap = true;
- fChars.heap.capacity = capacity;
- fChars.heap.ptr = newChars;
- fFields.heap.capacity = capacity;
- fFields.heap.ptr = newFields;
- }
-
- uprv_memcpy2(getCharPtr(), other.getCharPtr(), sizeof(char16_t) * capacity);
- uprv_memcpy2(getFieldPtr(), other.getFieldPtr(), sizeof(Field) * capacity);
-
- fZero = other.fZero;
- fLength = other.fLength;
- return *this;
-}
-
-int32_t NumberStringBuilder::length() const {
- return fLength;
-}
-
-int32_t NumberStringBuilder::codePointCount() const {
- return u_countChar32(getCharPtr() + fZero, fLength);
-}
-
-UChar32 NumberStringBuilder::getFirstCodePoint() const {
- if (fLength == 0) {
- return -1;
- }
- UChar32 cp;
- U16_GET(getCharPtr() + fZero, 0, 0, fLength, cp);
- return cp;
-}
-
-UChar32 NumberStringBuilder::getLastCodePoint() const {
- if (fLength == 0) {
- return -1;
- }
- int32_t offset = fLength;
- U16_BACK_1(getCharPtr() + fZero, 0, offset);
- UChar32 cp;
- U16_GET(getCharPtr() + fZero, 0, offset, fLength, cp);
- return cp;
-}
-
-UChar32 NumberStringBuilder::codePointAt(int32_t index) const {
- UChar32 cp;
- U16_GET(getCharPtr() + fZero, 0, index, fLength, cp);
- return cp;
-}
-
-UChar32 NumberStringBuilder::codePointBefore(int32_t index) const {
- int32_t offset = index;
- U16_BACK_1(getCharPtr() + fZero, 0, offset);
- UChar32 cp;
- U16_GET(getCharPtr() + fZero, 0, offset, fLength, cp);
- return cp;
-}
-
-NumberStringBuilder &NumberStringBuilder::clear() {
- // TODO: Reset the heap here?
- fZero = getCapacity() / 2;
- fLength = 0;
- return *this;
-}
-
-int32_t NumberStringBuilder::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) {
- int32_t count = U16_LENGTH(codePoint);
- int32_t position = prepareForInsert(index, count, status);
- if (U_FAILURE(status)) {
- return count;
- }
- if (count == 1) {
- getCharPtr()[position] = (char16_t) codePoint;
- getFieldPtr()[position] = field;
- } else {
- getCharPtr()[position] = U16_LEAD(codePoint);
- getCharPtr()[position + 1] = U16_TRAIL(codePoint);
- getFieldPtr()[position] = getFieldPtr()[position + 1] = field;
- }
- return count;
-}
-
-int32_t NumberStringBuilder::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,
- UErrorCode &status) {
- if (unistr.length() == 0) {
- // Nothing to insert.
- return 0;
- } else if (unistr.length() == 1) {
- // Fast path: insert using insertCodePoint.
- return insertCodePoint(index, unistr.charAt(0), field, status);
- } else {
- return insert(index, unistr, 0, unistr.length(), field, status);
- }
-}
-
-int32_t
-NumberStringBuilder::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);
- if (U_FAILURE(status)) {
- return count;
- }
- for (int32_t i = 0; i < count; i++) {
- getCharPtr()[position + i] = unistr.charAt(start + i);
- getFieldPtr()[position + i] = field;
- }
- return count;
-}
-
-int32_t
-NumberStringBuilder::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;
- int32_t count = otherLength - thisLength;
- int32_t position;
- if (count > 0) {
- // Overall, chars need to be added.
- position = prepareForInsert(startThis, count, status);
- } else {
- // Overall, chars need to be removed or kept the same.
- position = remove(startThis, -count);
- }
- if (U_FAILURE(status)) {
- return count;
- }
- for (int32_t i = 0; i < otherLength; i++) {
- getCharPtr()[position + i] = unistr.charAt(startOther + i);
- getFieldPtr()[position + i] = field;
- }
- return count;
-}
-
-int32_t NumberStringBuilder::append(const NumberStringBuilder &other, UErrorCode &status) {
- return insert(fLength, other, status);
-}
-
-int32_t
-NumberStringBuilder::insert(int32_t index, const NumberStringBuilder &other, UErrorCode &status) {
- if (this == &other) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return 0;
- }
- int32_t count = other.fLength;
- if (count == 0) {
- // Nothing to insert.
- return 0;
- }
- int32_t position = prepareForInsert(index, count, status);
- if (U_FAILURE(status)) {
- return count;
- }
- for (int32_t i = 0; i < count; i++) {
- getCharPtr()[position + i] = other.charAt(i);
- getFieldPtr()[position + i] = other.fieldAt(i);
- }
- return count;
-}
-
-void NumberStringBuilder::writeTerminator(UErrorCode& status) {
- int32_t position = prepareForInsert(fLength, 1, status);
- if (U_FAILURE(status)) {
- return;
- }
- getCharPtr()[position] = 0;
- getFieldPtr()[position] = UNUM_FIELD_COUNT;
- fLength--;
-}
-
-int32_t NumberStringBuilder::prepareForInsert(int32_t index, int32_t count, UErrorCode &status) {
- U_ASSERT(index >= 0);
- U_ASSERT(index <= fLength);
- U_ASSERT(count >= 0);
- if (index == 0 && fZero - count >= 0) {
- // Append to start
- fZero -= count;
- fLength += count;
- return fZero;
- } else if (index == fLength && fZero + fLength + count < getCapacity()) {
- // Append to end
- fLength += count;
- return fZero + fLength - count;
- } else {
- // Move chars around and/or allocate more space
- return prepareForInsertHelper(index, count, status);
- }
-}
-
-int32_t NumberStringBuilder::prepareForInsertHelper(int32_t index, int32_t count, UErrorCode &status) {
- int32_t oldCapacity = getCapacity();
- int32_t oldZero = fZero;
- char16_t *oldChars = getCharPtr();
- Field *oldFields = getFieldPtr();
- if (fLength + count > oldCapacity) {
- int32_t newCapacity = (fLength + count) * 2;
- int32_t newZero = newCapacity / 2 - (fLength + count) / 2;
-
- // C++ note: malloc appears in two places: here and in the assignment operator.
- auto newChars = static_cast<char16_t *> (uprv_malloc(sizeof(char16_t) * newCapacity));
- auto newFields = static_cast<Field *>(uprv_malloc(sizeof(Field) * newCapacity));
- if (newChars == nullptr || newFields == nullptr) {
- uprv_free(newChars);
- uprv_free(newFields);
- status = U_MEMORY_ALLOCATION_ERROR;
- return -1;
- }
-
- // First copy the prefix and then the suffix, leaving room for the new chars that the
- // caller wants to insert.
- // C++ note: memcpy is OK because the src and dest do not overlap.
- uprv_memcpy2(newChars + newZero, oldChars + oldZero, sizeof(char16_t) * index);
- uprv_memcpy2(newChars + newZero + index + count,
- oldChars + oldZero + index,
- sizeof(char16_t) * (fLength - index));
- uprv_memcpy2(newFields + newZero, oldFields + oldZero, sizeof(Field) * index);
- uprv_memcpy2(newFields + newZero + index + count,
- oldFields + oldZero + index,
- sizeof(Field) * (fLength - index));
-
- if (fUsingHeap) {
- uprv_free(oldChars);
- uprv_free(oldFields);
- }
- fUsingHeap = true;
- fChars.heap.ptr = newChars;
- fChars.heap.capacity = newCapacity;
- fFields.heap.ptr = newFields;
- fFields.heap.capacity = newCapacity;
- fZero = newZero;
- fLength += count;
- } else {
- int32_t newZero = oldCapacity / 2 - (fLength + count) / 2;
-
- // C++ note: memmove is required because src and dest may overlap.
- // First copy the entire string to the location of the prefix, and then move the suffix
- // to make room for the new chars that the caller wants to insert.
- uprv_memmove2(oldChars + newZero, oldChars + oldZero, sizeof(char16_t) * fLength);
- uprv_memmove2(oldChars + newZero + index + count,
- oldChars + newZero + index,
- sizeof(char16_t) * (fLength - index));
- uprv_memmove2(oldFields + newZero, oldFields + oldZero, sizeof(Field) * fLength);
- uprv_memmove2(oldFields + newZero + index + count,
- oldFields + newZero + index,
- sizeof(Field) * (fLength - index));
-
- fZero = newZero;
- fLength += count;
- }
- return fZero + index;
-}
-
-int32_t NumberStringBuilder::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,
- getCharPtr() + position + count,
- sizeof(char16_t) * (fLength - index - count));
- uprv_memmove2(getFieldPtr() + position,
- getFieldPtr() + position + count,
- sizeof(Field) * (fLength - index - count));
- fLength -= count;
- return position;
-}
-
-UnicodeString NumberStringBuilder::toUnicodeString() const {
- return UnicodeString(getCharPtr() + fZero, fLength);
-}
-
-const UnicodeString NumberStringBuilder::toTempUnicodeString() const {
- // Readonly-alias constructor:
- return UnicodeString(FALSE, getCharPtr() + fZero, fLength);
-}
-
-UnicodeString NumberStringBuilder::toDebugString() const {
- UnicodeString sb;
- sb.append(u"<NumberStringBuilder [", -1);
- sb.append(toUnicodeString());
- sb.append(u"] [", -1);
- for (int i = 0; i < fLength; i++) {
- if (fieldAt(i) == UNUM_FIELD_COUNT) {
- sb.append(u'n');
- } else {
- char16_t c;
- switch (fieldAt(i)) {
- case UNUM_SIGN_FIELD:
- c = u'-';
- break;
- case UNUM_INTEGER_FIELD:
- c = u'i';
- break;
- case UNUM_FRACTION_FIELD:
- c = u'f';
- break;
- case UNUM_EXPONENT_FIELD:
- c = u'e';
- break;
- case UNUM_EXPONENT_SIGN_FIELD:
- c = u'+';
- break;
- case UNUM_EXPONENT_SYMBOL_FIELD:
- c = u'E';
- break;
- case UNUM_DECIMAL_SEPARATOR_FIELD:
- c = u'.';
- break;
- case UNUM_GROUPING_SEPARATOR_FIELD:
- c = u',';
- break;
- case UNUM_PERCENT_FIELD:
- c = u'%';
- break;
- case UNUM_PERMILL_FIELD:
- c = u'‰';
- break;
- case UNUM_CURRENCY_FIELD:
- c = u'$';
- break;
- default:
- c = u'?';
- break;
- }
- sb.append(c);
- }
- }
- sb.append(u"]>", -1);
- return sb;
-}
-
-const char16_t *NumberStringBuilder::chars() const {
- return getCharPtr() + fZero;
-}
-
-bool NumberStringBuilder::contentEquals(const NumberStringBuilder &other) const {
- if (fLength != other.fLength) {
- return false;
- }
- for (int32_t i = 0; i < fLength; i++) {
- if (charAt(i) != other.charAt(i) || fieldAt(i) != other.fieldAt(i)) {
- return false;
- }
- }
- 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 {
- for (int32_t i = 0; i < fLength; i++) {
- if (field == fieldAt(i)) {
- return true;
- }
- }
- 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);
-}
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/icu4c/source/i18n/number_stringbuilder.h b/icu4c/source/i18n/number_stringbuilder.h
deleted file mode 100644
index d48f6e1..0000000
--- a/icu4c/source/i18n/number_stringbuilder.h
+++ /dev/null
@@ -1,164 +0,0 @@
-// © 2017 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 __NUMBER_STRINGBUILDER_H__
-#define __NUMBER_STRINGBUILDER_H__
-
-
-#include <cstdint>
-#include "unicode/numfmt.h"
-#include "unicode/ustring.h"
-#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 {
- private:
- static const int32_t DEFAULT_CAPACITY = 40;
-
- template<typename T>
- union ValueOrHeapArray {
- T value[DEFAULT_CAPACITY];
- struct {
- T *ptr;
- int32_t capacity;
- } heap;
- };
-
- public:
- NumberStringBuilder();
-
- ~NumberStringBuilder();
-
- NumberStringBuilder(const NumberStringBuilder &other);
-
- NumberStringBuilder &operator=(const NumberStringBuilder &other);
-
- int32_t length() const;
-
- int32_t codePointCount() const;
-
- inline char16_t charAt(int32_t index) const {
- U_ASSERT(index >= 0);
- U_ASSERT(index < fLength);
- return getCharPtr()[fZero + index];
- }
-
- inline Field fieldAt(int32_t index) const {
- U_ASSERT(index >= 0);
- U_ASSERT(index < fLength);
- return getFieldPtr()[fZero + index];
- }
-
- UChar32 getFirstCodePoint() const;
-
- UChar32 getLastCodePoint() const;
-
- UChar32 codePointAt(int32_t index) const;
-
- UChar32 codePointBefore(int32_t index) const;
-
- NumberStringBuilder &clear();
-
- int32_t appendCodePoint(UChar32 codePoint, Field field, UErrorCode &status);
-
- int32_t insertCodePoint(int32_t index, UChar32 codePoint, Field field, UErrorCode &status);
-
- int32_t append(const UnicodeString &unistr, Field field, UErrorCode &status);
-
- int32_t insert(int32_t index, const UnicodeString &unistr, Field field, UErrorCode &status);
-
- int32_t insert(int32_t index, const UnicodeString &unistr, int32_t start, int32_t end, Field field,
- UErrorCode &status);
-
- 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 insert(int32_t index, const NumberStringBuilder &other, UErrorCode &status);
-
- void writeTerminator(UErrorCode& status);
-
- /**
- * Gets a "safe" UnicodeString that can be used even after the NumberStringBuilder is destructed.
- * */
- UnicodeString toUnicodeString() const;
-
- /**
- * Gets an "unsafe" UnicodeString that is valid only as long as the NumberStringBuilder is alive and
- * unchanged. Slightly faster than toUnicodeString().
- */
- const UnicodeString toTempUnicodeString() const;
-
- UnicodeString toDebugString() const;
-
- 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 containsField(Field field) const;
-
- private:
- bool fUsingHeap = false;
- ValueOrHeapArray<char16_t> fChars;
- ValueOrHeapArray<Field> fFields;
- int32_t fZero = DEFAULT_CAPACITY / 2;
- int32_t fLength = 0;
-
- inline char16_t *getCharPtr() {
- return fUsingHeap ? fChars.heap.ptr : fChars.value;
- }
-
- inline const char16_t *getCharPtr() const {
- return fUsingHeap ? fChars.heap.ptr : fChars.value;
- }
-
- inline Field *getFieldPtr() {
- return fUsingHeap ? fFields.heap.ptr : fFields.value;
- }
-
- inline const Field *getFieldPtr() const {
- return fUsingHeap ? fFields.heap.ptr : fFields.value;
- }
-
- inline int32_t getCapacity() const {
- return fUsingHeap ? fChars.heap.capacity : DEFAULT_CAPACITY;
- }
-
- int32_t prepareForInsert(int32_t index, int32_t count, UErrorCode &status);
-
- int32_t prepareForInsertHelper(int32_t index, int32_t count, UErrorCode &status);
-
- int32_t remove(int32_t index, int32_t count);
-
- static bool isIntOrGroup(Field field);
-
- static bool isNumericField(Field field);
-
- int32_t trimBack(int32_t limit) const;
-
- int32_t trimFront(int32_t start) const;
-};
-
-} // namespace impl
-} // namespace number
-U_NAMESPACE_END
-
-
-#endif //__NUMBER_STRINGBUILDER_H__
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/icu4c/source/i18n/number_types.h b/icu4c/source/i18n/number_types.h
index 225d1e5..5aeead7 100644
--- a/icu4c/source/i18n/number_types.h
+++ b/icu4c/source/i18n/number_types.h
@@ -17,17 +17,16 @@
#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;
/**
diff --git a/icu4c/source/i18n/number_utils.h b/icu4c/source/i18n/number_utils.h
index 203dec6..93195f0 100644
--- a/icu4c/source/i18n/number_utils.h
+++ b/icu4c/source/i18n/number_utils.h
@@ -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) {
diff --git a/icu4c/source/i18n/number_utypes.h b/icu4c/source/i18n/number_utypes.h
index 88b493c..6dbe5be 100644
--- a/icu4c/source/i18n/number_utypes.h
+++ b/icu4c/source/i18n/number_utypes.h
@@ -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;
diff --git a/icu4c/source/i18n/numparse_affixes.cpp b/icu4c/source/i18n/numparse_affixes.cpp
index 6e00d9f..6dc30d2 100644
--- a/icu4c/source/i18n/numparse_affixes.cpp
+++ b/icu4c/source/i18n/numparse_affixes.cpp
@@ -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;
diff --git a/icu4c/source/i18n/numparse_compositions.cpp b/icu4c/source/i18n/numparse_compositions.cpp
index 19253da..2f7e1ab 100644
--- a/icu4c/source/i18n/numparse_compositions.cpp
+++ b/icu4c/source/i18n/numparse_compositions.cpp
@@ -11,6 +11,7 @@
#include "numparse_types.h"
#include "numparse_compositions.h"
+#include "string_segment.h"
#include "unicode/uniset.h"
using namespace icu;
diff --git a/icu4c/source/i18n/numparse_currency.cpp b/icu4c/source/i18n/numparse_currency.cpp
index 598ace5..6b53a73 100644
--- a/icu4c/source/i18n/numparse_currency.cpp
+++ b/icu4c/source/i18n/numparse_currency.cpp
@@ -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;
diff --git a/icu4c/source/i18n/numparse_decimal.cpp b/icu4c/source/i18n/numparse_decimal.cpp
index b120c5c..cf1e815 100644
--- a/icu4c/source/i18n/numparse_decimal.cpp
+++ b/icu4c/source/i18n/numparse_decimal.cpp
@@ -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;
diff --git a/icu4c/source/i18n/numparse_impl.h b/icu4c/source/i18n/numparse_impl.h
index 7d5f0b6..380d9aa 100644
--- a/icu4c/source/i18n/numparse_impl.h
+++ b/icu4c/source/i18n/numparse_impl.h
@@ -18,6 +18,7 @@
#include "unicode/localpointer.h"
#include "numparse_validators.h"
#include "number_multiplier.h"
+#include "string_segment.h"
U_NAMESPACE_BEGIN
diff --git a/icu4c/source/i18n/numparse_parsednumber.cpp b/icu4c/source/i18n/numparse_parsednumber.cpp
index 3145f71..6485d17 100644
--- a/icu4c/source/i18n/numparse_parsednumber.cpp
+++ b/icu4c/source/i18n/numparse_parsednumber.cpp
@@ -11,6 +11,7 @@
#include "numparse_types.h"
#include "number_decimalquantity.h"
+#include "string_segment.h"
#include "putilimp.h"
#include <cmath>
diff --git a/icu4c/source/i18n/numparse_scientific.cpp b/icu4c/source/i18n/numparse_scientific.cpp
index de38957..b83b693 100644
--- a/icu4c/source/i18n/numparse_scientific.cpp
+++ b/icu4c/source/i18n/numparse_scientific.cpp
@@ -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
index 7a84444..0000000
--- a/icu4c/source/i18n/numparse_stringsegment.h
+++ /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 */
diff --git a/icu4c/source/i18n/numparse_symbols.cpp b/icu4c/source/i18n/numparse_symbols.cpp
index e0daab9..bf14c71 100644
--- a/icu4c/source/i18n/numparse_symbols.cpp
+++ b/icu4c/source/i18n/numparse_symbols.cpp
@@ -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;
diff --git a/icu4c/source/i18n/numparse_types.h b/icu4c/source/i18n/numparse_types.h
index 0fd70fa..a6bfe68 100644
--- a/icu4c/source/i18n/numparse_types.h
+++ b/icu4c/source/i18n/numparse_types.h
@@ -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;
@@ -170,115 +171,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.
*
* Given a string, there should NOT be more than one way to consume the string with the same matcher
diff --git a/icu4c/source/i18n/numrange_fluent.cpp b/icu4c/source/i18n/numrange_fluent.cpp
index 079d519..a788108 100644
--- a/icu4c/source/i18n/numrange_fluent.cpp
+++ b/icu4c/source/i18n/numrange_fluent.cpp
@@ -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 {
diff --git a/icu4c/source/i18n/numrange_impl.cpp b/icu4c/source/i18n/numrange_impl.cpp
index 05eb2b8..7d732b3 100644
--- a/icu4c/source/i18n/numrange_impl.cpp
+++ b/icu4c/source/i18n/numrange_impl.cpp
@@ -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;
diff --git a/icu4c/source/i18n/numrange_impl.h b/icu4c/source/i18n/numrange_impl.h
index dc25dd4..f88e300 100644
--- a/icu4c/source/i18n/numrange_impl.h
+++ b/icu4c/source/i18n/numrange_impl.h
@@ -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;
diff --git a/icu4c/source/i18n/quantityformatter.cpp b/icu4c/source/i18n/quantityformatter.cpp
index 9182f9e..b8c26c4 100644
--- a/icu4c/source/i18n/quantityformatter.cpp
+++ b/icu4c/source/i18n/quantityformatter.cpp
@@ -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;
diff --git a/icu4c/source/i18n/quantityformatter.h b/icu4c/source/i18n/quantityformatter.h
index 046eec7..daaef4f 100644
--- a/icu4c/source/i18n/quantityformatter.h
+++ b/icu4c/source/i18n/quantityformatter.h
@@ -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 @@ class U_I18N_API QuantityFormatter : public UMemory {
/**
* 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 @@ class U_I18N_API QuantityFormatter : public UMemory {
double quantity,
const NumberFormat& fmt,
const PluralRules& rules,
- number::impl::NumberStringBuilder& output,
+ FormattedStringBuilder& output,
StandardPlural::Form& pluralForm,
UErrorCode& status);
diff --git a/icu4c/source/i18n/reldatefmt.cpp b/icu4c/source/i18n/reldatefmt.cpp
index 2b58e47..fd54bf0 100644
--- a/icu4c/source/i18n/reldatefmt.cpp
+++ b/icu4c/source/i18n/reldatefmt.cpp
@@ -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();
};
diff --git a/icu4c/source/i18n/numparse_stringsegment.cpp b/icu4c/source/i18n/string_segment.cpp
similarity index 96%
rename from icu4c/source/i18n/numparse_stringsegment.cpp
rename to icu4c/source/i18n/string_segment.cpp
index 3db4fe6..5d19ac5 100644
--- a/icu4c/source/i18n/numparse_stringsegment.cpp
+++ b/icu4c/source/i18n/string_segment.cpp
@@ -10,14 +10,12 @@
#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
index 0000000..b581f7e
--- /dev/null
+++ b/icu4c/source/i18n/string_segment.h
@@ -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 */
diff --git a/icu4c/source/i18n/unicode/numberformatter.h b/icu4c/source/i18n/unicode/numberformatter.h
index 4fd6830..5144ea9 100644
--- a/icu4c/source/i18n/unicode/numberformatter.h
+++ b/icu4c/source/i18n/unicode/numberformatter.h
@@ -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:
diff --git a/icu4c/source/test/depstest/dependencies.txt b/icu4c/source/test/depstest/dependencies.txt
index 466e642..f7404a0 100644
--- a/icu4c/source/test/depstest/dependencies.txt
+++ b/icu4c/source/test/depstest/dependencies.txt
@@ -932,7 +932,9 @@
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
diff --git a/icu4c/source/test/intltest/Makefile.in b/icu4c/source/test/intltest/Makefile.in
index b4cf918..3a7c754 100644
--- a/icu4c/source/test/intltest/Makefile.in
+++ b/icu4c/source/test/intltest/Makefile.in
@@ -64,10 +64,10 @@
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)
diff --git a/icu4c/source/test/intltest/numbertest_stringbuilder.cpp b/icu4c/source/test/intltest/formatted_string_builder_test.cpp
similarity index 81%
rename from icu4c/source/test/intltest/numbertest_stringbuilder.cpp
rename to icu4c/source/test/intltest/formatted_string_builder_test.cpp
index eaf9a7a..9da402f 100644
--- a/icu4c/source/test/intltest/numbertest_stringbuilder.cpp
+++ b/icu4c/source/test/intltest/formatted_string_builder_test.cpp
@@ -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 */
diff --git a/icu4c/source/test/intltest/intltest.vcxproj b/icu4c/source/test/intltest/intltest.vcxproj
index 5e82ef3..2129cfb 100644
--- a/icu4c/source/test/intltest/intltest.vcxproj
+++ b/icu4c/source/test/intltest/intltest.vcxproj
@@ -232,6 +232,7 @@
</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" />
@@ -251,8 +252,7 @@
<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" />
diff --git a/icu4c/source/test/intltest/intltest.vcxproj.filters b/icu4c/source/test/intltest/intltest.vcxproj.filters
index bed26bc..945f737 100644
--- a/icu4c/source/test/intltest/intltest.vcxproj.filters
+++ b/icu4c/source/test/intltest/intltest.vcxproj.filters
@@ -217,6 +217,9 @@
<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>
@@ -274,10 +277,7 @@
<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">
diff --git a/icu4c/source/test/intltest/itformat.cpp b/icu4c/source/test/intltest/itformat.cpp
index 1c993fc..870728a 100644
--- a/icu4c/source/test/intltest/itformat.cpp
+++ b/icu4c/source/test/intltest/itformat.cpp
@@ -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) {
diff --git a/icu4c/source/test/intltest/numbertest.h b/icu4c/source/test/intltest/numbertest.h
index 1ea3ee8..d139bc0 100644
--- a/icu4c/source/test/intltest/numbertest.h
+++ b/icu4c/source/test/intltest/numbertest.h
@@ -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
}
}
diff --git a/icu4c/source/test/intltest/numbertest_affixutils.cpp b/icu4c/source/test/intltest/numbertest_affixutils.cpp
index eefded6..7f29ad1 100644
--- a/icu4c/source/test/intltest/numbertest_affixutils.cpp
+++ b/icu4c/source/test/intltest/numbertest_affixutils.cpp
@@ -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();
diff --git a/icu4c/source/test/intltest/numbertest_modifiers.cpp b/icu4c/source/test/intltest/numbertest_modifiers.cpp
index 52f4f49..90144ad 100644
--- a/icu4c/source/test/intltest/numbertest_modifiers.cpp
+++ b/icu4c/source/test/intltest/numbertest_modifiers.cpp
@@ -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);
diff --git a/icu4c/source/test/intltest/numbertest_patternmodifier.cpp b/icu4c/source/test/intltest/numbertest_patternmodifier.cpp
index ba382a6..e557dcf 100644
--- a/icu4c/source/test/intltest/numbertest_patternmodifier.cpp
+++ b/icu4c/source/test/intltest/numbertest_patternmodifier.cpp
@@ -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(µs1);
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(µs3);
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);
diff --git a/icu4c/source/test/intltest/numbertest_stringsegment.cpp b/icu4c/source/test/intltest/string_segment_test.cpp
similarity index 91%
rename from icu4c/source/test/intltest/numbertest_stringsegment.cpp
rename to icu4c/source/test/intltest/string_segment_test.cpp
index dc5774f..0548d9a 100644
--- a/icu4c/source/test/intltest/numbertest_stringsegment.cpp
+++ b/icu4c/source/test/intltest/string_segment_test.cpp
@@ -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
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/NumberStringBuilder.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/FormattedStringBuilder.java
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 60a5467..ca3cb18 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/NumberStringBuilder.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/FormattedStringBuilder.java
@@ -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 @@
* <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 int codePointBefore(int index) {
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 int insert(int index, char[] chars, Field[] fields) {
}
/**
- * 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 @@ private int getCapacity() {
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 String toString() {
*
* <p>
* For example, if the string is "-12.345", the debug string will be something like
- * "<NumberStringBuilder [-123.45] [-iii.ff]>"
+ * "<FormattedStringBuilder [-123.45] [-iii.ff]>"
*
* @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 boolean contentEquals(char[] chars, Field[] fields) {
* 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 int hashCode() {
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
index 0000000..8bfe7a5
--- /dev/null
+++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/FormattedValueStringBuilderImpl.java
@@ -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);
+ }
+}
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/StringSegment.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/StringSegment.java
index 7ccf083..ce3f667 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/impl/StringSegment.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/StringSegment.java
@@ -6,14 +6,16 @@
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;
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/AffixUtils.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/AffixUtils.java
index efb41bc..ca79325 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/AffixUtils.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/AffixUtils.java
@@ -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 static final NumberFormat.Field getFieldForType(int type) {
/**
* 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 static final NumberFormat.Field getFieldForType(int type) {
* @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) {
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/ConstantAffixModifier.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/ConstantAffixModifier.java
index c82d50d..9249851 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/ConstantAffixModifier.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/ConstantAffixModifier.java
@@ -4,6 +4,8 @@
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 ConstantAffixModifier() {
}
@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);
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/ConstantMultiFieldModifier.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/ConstantMultiFieldModifier.java
index 6732960..39d57c4 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/ConstantMultiFieldModifier.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/ConstantMultiFieldModifier.java
@@ -5,14 +5,16 @@
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 ConstantMultiFieldModifier(
}
@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 boolean semanticallyEquivalent(Modifier other) {
@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'>",
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/CurrencySpacingEnabledModifier.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/CurrencySpacingEnabledModifier.java
index 61c04c5..e0f3be3 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/CurrencySpacingEnabledModifier.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/CurrencySpacingEnabledModifier.java
@@ -4,6 +4,7 @@
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 CurrencySpacingEnabledModifier(
/** 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 int apply(NumberStringBuilder output, int leftIndex, int rightIndex) {
/** Unsafe code path */
public static int applyCurrencySpacing(
- NumberStringBuilder output,
+ FormattedStringBuilder output,
int prefixStart,
int prefixLen,
int suffixStart,
@@ -117,7 +118,7 @@ public static int applyCurrencySpacing(
/** Unsafe code path */
private static int applyCurrencySpacingAffix(
- NumberStringBuilder output,
+ FormattedStringBuilder output,
int index,
byte affix,
DecimalFormatSymbols symbols) {
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/Modifier.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/Modifier.java
index f3f4635..cc56329 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/Modifier.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/Modifier.java
@@ -4,6 +4,7 @@
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
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/MutablePatternModifier.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/MutablePatternModifier.java
index b1c1e9a..67f79b9 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/MutablePatternModifier.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/MutablePatternModifier.java
@@ -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 ImmutablePatternModifier createImmutable() {
* @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 ImmutablePatternModifier createImmutableAndChain(MicroPropsGenerator pare
* 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 MicroProps processQuantity(DecimalQuantity fq) {
}
@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 boolean semanticallyEquivalent(Modifier other) {
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;
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/Padder.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/Padder.java
index 97a3109..ccbf871 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/Padder.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/Padder.java
@@ -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 boolean isValid() {
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 int padAndApply(
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.
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/SimpleModifier.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/SimpleModifier.java
index 26cb275..6241848 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/SimpleModifier.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/SimpleModifier.java
@@ -4,6 +4,7 @@
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 SimpleModifier(String compiledPattern, Field field, boolean strong, Param
}
@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 boolean semanticallyEquivalent(Modifier other) {
* @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 int formatAsPrefixSuffix(
/**
* 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) {
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/number/FormattedNumber.java b/icu4j/main/classes/core/src/com/ibm/icu/number/FormattedNumber.java
index 4fda533..c607144 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/number/FormattedNumber.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/number/FormattedNumber.java
@@ -7,9 +7,10 @@
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 @@
* @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 <A extends Appendable> A appendTo(A appendable) {
*/
@Override
public boolean nextPosition(ConstrainedFieldPosition cfpos) {
- return string.nextPosition(cfpos, null);
+ return FormattedValueStringBuilderImpl.nextPosition(string, cfpos, null);
}
/**
@@ -107,7 +108,7 @@ public boolean nextPosition(ConstrainedFieldPosition cfpos) {
*/
@Override
public AttributedCharacterIterator toCharacterIterator() {
- return string.toCharacterIterator(null);
+ return FormattedValueStringBuilderImpl.toCharacterIterator(string, null);
}
/**
@@ -145,7 +146,7 @@ public AttributedCharacterIterator toCharacterIterator() {
*/
public boolean nextFieldPosition(FieldPosition fieldPosition) {
fq.populateUFieldPosition(fieldPosition);
- return string.nextFieldPosition(fieldPosition);
+ return FormattedValueStringBuilderImpl.nextFieldPosition(string, fieldPosition);
}
/**
@@ -179,7 +180,7 @@ public IFixedDecimal getFixedDecimal() {
*/
@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 boolean equals(Object other) {
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())
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/number/FormattedNumberRange.java b/icu4j/main/classes/core/src/com/ibm/icu/number/FormattedNumberRange.java
index e23a96d..9992a5a 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/number/FormattedNumberRange.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/number/FormattedNumberRange.java
@@ -8,8 +8,9 @@
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 @@
* @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 CharSequence subSequence(int start, int end) {
*/
@Override
public boolean nextPosition(ConstrainedFieldPosition cfpos) {
- return string.nextPosition(cfpos, null);
+ return FormattedValueStringBuilderImpl.nextPosition(string, cfpos, null);
}
/**
@@ -142,7 +143,7 @@ public boolean nextPosition(ConstrainedFieldPosition cfpos) {
* @see NumberRangeFormatter
*/
public boolean nextFieldPosition(FieldPosition fieldPosition) {
- return string.nextFieldPosition(fieldPosition);
+ return FormattedValueStringBuilderImpl.nextFieldPosition(string, fieldPosition);
}
/**
@@ -153,7 +154,7 @@ public boolean nextFieldPosition(FieldPosition fieldPosition) {
*/
@Override
public AttributedCharacterIterator toCharacterIterator() {
- return string.toCharacterIterator(null);
+ return FormattedValueStringBuilderImpl.toCharacterIterator(string, null);
}
/**
@@ -207,7 +208,7 @@ public RangeIdentityResult getIdentityResult() {
*/
@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 boolean equals(Object other) {
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())
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/number/LocalizedNumberFormatter.java b/icu4j/main/classes/core/src/com/ibm/icu/number/LocalizedNumberFormatter.java
index d50aeee..eace5ba 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/number/LocalizedNumberFormatter.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/number/LocalizedNumberFormatter.java
@@ -7,12 +7,12 @@
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 Format toFormat() {
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 @@ private FormattedNumber format(DecimalQuantity fq) {
* @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 void formatImpl(DecimalQuantity fq, NumberStringBuilder string) {
*/
@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;
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatterImpl.java b/icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatterImpl.java
index 4adf958..3677412 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatterImpl.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatterImpl.java
@@ -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.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 @@ public NumberFormatterImpl(MacroProps macros) {
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 @@ public static int getPrefixSuffixStatic(
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 @@ public static int getPrefixSuffixStatic(
/**
* 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 @@ private static MicroProps preProcessUnsafe(MacroProps macros, DecimalQuantity in
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 @@ private static MicroPropsGenerator macrosToMicroGenerator(MacroProps macros, Mic
*/
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 @@ public static int writeAffixes(
public static int writeNumber(
MicroProps micros,
DecimalQuantity quantity,
- NumberStringBuilder string,
+ FormattedStringBuilder string,
int index) {
int length = 0;
if (quantity.isInfinite()) {
@@ -448,7 +448,7 @@ public static int writeNumber(
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 @@ private static int writeIntegerDigits(
private static int writeFractionDigits(
MicroProps micros,
DecimalQuantity quantity,
- NumberStringBuilder string,
+ FormattedStringBuilder string,
int index) {
int length = 0;
int fractionCount = -quantity.getLowerDisplayMagnitude();
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/number/NumberRangeFormatterImpl.java b/icu4j/main/classes/core/src/com/ibm/icu/number/NumberRangeFormatterImpl.java
index 8b9059b..81f4bd5 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/number/NumberRangeFormatterImpl.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/number/NumberRangeFormatterImpl.java
@@ -6,6 +6,7 @@
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.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 @@ public NumberRangeFormatterImpl(RangeMacroProps macros) {
}
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 @@ public FormattedNumberRange format(DecimalQuantity quantity1, DecimalQuantity qu
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 @@ private void formatSingleValue(DecimalQuantity quantity1, DecimalQuantity quanti
}
- 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 @@ private void formatApproximately(DecimalQuantity quantity1, DecimalQuantity quan
}
}
- 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.
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/number/ScientificNotation.java b/icu4j/main/classes/core/src/com/ibm/icu/number/ScientificNotation.java
index e94aa98..f195f6e 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/number/ScientificNotation.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/number/ScientificNotation.java
@@ -4,12 +4,12 @@
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 boolean semanticallyEquivalent(Modifier other) {
}
@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 @@ private static class ScientificModifier implements Modifier {
}
@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);
}
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/text/RelativeDateTimeFormatter.java b/icu4j/main/classes/core/src/com/ibm/icu/text/RelativeDateTimeFormatter.java
index a8e063b..686d801 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/text/RelativeDateTimeFormatter.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/text/RelativeDateTimeFormatter.java
@@ -16,15 +16,16 @@
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 @@ protected Object readResolve() throws InvalidObjectException {
*/
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 <A extends Appendable> A appendTo(A appendable) {
*/
@Override
public boolean nextPosition(ConstrainedFieldPosition cfpos) {
- return string.nextPosition(cfpos, Field.NUMERIC);
+ return FormattedValueStringBuilderImpl.nextPosition(string, cfpos, Field.NUMERIC);
}
/**
@@ -544,7 +545,7 @@ public boolean nextPosition(ConstrainedFieldPosition cfpos) {
*/
@Override
public AttributedCharacterIterator toCharacterIterator() {
- return string.toCharacterIterator(Field.NUMERIC);
+ return FormattedValueStringBuilderImpl.toCharacterIterator(string, Field.NUMERIC);
}
}
@@ -660,7 +661,7 @@ public static RelativeDateTimeFormatter getInstance(Locale locale, NumberFormat
* @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 FormattedRelativeDateTime formatToValue(double quantity, Direction direct
}
/** 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 @@ private NumberStringBuilder formatImpl(double quantity, Direction direction, Rel
* @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 FormattedRelativeDateTime formatNumericToValue(double offset, RelativeDat
}
/** 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 FormattedRelativeDateTime formatToValue(Direction direction, AbsoluteUnit
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 String format(double offset, RelativeDateTimeUnit unit) {
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);
diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberStringBuilderTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/FormattedStringBuilderTest.java
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 c85bbfe..caf2162 100644
--- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberStringBuilderTest.java
+++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/FormattedStringBuilderTest.java
@@ -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 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 void testInsertAppendCharSequence() {
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 void testInsertAppendCharSequence() {
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 void testSplice() {
{ "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 void testInsertAppendCodePoint() {
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 void testInsertAppendCodePoint() {
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 void testInsertAppendCodePoint() {
@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 void testCopy() {
@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 void testFields() {
// 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 void testFields() {
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 void testFields() {
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 void testFields() {
@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 void testUnlimitedCapacity() {
@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 @@ private static void assertCharSequenceEquals(CharSequence a, CharSequence b) {
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));
}
}
diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/AffixUtilsTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/AffixUtilsTest.java
index 5c528c6..e778170 100644
--- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/AffixUtilsTest.java
+++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/AffixUtilsTest.java
@@ -7,9 +7,9 @@
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 CharSequence getSymbol(int type) {
}
};
- 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 void testWithoutSymbolsOrIgnorables() {
}
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();
diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/DecimalQuantityTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/DecimalQuantityTest.java
index 9271d94..471682a 100644
--- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/DecimalQuantityTest.java
+++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/DecimalQuantityTest.java
@@ -19,10 +19,10 @@
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 @@ private static void testDecimalQuantityWithFormats(
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();
diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/ModifierTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/ModifierTest.java
index fee90da..2d4d33c 100644
--- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/ModifierTest.java
+++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/ModifierTest.java
@@ -7,12 +7,12 @@
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 void testConstantAffixModifier() {
@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 void testSimpleModifier() {
// 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 void testSimpleModifier() {
@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 void testCurrencySpacingEnabledModifier() {
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 @@ private void assertModifierEquals(
boolean expectedStrong,
String expectedChars,
String expectedFields) {
- NumberStringBuilder sb = new NumberStringBuilder();
+ FormattedStringBuilder sb = new FormattedStringBuilder();
sb.appendCodePoint('|', null);
assertModifierEquals(mod,
sb,
@@ -159,7 +159,7 @@ private void assertModifierEquals(
private void assertModifierEquals(
Modifier mod,
- NumberStringBuilder sb,
+ FormattedStringBuilder sb,
int expectedPrefixLength,
boolean expectedStrong,
String expectedChars,
@@ -173,7 +173,7 @@ private void assertModifierEquals(
sb.codePointCount() - oldCount,
mod.getCodePointCount());
}
- assertEquals("<NumberStringBuilder [" + expectedChars + "] [" + expectedFields + "]>",
+ assertEquals("<FormattedStringBuilder [" + expectedChars + "] [" + expectedFields + "]>",
sb.toDebugString());
}
}
diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/MutablePatternModifierTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/MutablePatternModifierTest.java
index 5f2c13c..9f8585b 100644
--- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/MutablePatternModifierTest.java
+++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/MutablePatternModifierTest.java
@@ -8,11 +8,11 @@
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 void mutableEqualsImmutable() {
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 void patternWithNoPlaceholder() {
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 void patternWithNoPlaceholder() {
}
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();
}