]> granicus.if.org Git - icu/commitdiff
ICU-13763 Makes FieldPositionIterator offset by input string length in DecimalFormat...
authorShane Carr <shane@unicode.org>
Wed, 23 May 2018 21:08:53 +0000 (21:08 +0000)
committerShane Carr <shane@unicode.org>
Wed, 23 May 2018 21:08:53 +0000 (21:08 +0000)
X-SVN-Rev: 41442

13 files changed:
icu4c/source/i18n/decimfmt.cpp
icu4c/source/i18n/fphdlimp.cpp
icu4c/source/i18n/fphdlimp.h
icu4c/source/i18n/number_capi.cpp
icu4c/source/i18n/number_fluent.cpp
icu4c/source/i18n/number_stringbuilder.cpp
icu4c/source/i18n/number_stringbuilder.h
icu4c/source/i18n/number_utils.cpp
icu4c/source/i18n/unicode/decimfmt.h
icu4c/source/i18n/unicode/fpositer.h
icu4c/source/i18n/unicode/numberformatter.h
icu4c/source/test/intltest/numfmtst.cpp
icu4c/source/test/intltest/numfmtst.h

index 161861d732683c62f7f0053db962345eeec2234a..8cce9c34295d49c8745f3a28c7b469926184ed5f 100644 (file)
@@ -453,9 +453,7 @@ DecimalFormat::format(double number, UnicodeString& appendTo, FieldPositionItera
         return appendTo;
     }
     FormattedNumber output = fields->formatter->formatDouble(number, status);
-    if (posIter != nullptr) {
-        output.populateFieldPositionIterator(*posIter, status);
-    }
+    fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
     auto appendable = UnicodeStringAppendable(appendTo);
     output.appendTo(appendable);
     return appendTo;
@@ -507,9 +505,7 @@ DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPositionIter
         return appendTo;
     }
     FormattedNumber output = fields->formatter->formatInt(number, status);
-    if (posIter != nullptr) {
-        output.populateFieldPositionIterator(*posIter, status);
-    }
+    fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
     auto appendable = UnicodeStringAppendable(appendTo);
     output.appendTo(appendable);
     return appendTo;
