parent
fc6612cc56
commit
6edd38f35f
@ -519,7 +519,9 @@ UnicodeString& DecimalFormat::format(double number, UnicodeString& appendTo, Fie
|
||||
return appendTo;
|
||||
}
|
||||
UErrorCode localStatus = U_ZERO_ERROR;
|
||||
FormattedNumber output = fields->formatter.formatDouble(number, localStatus);
|
||||
UFormattedNumberData output;
|
||||
output.quantity.setToDouble(number);
|
||||
fields->formatter.formatImpl(&output, localStatus);
|
||||
fieldPositionHelper(output, pos, appendTo.length(), localStatus);
|
||||
auto appendable = UnicodeStringAppendable(appendTo);
|
||||
output.appendTo(appendable, localStatus);
|
||||
@ -540,7 +542,9 @@ UnicodeString& DecimalFormat::format(double number, UnicodeString& appendTo, Fie
|
||||
if (pos.getField() == FieldPosition::DONT_CARE && fastFormatDouble(number, appendTo)) {
|
||||
return appendTo;
|
||||
}
|
||||
FormattedNumber output = fields->formatter.formatDouble(number, status);
|
||||
UFormattedNumberData output;
|
||||
output.quantity.setToDouble(number);
|
||||
fields->formatter.formatImpl(&output, status);
|
||||
fieldPositionHelper(output, pos, appendTo.length(), status);
|
||||
auto appendable = UnicodeStringAppendable(appendTo);
|
||||
output.appendTo(appendable, status);
|
||||
@ -562,7 +566,9 @@ DecimalFormat::format(double number, UnicodeString& appendTo, FieldPositionItera
|
||||
if (posIter == nullptr && fastFormatDouble(number, appendTo)) {
|
||||
return appendTo;
|
||||
}
|
||||
FormattedNumber output = fields->formatter.formatDouble(number, status);
|
||||
UFormattedNumberData output;
|
||||
output.quantity.setToDouble(number);
|
||||
fields->formatter.formatImpl(&output, status);
|
||||
fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
|
||||
auto appendable = UnicodeStringAppendable(appendTo);
|
||||
output.appendTo(appendable, status);
|
||||
@ -593,7 +599,9 @@ UnicodeString& DecimalFormat::format(int64_t number, UnicodeString& appendTo, Fi
|
||||
return appendTo;
|
||||
}
|
||||
UErrorCode localStatus = U_ZERO_ERROR;
|
||||
FormattedNumber output = fields->formatter.formatInt(number, localStatus);
|
||||
UFormattedNumberData output;
|
||||
output.quantity.setToLong(number);
|
||||
fields->formatter.formatImpl(&output, localStatus);
|
||||
fieldPositionHelper(output, pos, appendTo.length(), localStatus);
|
||||
auto appendable = UnicodeStringAppendable(appendTo);
|
||||
output.appendTo(appendable, localStatus);
|
||||
@ -614,7 +622,9 @@ UnicodeString& DecimalFormat::format(int64_t number, UnicodeString& appendTo, Fi
|
||||
if (pos.getField() == FieldPosition::DONT_CARE && fastFormatInt64(number, appendTo)) {
|
||||
return appendTo;
|
||||
}
|
||||
FormattedNumber output = fields->formatter.formatInt(number, status);
|
||||
UFormattedNumberData output;
|
||||
output.quantity.setToLong(number);
|
||||
fields->formatter.formatImpl(&output, status);
|
||||
fieldPositionHelper(output, pos, appendTo.length(), status);
|
||||
auto appendable = UnicodeStringAppendable(appendTo);
|
||||
output.appendTo(appendable, status);
|
||||
@ -636,7 +646,9 @@ DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPositionIter
|
||||
if (posIter == nullptr && fastFormatInt64(number, appendTo)) {
|
||||
return appendTo;
|
||||
}
|
||||
FormattedNumber output = fields->formatter.formatInt(number, status);
|
||||
UFormattedNumberData output;
|
||||
output.quantity.setToLong(number);
|
||||
fields->formatter.formatImpl(&output, status);
|
||||
fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
|
||||
auto appendable = UnicodeStringAppendable(appendTo);
|
||||
output.appendTo(appendable, status);
|
||||
@ -655,7 +667,9 @@ DecimalFormat::format(StringPiece number, UnicodeString& appendTo, FieldPosition
|
||||
appendTo.setToBogus();
|
||||
return appendTo;
|
||||
}
|
||||
FormattedNumber output = fields->formatter.formatDecimal(number, status);
|
||||
UFormattedNumberData output;
|
||||
output.quantity.setToDecNumber(number, status);
|
||||
fields->formatter.formatImpl(&output, status);
|
||||
fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
|
||||
auto appendable = UnicodeStringAppendable(appendTo);
|
||||
output.appendTo(appendable, status);
|
||||
@ -673,7 +687,9 @@ UnicodeString& DecimalFormat::format(const DecimalQuantity& number, UnicodeStrin
|
||||
appendTo.setToBogus();
|
||||
return appendTo;
|
||||
}
|
||||
FormattedNumber output = fields->formatter.formatDecimalQuantity(number, status);
|
||||
UFormattedNumberData output;
|
||||
output.quantity = number;
|
||||
fields->formatter.formatImpl(&output, status);
|
||||
fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
|
||||
auto appendable = UnicodeStringAppendable(appendTo);
|
||||
output.appendTo(appendable, status);
|
||||
@ -692,7 +708,9 @@ DecimalFormat::format(const DecimalQuantity& number, UnicodeString& appendTo, Fi
|
||||
appendTo.setToBogus();
|
||||
return appendTo;
|
||||
}
|
||||
FormattedNumber output = fields->formatter.formatDecimalQuantity(number, status);
|
||||
UFormattedNumberData output;
|
||||
output.quantity = number;
|
||||
fields->formatter.formatImpl(&output, status);
|
||||
fieldPositionHelper(output, pos, appendTo.length(), status);
|
||||
auto appendable = UnicodeStringAppendable(appendTo);
|
||||
output.appendTo(appendable, status);
|
||||
@ -1703,8 +1721,11 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getCurrencyParser(UErrorC
|
||||
}
|
||||
|
||||
void
|
||||
DecimalFormat::fieldPositionHelper(const number::FormattedNumber& formatted, FieldPosition& fieldPosition,
|
||||
int32_t offset, UErrorCode& status) {
|
||||
DecimalFormat::fieldPositionHelper(
|
||||
const UFormattedNumberData& formatted,
|
||||
FieldPosition& fieldPosition,
|
||||
int32_t offset,
|
||||
UErrorCode& status) {
|
||||
if (U_FAILURE(status)) { return; }
|
||||
// always return first occurrence:
|
||||
fieldPosition.setBeginIndex(0);
|
||||
@ -1717,12 +1738,15 @@ DecimalFormat::fieldPositionHelper(const number::FormattedNumber& formatted, Fie
|
||||
}
|
||||
|
||||
void
|
||||
DecimalFormat::fieldPositionIteratorHelper(const number::FormattedNumber& formatted, FieldPositionIterator* fpi,
|
||||
int32_t offset, UErrorCode& status) {
|
||||
DecimalFormat::fieldPositionIteratorHelper(
|
||||
const UFormattedNumberData& formatted,
|
||||
FieldPositionIterator* fpi,
|
||||
int32_t offset,
|
||||
UErrorCode& status) {
|
||||
if (U_SUCCESS(status) && (fpi != nullptr)) {
|
||||
FieldPositionIteratorHandler fpih(fpi, status);
|
||||
fpih.setShift(offset);
|
||||
formatted.getAllFieldPositionsImpl(fpih, status);
|
||||
formatted.getAllFieldPositions(fpih, status);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,8 +62,9 @@ class FieldPositionOnlyHandler : public FieldPositionHandler {
|
||||
|
||||
|
||||
// utility subclass FieldPositionIteratorHandler
|
||||
// exported as U_I18N_API for tests
|
||||
|
||||
class FieldPositionIteratorHandler : public FieldPositionHandler {
|
||||
class U_I18N_API FieldPositionIteratorHandler : public FieldPositionHandler {
|
||||
FieldPositionIterator* iter; // can be NULL
|
||||
UVector32* vec;
|
||||
UErrorCode status;
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "uassert.h"
|
||||
#include "unicode/numberformatter.h"
|
||||
#include "number_longnames.h"
|
||||
#include "number_utypes.h"
|
||||
|
||||
#include "sharednumberformat.h"
|
||||
#include "sharedpluralrules.h"
|
||||
@ -47,6 +48,8 @@
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
using number::impl::UFormattedNumberData;
|
||||
|
||||
static constexpr int32_t WIDTH_INDEX_COUNT = UMEASFMT_WIDTH_NARROW + 1;
|
||||
|
||||
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MeasureFormat)
|
||||
@ -504,12 +507,13 @@ UnicodeString &MeasureFormat::formatMeasurePerUnit(
|
||||
status = U_UNSUPPORTED_ERROR;
|
||||
return appendTo;
|
||||
}
|
||||
number::FormattedNumber result;
|
||||
UFormattedNumberData result;
|
||||
if (auto* lnf = df->toNumberFormatter(status)) {
|
||||
result = lnf->unit(measure.getUnit())
|
||||
result.quantity.setToDouble(measure.getNumber().getDouble(status));
|
||||
lnf->unit(measure.getUnit())
|
||||
.perUnit(perUnit)
|
||||
.unitWidth(getUnitWidth(fWidth))
|
||||
.formatDouble(measure.getNumber().getDouble(status), status);
|
||||
.formatImpl(&result, status);
|
||||
}
|
||||
DecimalFormat::fieldPositionHelper(result, pos, appendTo.length(), status);
|
||||
appendTo.append(result.toTempString(status));
|
||||
@ -699,11 +703,12 @@ UnicodeString &MeasureFormat::formatMeasure(
|
||||
SimpleFormatter formatter(pattern, 0, 1, status);
|
||||
return QuantityFormatter::format(formatter, formattedNumber, appendTo, pos, status);
|
||||
}
|
||||
number::FormattedNumber result;
|
||||
UFormattedNumberData result;
|
||||
if (auto* lnf = df->toNumberFormatter(status)) {
|
||||
result = lnf->unit(amtUnit)
|
||||
result.quantity.setToDouble(amtNumber.getDouble(status));
|
||||
lnf->unit(amtUnit)
|
||||
.unitWidth(getUnitWidth(fWidth))
|
||||
.formatDouble(amtNumber.getDouble(status), status);
|
||||
.formatImpl(&result, status);
|
||||
}
|
||||
DecimalFormat::fieldPositionHelper(result, pos, appendTo.length(), status);
|
||||
appendTo.append(result.toTempString(status));
|
||||
|
@ -156,7 +156,7 @@ unumf_resultToString(const UFormattedNumber* uresult, UChar* buffer, int32_t buf
|
||||
return 0;
|
||||
}
|
||||
|
||||
return result->fImpl.toTempString(*ec).extract(buffer, bufferCapacity, *ec);
|
||||
return result->fData.toTempString(*ec).extract(buffer, bufferCapacity, *ec);
|
||||
}
|
||||
|
||||
U_CAPI UBool U_EXPORT2
|
||||
@ -173,7 +173,7 @@ unumf_resultNextFieldPosition(const UFormattedNumber* uresult, UFieldPosition* u
|
||||
fp.setField(ufpos->field);
|
||||
fp.setBeginIndex(ufpos->beginIndex);
|
||||
fp.setEndIndex(ufpos->endIndex);
|
||||
bool retval = result->fImpl.nextFieldPosition(fp, *ec);
|
||||
bool retval = result->fData.nextFieldPosition(fp, *ec);
|
||||
ufpos->beginIndex = fp.getBeginIndex();
|
||||
ufpos->endIndex = fp.getEndIndex();
|
||||
// NOTE: MSVC sometimes complains when implicitly converting between bool and UBool
|
||||
@ -192,7 +192,8 @@ unumf_resultGetAllFieldPositions(const UFormattedNumber* uresult, UFieldPosition
|
||||
}
|
||||
|
||||
auto* fpi = reinterpret_cast<FieldPositionIterator*>(ufpositer);
|
||||
result->fImpl.getAllFieldPositions(*fpi, *ec);
|
||||
FieldPositionIteratorHandler fpih(fpi, *ec);
|
||||
result->fData.getAllFieldPositions(fpih, *ec);
|
||||
}
|
||||
|
||||
U_CAPI void U_EXPORT2
|
||||
|
@ -19,16 +19,6 @@ UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(FormattedNumber)
|
||||
|
||||
#define UPRV_NOARG
|
||||
|
||||
UBool FormattedNumber::nextFieldPosition(FieldPosition& fieldPosition, UErrorCode& status) const {
|
||||
UPRV_FORMATTED_VALUE_METHOD_GUARD(FALSE)
|
||||
return fData->nextFieldPosition(fieldPosition, status);
|
||||
}
|
||||
|
||||
void FormattedNumber::getAllFieldPositions(FieldPositionIterator& iterator, UErrorCode& status) const {
|
||||
FieldPositionIteratorHandler fpih(&iterator, status);
|
||||
getAllFieldPositionsImpl(fpih, status);
|
||||
}
|
||||
|
||||
void FormattedNumber::toDecimalNumber(ByteSink& sink, UErrorCode& status) const {
|
||||
UPRV_FORMATTED_VALUE_METHOD_GUARD(UPRV_NOARG)
|
||||
impl::DecNum decnum;
|
||||
|
@ -30,8 +30,10 @@ 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.
|
||||
*
|
||||
* Exported as U_I18N_API for tests
|
||||
*/
|
||||
class UFormattedNumberData : public FormattedValueStringBuilderImpl {
|
||||
class U_I18N_API UFormattedNumberData : public FormattedValueStringBuilderImpl {
|
||||
public:
|
||||
UFormattedNumberData() : FormattedValueStringBuilderImpl(kUndefinedField) {}
|
||||
virtual ~UFormattedNumberData();
|
||||
|
@ -379,23 +379,6 @@ UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(FormattedNumberRange)
|
||||
|
||||
#define UPRV_NOARG
|
||||
|
||||
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->nextFieldPosition(fieldPosition, status);
|
||||
}
|
||||
|
||||
void FormattedNumberRange::getAllFieldPositions(FieldPositionIterator& iterator, UErrorCode& status) const {
|
||||
FieldPositionIteratorHandler fpih(&iterator, status);
|
||||
getAllFieldPositionsImpl(fpih, status);
|
||||
}
|
||||
|
||||
void FormattedNumberRange::getAllFieldPositionsImpl(
|
||||
FieldPositionIteratorHandler& fpih, UErrorCode& status) const {
|
||||
UPRV_FORMATTED_VALUE_METHOD_GUARD(UPRV_NOARG)
|
||||
fData->getAllFieldPositions(fpih, status);
|
||||
}
|
||||
|
||||
UnicodeString FormattedNumberRange::getFirstDecimal(UErrorCode& status) const {
|
||||
UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString())
|
||||
return fData->quantity1.toScientificString();
|
||||
|
@ -53,10 +53,10 @@ class CompactDecimalFormat;
|
||||
|
||||
namespace number {
|
||||
class LocalizedNumberFormatter;
|
||||
class FormattedNumber;
|
||||
namespace impl {
|
||||
class DecimalQuantity;
|
||||
struct DecimalFormatFields;
|
||||
class UFormattedNumberData;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2168,11 +2168,17 @@ class U_I18N_API DecimalFormat : public NumberFormat {
|
||||
|
||||
const numparse::impl::NumberParserImpl* getCurrencyParser(UErrorCode& status) const;
|
||||
|
||||
static void fieldPositionHelper(const number::FormattedNumber& formatted, FieldPosition& fieldPosition,
|
||||
int32_t offset, UErrorCode& status);
|
||||
static void fieldPositionHelper(
|
||||
const number::impl::UFormattedNumberData& formatted,
|
||||
FieldPosition& fieldPosition,
|
||||
int32_t offset,
|
||||
UErrorCode& status);
|
||||
|
||||
static void fieldPositionIteratorHelper(const number::FormattedNumber& formatted,
|
||||
FieldPositionIterator* fpi, int32_t offset, UErrorCode& status);
|
||||
static void fieldPositionIteratorHelper(
|
||||
const number::impl::UFormattedNumberData& formatted,
|
||||
FieldPositionIterator* fpi,
|
||||
int32_t offset,
|
||||
UErrorCode& status);
|
||||
|
||||
void setupFastFormat();
|
||||
|
||||
|
@ -2490,60 +2490,6 @@ class U_I18N_API FormattedNumber : public UMemory, public FormattedValue {
|
||||
/** @copydoc FormattedValue::nextPosition() */
|
||||
UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const U_OVERRIDE;
|
||||
|
||||
#ifndef U_HIDE_DRAFT_API
|
||||
/**
|
||||
* Determines the start (inclusive) and end (exclusive) indices of the next occurrence of the given
|
||||
* <em>field</em> in the output string. This allows you to determine the locations of, for example,
|
||||
* the integer part, fraction part, or symbols.
|
||||
*
|
||||
* This is a simpler but less powerful alternative to {@link #nextPosition}.
|
||||
*
|
||||
* If a field occurs just once, calling this method will find that occurrence and return it. If a
|
||||
* field occurs multiple times, this method may be called repeatedly with the following pattern:
|
||||
*
|
||||
* <pre>
|
||||
* FieldPosition fpos(UNUM_GROUPING_SEPARATOR_FIELD);
|
||||
* while (formattedNumber.nextFieldPosition(fpos, status)) {
|
||||
* // do something with fpos.
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* This method is useful if you know which field to query. If you want all available field position
|
||||
* information, use {@link #nextPosition} or {@link #getAllFieldPositions}.
|
||||
*
|
||||
* @param fieldPosition
|
||||
* Input+output variable. On input, the "field" property determines which field to look
|
||||
* up, and the "beginIndex" and "endIndex" properties determine where to begin the search.
|
||||
* On output, the "beginIndex" is set to the beginning of the first occurrence of the
|
||||
* field with either begin or end indices after the input indices; "endIndex" is set to
|
||||
* the end of that occurrence of the field (exclusive index). If a field position is not
|
||||
* found, the method returns FALSE and the FieldPosition may or may not be changed.
|
||||
* @param status
|
||||
* Set if an error occurs while populating the FieldPosition.
|
||||
* @return TRUE if a new occurrence of the field was found; FALSE otherwise.
|
||||
* @draft ICU 62
|
||||
* @see UNumberFormatFields
|
||||
*/
|
||||
UBool nextFieldPosition(FieldPosition& fieldPosition, UErrorCode& status) const;
|
||||
|
||||
/**
|
||||
* Export the formatted number to a FieldPositionIterator. This allows you to determine which characters in
|
||||
* the output string correspond to which <em>fields</em>, such as the integer part, fraction part, and sign.
|
||||
*
|
||||
* This is an alternative to the more powerful #nextPosition() API.
|
||||
*
|
||||
* If information on only one field is needed, use #nextPosition() or #nextFieldPosition() instead.
|
||||
*
|
||||
* @param iterator
|
||||
* The FieldPositionIterator to populate with all of the fields present in the formatted number.
|
||||
* @param status
|
||||
* Set if an error occurs while populating the FieldPositionIterator.
|
||||
* @draft ICU 62
|
||||
* @see UNumberFormatFields
|
||||
*/
|
||||
void getAllFieldPositions(FieldPositionIterator &iterator, UErrorCode &status) const;
|
||||
#endif /* U_HIDE_DRAFT_API */
|
||||
|
||||
#ifndef U_HIDE_DRAFT_API
|
||||
/**
|
||||
* Export the formatted number as a "numeric string" conforming to the
|
||||
|
@ -728,52 +728,6 @@ class U_I18N_API FormattedNumberRange : public UMemory, public FormattedValue {
|
||||
UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const U_OVERRIDE;
|
||||
|
||||
#ifndef U_HIDE_DRAFT_API
|
||||
/**
|
||||
* Determines the start (inclusive) and end (exclusive) indices of the next occurrence of the given
|
||||
* <em>field</em> in the output string. This allows you to determine the locations of, for example,
|
||||
* the integer part, fraction part, or symbols.
|
||||
*
|
||||
* If both sides of the range have the same field, the field will occur twice, once before the
|
||||
* range separator and once after the range separator, if applicable.
|
||||
*
|
||||
* If a field occurs just once, calling this method will find that occurrence and return it. If a
|
||||
* field occurs multiple times, this method may be called repeatedly with the following pattern:
|
||||
*
|
||||
* <pre>
|
||||
* FieldPosition fpos(UNUM_INTEGER_FIELD);
|
||||
* while (formattedNumberRange.nextFieldPosition(fpos, status)) {
|
||||
* // do something with fpos.
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* This method is useful if you know which field to query. If you want all available field position
|
||||
* information, use #getAllFieldPositions().
|
||||
*
|
||||
* @param fieldPosition
|
||||
* Input+output variable. See {@link FormattedNumber#nextFieldPosition}.
|
||||
* @param status
|
||||
* Set if an error occurs while populating the FieldPosition.
|
||||
* @return TRUE if a new occurrence of the field was found; FALSE otherwise.
|
||||
* @draft ICU 63
|
||||
* @see UNumberFormatFields
|
||||
*/
|
||||
UBool nextFieldPosition(FieldPosition& fieldPosition, UErrorCode& status) const;
|
||||
|
||||
/**
|
||||
* Export the formatted number range to a FieldPositionIterator. This allows you to determine which characters in
|
||||
* the output string correspond to which <em>fields</em>, such as the integer part, fraction part, and sign.
|
||||
*
|
||||
* If information on only one field is needed, use #nextFieldPosition() instead.
|
||||
*
|
||||
* @param iterator
|
||||
* The FieldPositionIterator to populate with all of the fields present in the formatted number.
|
||||
* @param status
|
||||
* Set if an error occurs while populating the FieldPositionIterator.
|
||||
* @draft ICU 63
|
||||
* @see UNumberFormatFields
|
||||
*/
|
||||
void getAllFieldPositions(FieldPositionIterator &iterator, UErrorCode &status) const;
|
||||
|
||||
/**
|
||||
* Export the first formatted number as a decimal number. This endpoint
|
||||
* is useful for obtaining the exact number being printed after scaling
|
||||
|
@ -427,7 +427,7 @@ typedef struct UFormattedNumber UFormattedNumber;
|
||||
* NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead.
|
||||
*
|
||||
* @param skeleton The skeleton string, like u"percent precision-integer"
|
||||
* @param skeletonLen The number of UChars in the skeleton string, or -1 it it is NUL-terminated.
|
||||
* @param skeletonLen The number of UChars in the skeleton string, or -1 if it is NUL-terminated.
|
||||
* @param locale The NUL-terminated locale ID.
|
||||
* @param ec Set if an error occurs.
|
||||
* @stable ICU 62
|
||||
@ -443,7 +443,7 @@ unumf_openForSkeletonAndLocale(const UChar* skeleton, int32_t skeletonLen, const
|
||||
* location of a skeleton syntax error if such a syntax error exists.
|
||||
*
|
||||
* @param skeleton The skeleton string, like u"percent precision-integer"
|
||||
* @param skeletonLen The number of UChars in the skeleton string, or -1 it it is NUL-terminated.
|
||||
* @param skeletonLen The number of UChars in the skeleton string, or -1 if it is NUL-terminated.
|
||||
* @param locale The NUL-terminated locale ID.
|
||||
* @param perror A parse error struct populated if an error occurs when parsing. Can be NULL.
|
||||
* If no error occurs, perror->offset will be set to -1.
|
||||
|
@ -16,6 +16,9 @@
|
||||
#include "number_utils.h"
|
||||
#include "numbertest.h"
|
||||
#include "unicode/utypes.h"
|
||||
#include "number_utypes.h"
|
||||
|
||||
using number::impl::UFormattedNumberData;
|
||||
|
||||
// Horrible workaround for the lack of a status code in the constructor...
|
||||
// (Also affects numbertest_range.cpp)
|
||||
@ -2730,9 +2733,10 @@ void NumberFormatterApiTest::fieldPositionLogic() {
|
||||
UPRV_LENGTHOF(expectedFieldPositions));
|
||||
|
||||
// Test the iteration functionality of nextFieldPosition
|
||||
FieldPosition actual = {UNUM_GROUPING_SEPARATOR_FIELD};
|
||||
ConstrainedFieldPosition actual;
|
||||
actual.constrainField(UFIELD_CATEGORY_NUMBER, UNUM_GROUPING_SEPARATOR_FIELD);
|
||||
int32_t i = 1;
|
||||
while (fmtd.nextFieldPosition(actual, status)) {
|
||||
while (fmtd.nextPosition(actual, status)) {
|
||||
UFieldPosition expected = expectedFieldPositions[i++];
|
||||
assertEquals(
|
||||
UnicodeString(u"Next for grouping, field, case #") + Int64ToUnicodeString(i),
|
||||
@ -2741,18 +2745,19 @@ void NumberFormatterApiTest::fieldPositionLogic() {
|
||||
assertEquals(
|
||||
UnicodeString(u"Next for grouping, begin index, case #") + Int64ToUnicodeString(i),
|
||||
expected.beginIndex,
|
||||
actual.getBeginIndex());
|
||||
actual.getStart());
|
||||
assertEquals(
|
||||
UnicodeString(u"Next for grouping, end index, case #") + Int64ToUnicodeString(i),
|
||||
expected.endIndex,
|
||||
actual.getEndIndex());
|
||||
actual.getLimit());
|
||||
}
|
||||
assertEquals(u"Should have seen all grouping separators", 4, i);
|
||||
|
||||
// Make sure strings without fraction do not contain fraction field
|
||||
actual = {UNUM_FRACTION_FIELD};
|
||||
actual.reset();
|
||||
actual.constrainField(UFIELD_CATEGORY_NUMBER, UNUM_FRACTION_FIELD);
|
||||
fmtd = NumberFormatter::withLocale("en").formatInt(5, status);
|
||||
assertFalse(u"No fraction part in an integer", fmtd.nextFieldPosition(actual, status));
|
||||
assertFalse(u"No fraction part in an integer", fmtd.nextPosition(actual, status));
|
||||
}
|
||||
|
||||
void NumberFormatterApiTest::fieldPositionCoverage() {
|
||||
@ -3064,10 +3069,18 @@ void NumberFormatterApiTest::toFormat() {
|
||||
dynamic_cast<LocalizedNumberFormatterAsFormat*>(format.getAlias())->getNumberFormatter()
|
||||
.toSkeleton(status));
|
||||
|
||||
UFormattedNumberData result;
|
||||
result.quantity.setToDouble(514.23);
|
||||
lnf.formatImpl(&result, status);
|
||||
FieldPositionIterator fpi1;
|
||||
lnf.formatDouble(514.23, status).getAllFieldPositions(fpi1, status);
|
||||
{
|
||||
FieldPositionIteratorHandler fpih(&fpi1, status);
|
||||
result.getAllFieldPositions(fpih, status);
|
||||
}
|
||||
|
||||
FieldPositionIterator fpi2;
|
||||
format->format(514.23, sb.remove(), &fpi2, status);
|
||||
|
||||
assertTrue("Should produce same field position iterator", fpi1 == fpi2);
|
||||
}
|
||||
|
||||
@ -3119,19 +3132,20 @@ void NumberFormatterApiTest::errors() {
|
||||
"Terminal toSkeleton on error object should be bogus",
|
||||
output.isBogus());
|
||||
|
||||
// FieldPosition
|
||||
// FieldPosition (constrained category)
|
||||
status = U_ZERO_ERROR;
|
||||
FieldPosition fp;
|
||||
fn.nextFieldPosition(fp, status);
|
||||
ConstrainedFieldPosition fp;
|
||||
fp.constrainCategory(UFIELD_CATEGORY_NUMBER);
|
||||
fn.nextPosition(fp, status);
|
||||
assertEquals(
|
||||
"Should fail on FieldPosition terminal method with correct error code",
|
||||
U_NUMBER_ARG_OUTOFBOUNDS_ERROR,
|
||||
status);
|
||||
|
||||
// FieldPositionIterator
|
||||
// FieldPositionIterator (no constraints)
|
||||
status = U_ZERO_ERROR;
|
||||
FieldPositionIterator fpi;
|
||||
fn.getAllFieldPositions(fpi, status);
|
||||
fp.reset();
|
||||
fn.nextPosition(fp, status);
|
||||
assertEquals(
|
||||
"Should fail on FieldPositoinIterator terminal method with correct error code",
|
||||
U_NUMBER_ARG_OUTOFBOUNDS_ERROR,
|
||||
@ -3592,64 +3606,6 @@ void NumberFormatterApiTest::assertNumberFieldPositions(
|
||||
UFIELD_CATEGORY_NUMBER,
|
||||
expectedFieldPositions,
|
||||
length);
|
||||
|
||||
// Check FormattedNumber-specific functions
|
||||
UnicodeString baseMessage = UnicodeString(message) + u": " + formattedNumber.toString(status) + u": ";
|
||||
FieldPositionIterator fpi;
|
||||
formattedNumber.getAllFieldPositions(fpi, status);
|
||||
int32_t i = 0;
|
||||
FieldPosition actual;
|
||||
while (fpi.next(actual)) {
|
||||
UFieldPosition expected = expectedFieldPositions[i++];
|
||||
assertEquals(
|
||||
baseMessage + UnicodeString(u"Field, case #") + Int64ToUnicodeString(i),
|
||||
expected.field,
|
||||
actual.getField());
|
||||
assertEquals(
|
||||
baseMessage + UnicodeString(u"Iterator, begin, case #") + Int64ToUnicodeString(i),
|
||||
expected.beginIndex,
|
||||
actual.getBeginIndex());
|
||||
assertEquals(
|
||||
baseMessage + UnicodeString(u"Iterator, end, case #") + Int64ToUnicodeString(i),
|
||||
expected.endIndex,
|
||||
actual.getEndIndex());
|
||||
|
||||
// Check for the first location of the field
|
||||
FieldPosition actual2(expected.field);
|
||||
// Fast-forward the field to skip previous occurrences of the field:
|
||||
actual2.setBeginIndex(expected.beginIndex);
|
||||
actual2.setEndIndex(expected.beginIndex);
|
||||
UBool found = formattedNumber.nextFieldPosition(actual2, status);
|
||||
assertEquals(
|
||||
baseMessage + UnicodeString(u"Next, found first, case #") + Int64ToUnicodeString(i),
|
||||
(UBool) TRUE,
|
||||
found);
|
||||
assertEquals(
|
||||
baseMessage + UnicodeString(u"Next, begin, case #") + Int64ToUnicodeString(i),
|
||||
expected.beginIndex,
|
||||
actual2.getBeginIndex());
|
||||
assertEquals(
|
||||
baseMessage + UnicodeString(u"Next, end, case #") + Int64ToUnicodeString(i),
|
||||
expected.endIndex,
|
||||
actual2.getEndIndex());
|
||||
|
||||
// The next position should be empty unless the field occurs again
|
||||
UBool occursAgain = false;
|
||||
for (int32_t j=i; j<length; j++) {
|
||||
if (expectedFieldPositions[j].field == expected.field) {
|
||||
occursAgain = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!occursAgain) {
|
||||
found = formattedNumber.nextFieldPosition(actual2, status);
|
||||
assertEquals(
|
||||
baseMessage + UnicodeString(u"Next, found second, case #") + Int64ToUnicodeString(i),
|
||||
(UBool) FALSE,
|
||||
found);
|
||||
}
|
||||
}
|
||||
assertEquals(baseMessage + u"Should have seen every field position", length, i);
|
||||
}
|
||||
|
||||
|
||||
|
@ -12,7 +12,9 @@ import java.text.FieldPosition;
|
||||
import java.text.Format;
|
||||
import java.text.ParsePosition;
|
||||
|
||||
import com.ibm.icu.number.FormattedNumber;
|
||||
import com.ibm.icu.impl.FormattedStringBuilder;
|
||||
import com.ibm.icu.impl.FormattedValueStringBuilderImpl;
|
||||
import com.ibm.icu.impl.Utility;
|
||||
import com.ibm.icu.number.LocalizedNumberFormatter;
|
||||
import com.ibm.icu.number.NumberFormatter;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
@ -46,16 +48,18 @@ public class LocalizedNumberFormatterAsFormat extends Format {
|
||||
if (!(obj instanceof Number)) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
FormattedNumber result = formatter.format((Number) obj);
|
||||
DecimalQuantity dq = new DecimalQuantity_DualStorageBCD((Number) obj);
|
||||
FormattedStringBuilder string = new FormattedStringBuilder();
|
||||
formatter.formatImpl(dq, string);
|
||||
// always return first occurrence:
|
||||
pos.setBeginIndex(0);
|
||||
pos.setEndIndex(0);
|
||||
boolean found = result.nextFieldPosition(pos);
|
||||
boolean found = FormattedValueStringBuilderImpl.nextFieldPosition(string, pos);
|
||||
if (found && toAppendTo.length() != 0) {
|
||||
pos.setBeginIndex(pos.getBeginIndex() + toAppendTo.length());
|
||||
pos.setEndIndex(pos.getEndIndex() + toAppendTo.length());
|
||||
}
|
||||
result.appendTo(toAppendTo);
|
||||
Utility.appendTo(string, toAppendTo);
|
||||
return toAppendTo;
|
||||
}
|
||||
|
||||
|
@ -4,8 +4,6 @@ package com.ibm.icu.number;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.AttributedCharacterIterator;
|
||||
import java.text.FieldPosition;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.ibm.icu.impl.FormattedStringBuilder;
|
||||
import com.ibm.icu.impl.FormattedValueStringBuilderImpl;
|
||||
@ -107,44 +105,6 @@ public class FormattedNumber implements FormattedValue {
|
||||
return FormattedValueStringBuilderImpl.toCharacterIterator(string, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the start (inclusive) and end (exclusive) indices of the next occurrence of the
|
||||
* given <em>field</em> in the output string. This allows you to determine the locations of,
|
||||
* for example, the integer part, fraction part, or symbols.
|
||||
* <p>
|
||||
* This is a simpler but less powerful alternative to {@link #nextPosition}.
|
||||
* <p>
|
||||
* If a field occurs just once, calling this method will find that occurrence and return it. If a
|
||||
* field occurs multiple times, this method may be called repeatedly with the following pattern:
|
||||
*
|
||||
* <pre>
|
||||
* FieldPosition fpos = new FieldPosition(NumberFormat.Field.GROUPING_SEPARATOR);
|
||||
* while (formattedNumber.nextFieldPosition(fpos, status)) {
|
||||
* // do something with fpos.
|
||||
* }
|
||||
* </pre>
|
||||
* <p>
|
||||
* This method is useful if you know which field to query. If you want all available field position
|
||||
* information, use {@link #nextPosition} or {@link #toCharacterIterator()}.
|
||||
*
|
||||
* @param fieldPosition
|
||||
* Input+output variable. On input, the "field" property determines which field to look
|
||||
* up, and the "beginIndex" and "endIndex" properties determine where to begin the search.
|
||||
* On output, the "beginIndex" is set to the beginning of the first occurrence of the
|
||||
* field with either begin or end indices after the input indices, "endIndex" is set to
|
||||
* the end of that occurrence of the field (exclusive index). If a field position is not
|
||||
* found, the method returns FALSE and the FieldPosition may or may not be changed.
|
||||
* @return true if a new occurrence of the field was found; false otherwise.
|
||||
* @draft ICU 62
|
||||
* @provisional This API might change or be removed in a future release.
|
||||
* @see com.ibm.icu.text.NumberFormat.Field
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public boolean nextFieldPosition(FieldPosition fieldPosition) {
|
||||
fq.populateUFieldPosition(fieldPosition);
|
||||
return FormattedValueStringBuilderImpl.nextFieldPosition(string, fieldPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Export the formatted number as a BigDecimal. This endpoint is useful for obtaining the exact
|
||||
* number being printed after scaling and rounding have been applied by the number formatting
|
||||
@ -166,41 +126,4 @@ public class FormattedNumber implements FormattedValue {
|
||||
public IFixedDecimal getFixedDecimal() {
|
||||
return fq;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @draft ICU 60
|
||||
* @provisional This API might change or be removed in a future release.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// 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())
|
||||
^ fq.toBigDecimal().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @draft ICU 60
|
||||
* @provisional This API might change or be removed in a future release.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other)
|
||||
return true;
|
||||
if (other == null)
|
||||
return false;
|
||||
if (!(other instanceof FormattedNumber))
|
||||
return false;
|
||||
// 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())
|
||||
&& Arrays.equals(string.toFieldArray(), _other.string.toFieldArray())
|
||||
&& fq.toBigDecimal().equals(_other.fq.toBigDecimal());
|
||||
}
|
||||
}
|
@ -5,7 +5,6 @@ package com.ibm.icu.number;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.text.AttributedCharacterIterator;
|
||||
import java.text.FieldPosition;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.ibm.icu.impl.FormattedStringBuilder;
|
||||
@ -110,39 +109,6 @@ public class FormattedNumberRange implements FormattedValue {
|
||||
return FormattedValueStringBuilderImpl.nextPosition(string, cfpos, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the start (inclusive) and end (exclusive) indices of the next occurrence of the given
|
||||
* <em>field</em> in the output string. This allows you to determine the locations of, for example,
|
||||
* the integer part, fraction part, or symbols.
|
||||
* <p>
|
||||
* If both sides of the range have the same field, the field will occur twice, once before the range separator and
|
||||
* once after the range separator, if applicable.
|
||||
* <p>
|
||||
* If a field occurs just once, calling this method will find that occurrence and return it. If a field occurs
|
||||
* multiple times, this method may be called repeatedly with the following pattern:
|
||||
*
|
||||
* <pre>
|
||||
* FieldPosition fpos = new FieldPosition(NumberFormat.Field.INTEGER);
|
||||
* while (formattedNumberRange.nextFieldPosition(fpos, status)) {
|
||||
* // do something with fpos.
|
||||
* }
|
||||
* </pre>
|
||||
* <p>
|
||||
* This method is useful if you know which field to query. If you want all available field position information, use
|
||||
* {@link #toCharacterIterator()}.
|
||||
*
|
||||
* @param fieldPosition
|
||||
* Input+output variable. See {@link FormattedNumber#nextFieldPosition(FieldPosition)}.
|
||||
* @return true if a new occurrence of the field was found; false otherwise.
|
||||
* @draft ICU 63
|
||||
* @provisional This API might change or be removed in a future release.
|
||||
* @see com.ibm.icu.text.NumberFormat.Field
|
||||
* @see NumberRangeFormatter
|
||||
*/
|
||||
public boolean nextFieldPosition(FieldPosition fieldPosition) {
|
||||
return FormattedValueStringBuilderImpl.nextFieldPosition(string, fieldPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
|
@ -97,20 +97,11 @@ public class LocalizedNumberFormatter extends NumberFormatterSettings<LocalizedN
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public FormattedNumber format(Measure input) {
|
||||
DecimalQuantity fq = new DecimalQuantity_DualStorageBCD(input.getNumber());
|
||||
MeasureUnit unit = input.getUnit();
|
||||
Number number = input.getNumber();
|
||||
// Use this formatter if possible
|
||||
if (Objects.equals(resolve().unit, unit)) {
|
||||
return format(number);
|
||||
}
|
||||
// This mechanism saves the previously used unit, so if the user calls this method with the
|
||||
// same unit multiple times in a row, they get a more efficient code path.
|
||||
LocalizedNumberFormatter withUnit = savedWithUnit;
|
||||
if (withUnit == null || !Objects.equals(withUnit.resolve().unit, unit)) {
|
||||
withUnit = new LocalizedNumberFormatter(this, KEY_UNIT, unit);
|
||||
savedWithUnit = withUnit;
|
||||
}
|
||||
return withUnit.format(number);
|
||||
FormattedStringBuilder string = new FormattedStringBuilder();
|
||||
formatImpl(fq, unit, string);
|
||||
return new FormattedNumber(string, fq);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -161,6 +152,29 @@ public class LocalizedNumberFormatter extends NumberFormatterSettings<LocalizedN
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Version of above for unit override.
|
||||
*
|
||||
* @internal
|
||||
* @deprecated ICU 67 This API is ICU internal only.
|
||||
*/
|
||||
@Deprecated
|
||||
public void formatImpl(DecimalQuantity fq, MeasureUnit unit, FormattedStringBuilder string) {
|
||||
// Use this formatter if possible
|
||||
if (Objects.equals(resolve().unit, unit)) {
|
||||
formatImpl(fq, string);
|
||||
return;
|
||||
}
|
||||
// This mechanism saves the previously used unit, so if the user calls this method with the
|
||||
// same unit multiple times in a row, they get a more efficient code path.
|
||||
LocalizedNumberFormatter withUnit = savedWithUnit;
|
||||
if (withUnit == null || !Objects.equals(withUnit.resolve().unit, unit)) {
|
||||
withUnit = new LocalizedNumberFormatter(this, KEY_UNIT, unit);
|
||||
savedWithUnit = withUnit;
|
||||
}
|
||||
withUnit.formatImpl(fq, string);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated This API is ICU internal only. Use {@link FormattedNumber#nextPosition}
|
||||
|
@ -346,25 +346,13 @@ public abstract class Precision implements Cloneable {
|
||||
if (this.mathContext.equals(mathContext)) {
|
||||
return this;
|
||||
}
|
||||
Precision other = (Precision) this.clone();
|
||||
Precision other = createCopy();
|
||||
other.mathContext = mathContext;
|
||||
return other;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @draft ICU 62
|
||||
* @provisional This API might change or be removed in a future release.
|
||||
*/
|
||||
@Override
|
||||
public Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
// Should not happen since parent is Object
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
/** Package-private clone method */
|
||||
abstract Precision createCopy();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
@ -566,6 +554,13 @@ public abstract class Precision implements Cloneable {
|
||||
value.roundToInfinity();
|
||||
value.setMinFraction(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
InfiniteRounderImpl createCopy() {
|
||||
InfiniteRounderImpl copy = new InfiniteRounderImpl();
|
||||
copy.mathContext = mathContext;
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
|
||||
static class FractionRounderImpl extends FractionPrecision {
|
||||
@ -582,6 +577,13 @@ public abstract class Precision implements Cloneable {
|
||||
value.roundToMagnitude(getRoundingMagnitudeFraction(maxFrac), mathContext);
|
||||
value.setMinFraction(Math.max(0, -getDisplayMagnitudeFraction(minFrac)));
|
||||
}
|
||||
|
||||
@Override
|
||||
FractionRounderImpl createCopy() {
|
||||
FractionRounderImpl copy = new FractionRounderImpl(minFrac, maxFrac);
|
||||
copy.mathContext = mathContext;
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
|
||||
static class SignificantRounderImpl extends Precision {
|
||||
@ -611,6 +613,13 @@ public abstract class Precision implements Cloneable {
|
||||
assert quantity.isZeroish();
|
||||
quantity.setMinFraction(minSig - minInt);
|
||||
}
|
||||
|
||||
@Override
|
||||
SignificantRounderImpl createCopy() {
|
||||
SignificantRounderImpl copy = new SignificantRounderImpl(minSig, maxSig);
|
||||
copy.mathContext = mathContext;
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
|
||||
static class FracSigRounderImpl extends Precision {
|
||||
@ -642,6 +651,13 @@ public abstract class Precision implements Cloneable {
|
||||
value.roundToMagnitude(roundingMag, mathContext);
|
||||
value.setMinFraction(Math.max(0, -displayMag));
|
||||
}
|
||||
|
||||
@Override
|
||||
FracSigRounderImpl createCopy() {
|
||||
FracSigRounderImpl copy = new FracSigRounderImpl(minFrac, maxFrac, minSig, maxSig);
|
||||
copy.mathContext = mathContext;
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -659,6 +675,13 @@ public abstract class Precision implements Cloneable {
|
||||
value.roundToIncrement(increment, mathContext);
|
||||
value.setMinFraction(increment.scale());
|
||||
}
|
||||
|
||||
@Override
|
||||
IncrementRounderImpl createCopy() {
|
||||
IncrementRounderImpl copy = new IncrementRounderImpl(increment);
|
||||
copy.mathContext = mathContext;
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -681,6 +704,13 @@ public abstract class Precision implements Cloneable {
|
||||
value.roundToMagnitude(-maxFrac, mathContext);
|
||||
value.setMinFraction(minFrac);
|
||||
}
|
||||
|
||||
@Override
|
||||
IncrementOneRounderImpl createCopy() {
|
||||
IncrementOneRounderImpl copy = new IncrementOneRounderImpl(increment, minFrac, maxFrac);
|
||||
copy.mathContext = mathContext;
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -701,6 +731,13 @@ public abstract class Precision implements Cloneable {
|
||||
value.roundToNickel(-maxFrac, mathContext);
|
||||
value.setMinFraction(minFrac);
|
||||
}
|
||||
|
||||
@Override
|
||||
IncrementFiveRounderImpl createCopy() {
|
||||
IncrementFiveRounderImpl copy = new IncrementFiveRounderImpl(increment, minFrac, maxFrac);
|
||||
copy.mathContext = mathContext;
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
|
||||
static class CurrencyRounderImpl extends CurrencyPrecision {
|
||||
@ -715,6 +752,13 @@ public abstract class Precision implements Cloneable {
|
||||
// Call .withCurrency() before .apply()!
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@Override
|
||||
CurrencyRounderImpl createCopy() {
|
||||
CurrencyRounderImpl copy = new CurrencyRounderImpl(usage);
|
||||
copy.mathContext = mathContext;
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
|
||||
private static int getRoundingMagnitudeFraction(int maxFrac) {
|
||||
|
@ -27,7 +27,7 @@ import com.ibm.icu.text.NumberFormat;
|
||||
* @stable ICU 60
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public class ScientificNotation extends Notation implements Cloneable {
|
||||
public class ScientificNotation extends Notation {
|
||||
|
||||
int engineeringInterval;
|
||||
boolean requireMinInt;
|
||||
@ -62,7 +62,7 @@ public class ScientificNotation extends Notation implements Cloneable {
|
||||
*/
|
||||
public ScientificNotation withMinExponentDigits(int minExponentDigits) {
|
||||
if (minExponentDigits >= 1 && minExponentDigits <= RoundingUtils.MAX_INT_FRAC_SIG) {
|
||||
ScientificNotation other = (ScientificNotation) this.clone();
|
||||
ScientificNotation other = createCopy();
|
||||
other.minExponentDigits = minExponentDigits;
|
||||
return other;
|
||||
} else {
|
||||
@ -87,23 +87,19 @@ public class ScientificNotation extends Notation implements Cloneable {
|
||||
* @see NumberFormatter
|
||||
*/
|
||||
public ScientificNotation withExponentSignDisplay(SignDisplay exponentSignDisplay) {
|
||||
ScientificNotation other = (ScientificNotation) this.clone();
|
||||
ScientificNotation other = createCopy();
|
||||
other.exponentSignDisplay = exponentSignDisplay;
|
||||
return other;
|
||||
}
|
||||
|
||||
/**
|
||||
* @draft ICU 60
|
||||
* @provisional This API might change or be removed in a future release.
|
||||
*/
|
||||
@Override
|
||||
public Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
// Should not happen since parent is Object
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
/** Package-private clone method */
|
||||
ScientificNotation createCopy() {
|
||||
return new ScientificNotation(
|
||||
engineeringInterval,
|
||||
requireMinInt,
|
||||
minExponentDigits,
|
||||
exponentSignDisplay
|
||||
);
|
||||
}
|
||||
|
||||
/* package-private */ MicroPropsGenerator withLocaleData(
|
||||
|
@ -12,9 +12,14 @@ import java.text.AttributedCharacterIterator;
|
||||
import java.text.FieldPosition;
|
||||
import java.text.ParsePosition;
|
||||
|
||||
import com.ibm.icu.impl.FormattedStringBuilder;
|
||||
import com.ibm.icu.impl.FormattedValueStringBuilderImpl;
|
||||
import com.ibm.icu.impl.Utility;
|
||||
import com.ibm.icu.impl.number.AffixUtils;
|
||||
import com.ibm.icu.impl.number.DecimalFormatProperties;
|
||||
import com.ibm.icu.impl.number.DecimalFormatProperties.ParseMode;
|
||||
import com.ibm.icu.impl.number.DecimalQuantity;
|
||||
import com.ibm.icu.impl.number.DecimalQuantity_DualStorageBCD;
|
||||
import com.ibm.icu.impl.number.Padder;
|
||||
import com.ibm.icu.impl.number.Padder.PadPosition;
|
||||
import com.ibm.icu.impl.number.PatternStringParser;
|
||||
@ -708,9 +713,11 @@ public class DecimalFormat extends NumberFormat {
|
||||
*/
|
||||
@Override
|
||||
public StringBuffer format(double number, StringBuffer result, FieldPosition fieldPosition) {
|
||||
FormattedNumber output = formatter.format(number);
|
||||
fieldPositionHelper(output, fieldPosition, result.length());
|
||||
output.appendTo(result);
|
||||
DecimalQuantity dq = new DecimalQuantity_DualStorageBCD(number);
|
||||
FormattedStringBuilder string = new FormattedStringBuilder();
|
||||
formatter.formatImpl(dq, string);
|
||||
fieldPositionHelper(dq, string, fieldPosition, result.length());
|
||||
Utility.appendTo(string, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -721,9 +728,11 @@ public class DecimalFormat extends NumberFormat {
|
||||
*/
|
||||
@Override
|
||||
public StringBuffer format(long number, StringBuffer result, FieldPosition fieldPosition) {
|
||||
FormattedNumber output = formatter.format(number);
|
||||
fieldPositionHelper(output, fieldPosition, result.length());
|
||||
output.appendTo(result);
|
||||
DecimalQuantity dq = new DecimalQuantity_DualStorageBCD(number);
|
||||
FormattedStringBuilder string = new FormattedStringBuilder();
|
||||
formatter.formatImpl(dq, string);
|
||||
fieldPositionHelper(dq, string, fieldPosition, result.length());
|
||||
Utility.appendTo(string, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -734,9 +743,11 @@ public class DecimalFormat extends NumberFormat {
|
||||
*/
|
||||
@Override
|
||||
public StringBuffer format(BigInteger number, StringBuffer result, FieldPosition fieldPosition) {
|
||||
FormattedNumber output = formatter.format(number);
|
||||
fieldPositionHelper(output, fieldPosition, result.length());
|
||||
output.appendTo(result);
|
||||
DecimalQuantity dq = new DecimalQuantity_DualStorageBCD(number);
|
||||
FormattedStringBuilder string = new FormattedStringBuilder();
|
||||
formatter.formatImpl(dq, string);
|
||||
fieldPositionHelper(dq, string, fieldPosition, result.length());
|
||||
Utility.appendTo(string, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -748,9 +759,11 @@ public class DecimalFormat extends NumberFormat {
|
||||
@Override
|
||||
public StringBuffer format(
|
||||
java.math.BigDecimal number, StringBuffer result, FieldPosition fieldPosition) {
|
||||
FormattedNumber output = formatter.format(number);
|
||||
fieldPositionHelper(output, fieldPosition, result.length());
|
||||
output.appendTo(result);
|
||||
DecimalQuantity dq = new DecimalQuantity_DualStorageBCD(number);
|
||||
FormattedStringBuilder string = new FormattedStringBuilder();
|
||||
formatter.formatImpl(dq, string);
|
||||
fieldPositionHelper(dq, string, fieldPosition, result.length());
|
||||
Utility.appendTo(string, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -761,9 +774,11 @@ public class DecimalFormat extends NumberFormat {
|
||||
*/
|
||||
@Override
|
||||
public StringBuffer format(BigDecimal number, StringBuffer result, FieldPosition fieldPosition) {
|
||||
FormattedNumber output = formatter.format(number);
|
||||
fieldPositionHelper(output, fieldPosition, result.length());
|
||||
output.appendTo(result);
|
||||
DecimalQuantity dq = new DecimalQuantity_DualStorageBCD(number);
|
||||
FormattedStringBuilder string = new FormattedStringBuilder();
|
||||
formatter.formatImpl(dq, string);
|
||||
fieldPositionHelper(dq, string, fieldPosition, result.length());
|
||||
Utility.appendTo(string, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -792,12 +807,14 @@ public class DecimalFormat extends NumberFormat {
|
||||
// because its caching mechanism will not provide any benefit here.
|
||||
DecimalFormatSymbols localSymbols = (DecimalFormatSymbols) symbols.clone();
|
||||
localSymbols.setCurrency(currAmt.getCurrency());
|
||||
FormattedNumber output = formatter
|
||||
.symbols(localSymbols)
|
||||
|
||||
DecimalQuantity dq = new DecimalQuantity_DualStorageBCD(currAmt.getNumber());
|
||||
FormattedStringBuilder string = new FormattedStringBuilder();
|
||||
formatter.symbols(localSymbols)
|
||||
.unit(currAmt.getCurrency())
|
||||
.format(currAmt.getNumber());
|
||||
fieldPositionHelper(output, fieldPosition, result.length());
|
||||
output.appendTo(result);
|
||||
.formatImpl(dq, string);
|
||||
fieldPositionHelper(dq, string, fieldPosition, result.length());
|
||||
Utility.appendTo(string, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -2585,11 +2602,13 @@ public synchronized void setParseStrictMode(ParseMode parseMode) {
|
||||
PatternStringParser.parseToExistingProperties(pattern, properties, ignoreRounding);
|
||||
}
|
||||
|
||||
static void fieldPositionHelper(FormattedNumber formatted, FieldPosition fieldPosition, int offset) {
|
||||
static void fieldPositionHelper(
|
||||
DecimalQuantity dq, FormattedStringBuilder string, FieldPosition fieldPosition, int offset) {
|
||||
// always return first occurrence:
|
||||
fieldPosition.setBeginIndex(0);
|
||||
fieldPosition.setEndIndex(0);
|
||||
boolean found = formatted.nextFieldPosition(fieldPosition);
|
||||
dq.populateUFieldPosition(fieldPosition);
|
||||
boolean found = FormattedValueStringBuilderImpl.nextFieldPosition(string, fieldPosition);;
|
||||
if (found && offset != 0) {
|
||||
fieldPosition.setBeginIndex(fieldPosition.getBeginIndex() + offset);
|
||||
fieldPosition.setEndIndex(fieldPosition.getEndIndex() + offset);
|
||||
|
@ -31,13 +31,16 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.ibm.icu.impl.DontCareFieldPosition;
|
||||
import com.ibm.icu.impl.FormattedStringBuilder;
|
||||
import com.ibm.icu.impl.FormattedValueStringBuilderImpl;
|
||||
import com.ibm.icu.impl.ICUData;
|
||||
import com.ibm.icu.impl.ICUResourceBundle;
|
||||
import com.ibm.icu.impl.SimpleCache;
|
||||
import com.ibm.icu.impl.SimpleFormatterImpl;
|
||||
import com.ibm.icu.impl.Utility;
|
||||
import com.ibm.icu.impl.number.DecimalQuantity;
|
||||
import com.ibm.icu.impl.number.DecimalQuantity_DualStorageBCD;
|
||||
import com.ibm.icu.impl.number.LongNameHandler;
|
||||
import com.ibm.icu.impl.number.RoundingUtils;
|
||||
import com.ibm.icu.number.FormattedNumber;
|
||||
import com.ibm.icu.number.IntegerWidth;
|
||||
import com.ibm.icu.number.LocalizedNumberFormatter;
|
||||
import com.ibm.icu.number.NumberFormatter;
|
||||
@ -320,9 +323,10 @@ public class MeasureFormat extends UFormat {
|
||||
} else if (obj instanceof Measure[]) {
|
||||
formatMeasuresInternal(toAppendTo, fpos, (Measure[]) obj);
|
||||
} else if (obj instanceof Measure) {
|
||||
FormattedNumber result = formatMeasure((Measure) obj);
|
||||
result.nextFieldPosition(fpos); // No offset: toAppendTo.length() is considered below
|
||||
result.appendTo(toAppendTo);
|
||||
FormattedStringBuilder result = formatMeasure((Measure) obj);
|
||||
// No offset: toAppendTo.length() is considered below
|
||||
FormattedValueStringBuilderImpl.nextFieldPosition(result, fpos);
|
||||
Utility.appendTo(result, toAppendTo);
|
||||
} else {
|
||||
throw new IllegalArgumentException(obj.toString());
|
||||
}
|
||||
@ -386,11 +390,13 @@ public class MeasureFormat extends UFormat {
|
||||
MeasureUnit perUnit,
|
||||
StringBuilder appendTo,
|
||||
FieldPosition pos) {
|
||||
FormattedNumber result = getUnitFormatterFromCache(NUMBER_FORMATTER_STANDARD,
|
||||
measure.getUnit(),
|
||||
perUnit).format(measure.getNumber());
|
||||
DecimalFormat.fieldPositionHelper(result, pos, appendTo.length());
|
||||
result.appendTo(appendTo);
|
||||
DecimalQuantity dq = new DecimalQuantity_DualStorageBCD(measure.getNumber());
|
||||
FormattedStringBuilder string = new FormattedStringBuilder();
|
||||
getUnitFormatterFromCache(
|
||||
NUMBER_FORMATTER_STANDARD, measure.getUnit(), perUnit
|
||||
).formatImpl(dq, string);
|
||||
DecimalFormat.fieldPositionHelper(dq, string, pos, appendTo.length());
|
||||
Utility.appendTo(string, appendTo);
|
||||
return appendTo;
|
||||
}
|
||||
|
||||
@ -433,9 +439,9 @@ public class MeasureFormat extends UFormat {
|
||||
return;
|
||||
}
|
||||
if (measures.length == 1) {
|
||||
FormattedNumber result = formatMeasure(measures[0]);
|
||||
result.nextFieldPosition(fieldPosition);
|
||||
result.appendTo(appendTo);
|
||||
FormattedStringBuilder result = formatMeasure(measures[0]);
|
||||
FormattedValueStringBuilderImpl.nextFieldPosition(result, fieldPosition);
|
||||
Utility.appendTo(result, appendTo);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -768,20 +774,26 @@ public class MeasureFormat extends UFormat {
|
||||
|
||||
/// END NUMBER FORMATTER CACHING MACHINERY ///
|
||||
|
||||
private FormattedNumber formatMeasure(Measure measure) {
|
||||
private FormattedStringBuilder formatMeasure(Measure measure) {
|
||||
MeasureUnit unit = measure.getUnit();
|
||||
DecimalQuantity dq = new DecimalQuantity_DualStorageBCD(measure.getNumber());
|
||||
FormattedStringBuilder string = new FormattedStringBuilder();
|
||||
if (unit instanceof Currency) {
|
||||
return getUnitFormatterFromCache(NUMBER_FORMATTER_CURRENCY, unit, null)
|
||||
.format(measure.getNumber());
|
||||
getUnitFormatterFromCache(NUMBER_FORMATTER_CURRENCY, unit, null)
|
||||
.formatImpl(dq, string);
|
||||
} else {
|
||||
return getUnitFormatterFromCache(NUMBER_FORMATTER_STANDARD, unit, null)
|
||||
.format(measure.getNumber());
|
||||
getUnitFormatterFromCache(NUMBER_FORMATTER_STANDARD, unit, null)
|
||||
.formatImpl(dq, string);
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
private FormattedNumber formatMeasureInteger(Measure measure) {
|
||||
return getUnitFormatterFromCache(NUMBER_FORMATTER_INTEGER, measure.getUnit(), null)
|
||||
.format(measure.getNumber());
|
||||
private FormattedStringBuilder formatMeasureInteger(Measure measure) {
|
||||
DecimalQuantity dq = new DecimalQuantity_DualStorageBCD(measure.getNumber());
|
||||
FormattedStringBuilder string = new FormattedStringBuilder();
|
||||
getUnitFormatterFromCache(NUMBER_FORMATTER_INTEGER, measure.getUnit(), null)
|
||||
.formatImpl(dq, string);
|
||||
return string;
|
||||
}
|
||||
|
||||
private void formatMeasuresSlowTrack(
|
||||
@ -797,14 +809,14 @@ public class MeasureFormat extends UFormat {
|
||||
|
||||
int fieldPositionFoundIndex = -1;
|
||||
for (int i = 0; i < measures.length; ++i) {
|
||||
FormattedNumber result;
|
||||
FormattedStringBuilder result;
|
||||
if (i == measures.length - 1) {
|
||||
result = formatMeasure(measures[i]);
|
||||
} else {
|
||||
result = formatMeasureInteger(measures[i]);
|
||||
}
|
||||
if (fieldPositionFoundIndex == -1) {
|
||||
result.nextFieldPosition(fpos);
|
||||
FormattedValueStringBuilderImpl.nextFieldPosition(result, fpos);
|
||||
if (fpos.getEndIndex() != 0) {
|
||||
fieldPositionFoundIndex = i;
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ import com.ibm.icu.number.Precision;
|
||||
import com.ibm.icu.number.Scale;
|
||||
import com.ibm.icu.number.ScientificNotation;
|
||||
import com.ibm.icu.number.UnlocalizedNumberFormatter;
|
||||
import com.ibm.icu.text.ConstrainedFieldPosition;
|
||||
import com.ibm.icu.text.DecimalFormatSymbols;
|
||||
import com.ibm.icu.text.NumberFormat;
|
||||
import com.ibm.icu.text.NumberingSystem;
|
||||
@ -2585,9 +2586,10 @@ public class NumberFormatterApiTest {
|
||||
assertNumberFieldPositions(message, fmtd, expectedFieldPositions);
|
||||
|
||||
// Test the iteration functionality of nextFieldPosition
|
||||
FieldPosition actual = new FieldPosition(NumberFormat.Field.GROUPING_SEPARATOR);
|
||||
ConstrainedFieldPosition actual = new ConstrainedFieldPosition();
|
||||
actual.constrainField(NumberFormat.Field.GROUPING_SEPARATOR);
|
||||
int i = 1;
|
||||
while (fmtd.nextFieldPosition(actual)) {
|
||||
while (fmtd.nextPosition(actual)) {
|
||||
Object[] cas = expectedFieldPositions[i++];
|
||||
NumberFormat.Field expectedField = (NumberFormat.Field) cas[0];
|
||||
int expectedBeginIndex = (Integer) cas[1];
|
||||
@ -2596,22 +2598,23 @@ public class NumberFormatterApiTest {
|
||||
assertEquals(
|
||||
"Next for grouping, field, case #" + i,
|
||||
expectedField,
|
||||
actual.getFieldAttribute());
|
||||
actual.getField());
|
||||
assertEquals(
|
||||
"Next for grouping, begin index, case #" + i,
|
||||
expectedBeginIndex,
|
||||
actual.getBeginIndex());
|
||||
actual.getStart());
|
||||
assertEquals(
|
||||
"Next for grouping, end index, case #" + i,
|
||||
expectedEndIndex,
|
||||
actual.getEndIndex());
|
||||
actual.getLimit());
|
||||
}
|
||||
assertEquals("Should have seen all grouping separators", 4, i);
|
||||
|
||||
// Make sure strings without fraction do not contain fraction field
|
||||
actual = new FieldPosition(NumberFormat.Field.FRACTION);
|
||||
actual.reset();
|
||||
actual.constrainField(NumberFormat.Field.FRACTION);
|
||||
fmtd = NumberFormatter.withLocale(ULocale.ENGLISH).format(5);
|
||||
assertFalse("No fraction part in an integer", fmtd.nextFieldPosition(actual));
|
||||
assertFalse("No fraction part in an integer", fmtd.nextPosition(actual));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
Loading…
Reference in New Issue
Block a user