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);
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);
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);
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);
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);
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);
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);
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);
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);
}
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);
}
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);
}
}
// 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;
#include "uassert.h"
#include "unicode/numberformatter.h"
#include "number_longnames.h"
+#include "number_utypes.h"
#include "sharednumberformat.h"
#include "sharedpluralrules.h"
U_NAMESPACE_BEGIN
+using number::impl::UFormattedNumberData;
+
static constexpr int32_t WIDTH_INDEX_COUNT = UMEASFMT_WIDTH_NARROW + 1;
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MeasureFormat)
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));
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));
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
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
}
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
#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;
*
* 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();
#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();
namespace number {
class LocalizedNumberFormatter;
-class FormattedNumber;
namespace impl {
class DecimalQuantity;
struct DecimalFormatFields;
+class UFormattedNumberData;
}
}
const numparse::impl::NumberParserImpl* getCurrencyParser(UErrorCode& status) const;
- 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);
+ static void fieldPositionHelper(
+ const number::impl::UFormattedNumberData& formatted,
+ FieldPosition& fieldPosition,
+ int32_t offset,
+ UErrorCode& status);
+
+ static void fieldPositionIteratorHelper(
+ const number::impl::UFormattedNumberData& formatted,
+ FieldPositionIterator* fpi,
+ int32_t offset,
+ UErrorCode& status);
void setupFastFormat();
/** @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
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
* 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
* 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.
#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)
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),
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() {
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);
}
"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,
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);
}
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;
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;
}
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;
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
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());
- }
}
\ No newline at end of file
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;
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}
*
* @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);
}
/**
}
}
+ /**
+ * 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}
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
value.roundToInfinity();
value.setMinFraction(0);
}
+
+ @Override
+ InfiniteRounderImpl createCopy() {
+ InfiniteRounderImpl copy = new InfiniteRounderImpl();
+ copy.mathContext = mathContext;
+ return copy;
+ }
}
static class FractionRounderImpl extends FractionPrecision {
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 {
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 {
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;
+ }
}
/**
value.roundToIncrement(increment, mathContext);
value.setMinFraction(increment.scale());
}
+
+ @Override
+ IncrementRounderImpl createCopy() {
+ IncrementRounderImpl copy = new IncrementRounderImpl(increment);
+ copy.mathContext = mathContext;
+ return copy;
+ }
}
/**
value.roundToMagnitude(-maxFrac, mathContext);
value.setMinFraction(minFrac);
}
+
+ @Override
+ IncrementOneRounderImpl createCopy() {
+ IncrementOneRounderImpl copy = new IncrementOneRounderImpl(increment, minFrac, maxFrac);
+ copy.mathContext = mathContext;
+ return copy;
+ }
}
/**
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 {
// 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) {
* @stable ICU 60
* @see NumberFormatter
*/
-public class ScientificNotation extends Notation implements Cloneable {
+public class ScientificNotation extends Notation {
int engineeringInterval;
boolean requireMinInt;
*/
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 {
* @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(
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;
*/
@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;
}
*/
@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;
}
*/
@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;
}
@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;
}
*/
@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;
}
// 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;
}
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);
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;
} 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());
}
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;
}
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;
}
/// 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(
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;
}
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;
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];
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