@@ -519,9 +515,7 @@ UnicodeString&
 DecimalFormat::format(StringPiece number, UnicodeString& appendTo, FieldPositionIterator* posIter,
                       UErrorCode& status) const {
     FormattedNumber output = fields->formatter->formatDecimal(number, status);
-    if (posIter != nullptr) {
-        output.populateFieldPositionIterator(*posIter, status);
-    }
+    fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
     auto appendable = UnicodeStringAppendable(appendTo);
     output.appendTo(appendable);
     return appendTo;
@@ -530,9 +524,7 @@ DecimalFormat::format(StringPiece number, UnicodeString& appendTo, FieldPosition
 UnicodeString& DecimalFormat::format(const DecimalQuantity& number, UnicodeString& appendTo,
                                      FieldPositionIterator* posIter, UErrorCode& status) const {
     FormattedNumber output = fields->formatter->formatDecimalQuantity(number, status);
-    if (posIter != nullptr) {
-        output.populateFieldPositionIterator(*posIter, status);
-    }
+    fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
     auto appendable = UnicodeStringAppendable(appendTo);
     output.appendTo(appendable);
     return appendTo;
@@ -1237,8 +1229,18 @@ DecimalFormat::fieldPositionHelper(const number::FormattedNumber& formatted, Fie
     fieldPosition.setEndIndex(0);
     bool found = formatted.nextFieldPosition(fieldPosition, status);
     if (found && offset != 0) {
-        fieldPosition.setBeginIndex(fieldPosition.getBeginIndex() + offset);
-        fieldPosition.setEndIndex(fieldPosition.getEndIndex() + offset);
+        FieldPositionOnlyHandler fpoh(fieldPosition);
+        fpoh.shiftLast(offset);
+    }
+}
+
+void
+DecimalFormat::fieldPositionIteratorHelper(const number::FormattedNumber& formatted, FieldPositionIterator* fpi,
+                                           int32_t offset, UErrorCode& status) {
+    if (fpi != nullptr) {
+        FieldPositionIteratorHandler fpih(fpi, status);
+        fpih.setShift(offset);
+        formatted.getAllFieldPositionsImpl(fpih, status);
     }
 }
 
index abcec97ee3171c0fd64f9ed033704dffe207fea2..c4015fae1bbaff0b2de6b472fb413a2ed2e418ef 100644 (file)
@@ -22,17 +22,8 @@ U_NAMESPACE_BEGIN
 FieldPositionHandler::~FieldPositionHandler() {
 }
 
-void
-FieldPositionHandler::addAttribute(int32_t, int32_t, int32_t) {
-}
-
-void
-FieldPositionHandler::shiftLast(int32_t) {
-}
-
-UBool
-FieldPositionHandler::isRecording(void) const {
-  return FALSE;
+void FieldPositionHandler::setShift(int32_t delta) {
+  fShift = delta;
 }
 
 
@@ -48,8 +39,8 @@ FieldPositionOnlyHandler::~FieldPositionOnlyHandler() {
 void
 FieldPositionOnlyHandler::addAttribute(int32_t id, int32_t start, int32_t limit) {
   if (pos.getField() == id) {
-    pos.setBeginIndex(start);
-    pos.setEndIndex(limit);
+    pos.setBeginIndex(start + fShift);
+    pos.setEndIndex(limit + fShift);
   }
 }
 
@@ -91,8 +82,8 @@ FieldPositionIteratorHandler::addAttribute(int32_t id, int32_t start, int32_t li
   if (iter && U_SUCCESS(status) && start < limit) {
     int32_t size = vec->size();
     vec->addElement(id, status);
-    vec->addElement(start, status);
-    vec->addElement(limit, status);
+    vec->addElement(start + fShift, status);
+    vec->addElement(limit + fShift, status);
     if (!U_SUCCESS(status)) {
       vec->setSize(size);
     }
index f3ac12c2bacb9a7b081b42bd4d55b69931e73893..2e9d5622b1b5b0841fb927ad88da03353839bff0 100644 (file)
@@ -22,11 +22,16 @@ U_NAMESPACE_BEGIN
 // base class, null implementation
 
 class U_I18N_API FieldPositionHandler: public UMemory {
+ protected:
+  int32_t fShift = 0;
+
  public:
   virtual ~FieldPositionHandler();
-  virtual void addAttribute(int32_t id, int32_t start, int32_t limit);
-  virtual void shiftLast(int32_t delta);
-  virtual UBool isRecording(void) const;
+  virtual void addAttribute(int32_t id, int32_t start, int32_t limit) = 0;
+  virtual void shiftLast(int32_t delta) = 0;
+  virtual UBool isRecording(void) const = 0;
+
+  void setShift(int32_t delta);
 };
 
 
@@ -39,9 +44,9 @@ class FieldPositionOnlyHandler : public FieldPositionHandler {
   FieldPositionOnlyHandler(FieldPosition& pos);
   virtual ~FieldPositionOnlyHandler();
 
-  virtual void addAttribute(int32_t id, int32_t start, int32_t limit);
-  virtual void shiftLast(int32_t delta);
-  virtual UBool isRecording(void) const;
+  void addAttribute(int32_t id, int32_t start, int32_t limit) U_OVERRIDE;
+  void shiftLast(int32_t delta) U_OVERRIDE;
+  UBool isRecording(void) const U_OVERRIDE;
 };
 
 
@@ -63,9 +68,9 @@ class FieldPositionIteratorHandler : public FieldPositionHandler {
   FieldPositionIteratorHandler(FieldPositionIterator* posIter, UErrorCode& status);
   ~FieldPositionIteratorHandler();
 
-  virtual void addAttribute(int32_t id, int32_t start, int32_t limit);
-  virtual void shiftLast(int32_t delta);
-  virtual UBool isRecording(void) const;
+  void addAttribute(int32_t id, int32_t start, int32_t limit) U_OVERRIDE;
+  void shiftLast(int32_t delta) U_OVERRIDE;
+  UBool isRecording(void) const U_OVERRIDE;
 };
 
 U_NAMESPACE_END
index 6d979cbd0fdc71ecec06d1731ca609f20c1501ba..ca7918bc82e8796a0d308f21650abcf616dc6804 100644 (file)
@@ -9,6 +9,7 @@
 // Helpful in toString methods and elsewhere.
 #define UNISTR_FROM_STRING_EXPLICIT
 
+#include "fphdlimp.h"
 #include "number_utypes.h"
 #include "numparse_types.h"
 #include "unicode/numberformatter.h"
@@ -189,8 +190,9 @@ unumf_resultGetAllFieldPositions(const UFormattedNumber* uresult, UFieldPosition
         return;
     }
 
-    auto* helper = reinterpret_cast<FieldPositionIterator*>(ufpositer);
-    result->string.getAllFieldPositions(*helper, *ec);
+    auto* fpi = reinterpret_cast<FieldPositionIterator*>(ufpositer);
+    FieldPositionIteratorHandler fpih(fpi, *ec);
+    result->string.getAllFieldPositions(fpih, *ec);
 }
 
 U_CAPI void U_EXPORT2
index 5e50837366c773244e85c7a6341114009c826b21..67ada4460fd5c729c04f5ec3b78a06eae77f9bce 100644 (file)
@@ -14,6 +14,7 @@
 #include "number_utils.h"
 #include "number_utypes.h"
 #include "util.h"
+#include "fphdlimp.h"
 
 using namespace icu;
 using namespace icu::number;
@@ -813,17 +814,16 @@ UBool FormattedNumber::nextFieldPosition(FieldPosition& fieldPosition, UErrorCod
 }
 
 void FormattedNumber::populateFieldPositionIterator(FieldPositionIterator& iterator, UErrorCode& status) {
-    if (U_FAILURE(status)) {
-        return;
-    }
-    if (fResults == nullptr) {
-        status = fErrorCode;
-        return;
-    }
-    fResults->string.getAllFieldPositions(iterator, status);
+    getAllFieldPositions(iterator, status);
 }
 
 void FormattedNumber::getAllFieldPositions(FieldPositionIterator& iterator, UErrorCode& status) const {
+    FieldPositionIteratorHandler fpih(&iterator, status);
+    getAllFieldPositionsImpl(fpih, status);
+}
+
+void FormattedNumber::getAllFieldPositionsImpl(FieldPositionIteratorHandler& fpih,
+                                               UErrorCode& status) const {
     if (U_FAILURE(status)) {
         return;
     }
@@ -831,7 +831,7 @@ void FormattedNumber::getAllFieldPositions(FieldPositionIterator& iterator, UErr
         status = fErrorCode;
         return;
     }
-    fResults->string.getAllFieldPositions(iterator, status);
+    fResults->string.getAllFieldPositions(fpih, status);
 }
 
 void FormattedNumber::getDecimalQuantity(DecimalQuantity& output, UErrorCode& status) const {
index a71e85e7c84050acfd9fe4b3fe0041a18b36b20f..37770d11d51dfba56f5516cb89056a77956dc7a8 100644 (file)
@@ -7,7 +7,6 @@
 
 #include "number_stringbuilder.h"
 #include "unicode/utf16.h"
-#include "uvectr32.h"
 
 using namespace icu;
 using namespace icu::number;
@@ -461,29 +460,18 @@ bool NumberStringBuilder::nextFieldPosition(FieldPosition& fp, UErrorCode& statu
     return seenStart;
 }
 
-void NumberStringBuilder::getAllFieldPositions(FieldPositionIterator& fpi, UErrorCode& status) const {
-    // TODO: Set an initial capacity on uvec?
-    LocalPointer <UVector32> uvec(new UVector32(status), status);
-    if (U_FAILURE(status)) {
-        return;
-    }
-
+void NumberStringBuilder::getAllFieldPositions(FieldPositionIteratorHandler& fpih,
+                                               UErrorCode& status) const {
     Field current = UNUM_FIELD_COUNT;
     int32_t currentStart = -1;
     for (int32_t i = 0; i < fLength; i++) {
         Field field = fieldAt(i);
         if (current == UNUM_INTEGER_FIELD && field == UNUM_GROUPING_SEPARATOR_FIELD) {
             // Special case: GROUPING_SEPARATOR counts as an INTEGER.
-            // Add the field, followed by the start index, followed by the end index to uvec.
-            uvec->addElement(UNUM_GROUPING_SEPARATOR_FIELD, status);
-            uvec->addElement(i, status);
-            uvec->addElement(i + 1, status);
+            fpih.addAttribute(UNUM_GROUPING_SEPARATOR_FIELD, i, i + 1);
         } else if (current != field) {
             if (current != UNUM_FIELD_COUNT) {
-                // Add the field, followed by the start index, followed by the end index to uvec.
-                uvec->addElement(current, status);
-                uvec->addElement(currentStart, status);
-                uvec->addElement(i, status);
+                fpih.addAttribute(current, currentStart, i);
             }
             current = field;
             currentStart = i;
@@ -493,14 +481,8 @@ void NumberStringBuilder::getAllFieldPositions(FieldPositionIterator& fpi, UErro
         }
     }
     if (current != UNUM_FIELD_COUNT) {
-        // Add the field, followed by the start index, followed by the end index to uvec.
-        uvec->addElement(current, status);
-        uvec->addElement(currentStart, status);
-        uvec->addElement(fLength, status);
+        fpih.addAttribute(current, currentStart, fLength);
     }
-
-    // Give uvec to the FieldPositionIterator, which adopts it.
-    fpi.setData(uvec.orphan(), status);
 }
 
 #endif /* #if !UCONFIG_NO_FORMATTING */
index 82e44e30f416d3e1484a7a1c5bf5d6a9bb377c50..cd8ce2f805e994f8fb1e3af67cb54b0dec593a3f 100644 (file)
@@ -14,6 +14,7 @@
 #include "cstring.h"
 #include "uassert.h"
 #include "number_types.h"
+#include "fphdlimp.h"
 
 U_NAMESPACE_BEGIN namespace number {
 namespace impl {
@@ -103,7 +104,7 @@ class U_I18N_API NumberStringBuilder : public UMemory {
 
     bool nextFieldPosition(FieldPosition& fp, UErrorCode& status) const;
 
-    void getAllFieldPositions(FieldPositionIterator& fpi, UErrorCode& status) const;
+    void getAllFieldPositions(FieldPositionIteratorHandler& fpih, UErrorCode& status) const;
 
   private:
     bool fUsingHeap = false;
index da653e4a6d993f023955792682aa0e9507d98729..ab6d5fab72c2dda61468e2c8c7718e1cd42cf0ec 100644 (file)
@@ -17,6 +17,7 @@
 #include "decContext.h"
 #include "decNumber.h"
 #include "double-conversion.h"
+#include "fphdlimp.h"
 #include "uresimp.h"
 #include "ureslocs.h"
 #include "number_utypes.h"
@@ -111,7 +112,8 @@ UnicodeString& LocalizedNumberFormatterAsFormat::format(const Formattable& obj,
     }
     appendTo.append(data.string.toTempUnicodeString());
     if (posIter != nullptr) {
-        data.string.getAllFieldPositions(*posIter, status);
+        FieldPositionIteratorHandler fpih(posIter, status);
+        data.string.getAllFieldPositions(fpih, status);
     }
     return appendTo;
 }
index e7d034ff10c890d141dcf4ebe0c740ed9dddb16f..407e04f8a12c071c3b780390f513dd21eb51d9aa 100644 (file)
@@ -2130,6 +2130,9 @@ class U_I18N_API DecimalFormat : public NumberFormat {
     static void fieldPositionHelper(const number::FormattedNumber& formatted, FieldPosition& fieldPosition,
                                     int32_t offset, UErrorCode& status);
 
+    static void fieldPositionIteratorHelper(const number::FormattedNumber& formatted,
+                                            FieldPositionIterator* fpi, int32_t offset, UErrorCode& status);
+
     void setupFastFormat();
 
     bool fastFormatDouble(double input, UnicodeString& output) const;
index 38ccd8feb30676bd596436e04a81d4d8288c46e3..d9c8eff511b8855c0869dfc1a7d9da7b0ec9ba89 100644 (file)
@@ -47,13 +47,6 @@ U_NAMESPACE_BEGIN
 
 class UVector32;
 
-// Forward declaration for number formatting:
-namespace number {
-namespace impl {
-class NumberStringBuilder;
-}
-}
-
 /**
  * FieldPositionIterator returns the field ids and their start/limit positions generated
  * by a call to Format::format.  See Format, NumberFormat, DecimalFormat.
@@ -114,7 +107,6 @@ private:
     void setData(UVector32 *adopt, UErrorCode& status);
 
     friend class FieldPositionIteratorHandler;
-    friend class number::impl::NumberStringBuilder;
 
     UVector32 *data;
     int32_t pos;
index 9f918e4bed115b9818c243cea0e03b3bfa1d02d0..4519d162030cdfcb5732269c04d1ee1272dfc7c1 100644 (file)
@@ -80,6 +80,7 @@ U_NAMESPACE_BEGIN
 
 // Forward declarations:
 class IFixedDecimal;
+class FieldPositionIteratorHandler;
 
 namespace numparse {
 namespace impl {
@@ -2515,6 +2516,12 @@ class U_I18N_API FormattedNumber : public UMemory {
      */
     void getDecimalQuantity(impl::DecimalQuantity& output, UErrorCode& status) const;
 
+    /**
+     * Populates the mutable builder type FieldPositionIteratorHandler.
+     * @internal
+     */
+    void getAllFieldPositionsImpl(FieldPositionIteratorHandler& fpih, UErrorCode& status) const;
+
 #endif
 
     // Don't allow copying of FormattedNumber, but moving is okay.
index 24a684dc0e8fcab389f266eddbe3330dfe52e930..cdda8dc3454e625a55845706b6d89757d62b9a98 100644 (file)
@@ -212,6 +212,7 @@ void NumberFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &n
   TESTCASE_AUTO(Test11913_BigDecimal);
   TESTCASE_AUTO(Test11020_RoundingInScientificNotation);
   TESTCASE_AUTO(Test11640_TripleCurrencySymbol);
+  TESTCASE_AUTO(Test13763_FieldPositionIteratorOffset);
   TESTCASE_AUTO_END;
 }
 
@@ -9048,4 +9049,22 @@ void NumberFormatTest::Test11640_TripleCurrencySymbol() {
                 "US dollars ", result);
 }
 
+
+void NumberFormatTest::Test13763_FieldPositionIteratorOffset() {
+    IcuTestErrorCode status(*this, "Test13763_FieldPositionIteratorOffset");
+    FieldPositionIterator fpi;
+    UnicodeString result(u"foo\U0001F4FBbar"); // 8 code units
+    LocalPointer<NumberFormat> nf(NumberFormat::createInstance("en", status));
+    nf->format(5142.3, result, &fpi, status);
+
+    int32_t expected[] = {
+      UNUM_GROUPING_SEPARATOR_FIELD, 9, 10,
+      UNUM_INTEGER_FIELD, 8, 13,
+      UNUM_DECIMAL_SEPARATOR_FIELD, 13, 14,
+      UNUM_FRACTION_FIELD, 14, 15,
+    };
+    int32_t tupleCount = UPRV_LENGTHOF(expected)/3;
+    expectPositions(fpi, expected, tupleCount, result);
+}
+
 #endif /* #if !UCONFIG_NO_FORMATTING */
index de4becea7e4a01c89c2d3d983d90583958d04324..f36a3abd6a86c58ae4677584b8449c9e3b91fefa 100644 (file)
@@ -276,6 +276,7 @@ class NumberFormatTest: public CalendarTimeZoneTest {
     void Test11913_BigDecimal();
     void Test11020_RoundingInScientificNotation();
     void Test11640_TripleCurrencySymbol();
+    void Test13763_FieldPositionIteratorOffset();
 
  private:
     UBool testFormattableAsUFormattable(const char *file, int line, Formattable &f);