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;
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;
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;
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;
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);
}
}
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;
}
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);
}
}
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);
}
// 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);
};
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;
};
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
// 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"
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
#include "number_utils.h"
#include "number_utypes.h"
#include "util.h"
+#include "fphdlimp.h"
using namespace icu;
using namespace icu::number;
}
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;
}
status = fErrorCode;
return;
}
- fResults->string.getAllFieldPositions(iterator, status);
+ fResults->string.getAllFieldPositions(fpih, status);
}
void FormattedNumber::getDecimalQuantity(DecimalQuantity& output, UErrorCode& status) const {
#include "number_stringbuilder.h"
#include "unicode/utf16.h"
-#include "uvectr32.h"
using namespace icu;
using namespace icu::number;
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;
}
}
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 */
#include "cstring.h"
#include "uassert.h"
#include "number_types.h"
+#include "fphdlimp.h"
U_NAMESPACE_BEGIN namespace number {
namespace impl {
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;
#include "decContext.h"
#include "decNumber.h"
#include "double-conversion.h"
+#include "fphdlimp.h"
#include "uresimp.h"
#include "ureslocs.h"
#include "number_utypes.h"
}
appendTo.append(data.string.toTempUnicodeString());
if (posIter != nullptr) {
- data.string.getAllFieldPositions(*posIter, status);
+ FieldPositionIteratorHandler fpih(posIter, status);
+ data.string.getAllFieldPositions(fpih, status);
}
return appendTo;
}
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;
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.
void setData(UVector32 *adopt, UErrorCode& status);
friend class FieldPositionIteratorHandler;
- friend class number::impl::NumberStringBuilder;
UVector32 *data;
int32_t pos;
// Forward declarations:
class IFixedDecimal;
+class FieldPositionIteratorHandler;
namespace numparse {
namespace impl {
*/
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.
TESTCASE_AUTO(Test11913_BigDecimal);
TESTCASE_AUTO(Test11020_RoundingInScientificNotation);
TESTCASE_AUTO(Test11640_TripleCurrencySymbol);
+ TESTCASE_AUTO(Test13763_FieldPositionIteratorOffset);
TESTCASE_AUTO_END;
}
"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 */
void Test11913_BigDecimal();
void Test11020_RoundingInScientificNotation();
void Test11640_TripleCurrencySymbol();
+ void Test13763_FieldPositionIteratorOffset();
private:
UBool testFormattableAsUFormattable(const char *file, int line, Formattable &f);