ICU-13763 Makes FieldPositionIterator offset by input string length in DecimalFormat, restoring ICU 61 behavior.

X-SVN-Rev: 41442
This commit is contained in:
Shane Carr 2018-05-23 21:08:53 +00:00
parent 49960567e6
commit 2af33b7796
13 changed files with 89 additions and 82 deletions

View 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);
}
}

View 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);
}

View 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

View 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

View 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 {

View 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 */

View 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;

View 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;
}

View 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;

View 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;

View 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.

View 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 */

View 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);