ICU-20409 Additional refactoring of FormattedValue implementations.

- Migrates Number[Range] formatter to helper macros.
- Adds additional macros.
- Syncs docstrings between subclasses.
This commit is contained in:
Shane Carr 2019-02-14 22:42:09 -08:00 committed by Shane F. Carr
parent 8c2de1401e
commit 35b182767f
23 changed files with 213 additions and 406 deletions

View file

@ -130,6 +130,10 @@ public:
return fString;
}
inline const number::impl::NumberStringBuilder& getStringRef() const {
return fString;
}
private:
number::impl::NumberStringBuilder fString;
number::impl::Field fNumericField;
@ -146,12 +150,22 @@ struct UFormattedValueImpl : public UMemory, public UFormattedValueApiHelper {
};
/** Boilerplate to check for valid status before dereferencing the fData pointer. */
#define UPRV_FORMATTED_VALUE_METHOD_GUARD(returnExpression) \
if (U_FAILURE(status)) { \
return returnExpression; \
} \
if (fData == nullptr) { \
status = fErrorCode; \
return returnExpression; \
} \
/** Implementation of the methods from U_FORMATTED_VALUE_SUBCLASS_AUTO. */
#define UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(Name) \
Name::Name(Name&& src) U_NOEXCEPT { \
fData = src.fData; \
Name::Name(Name&& src) U_NOEXCEPT \
: fData(src.fData), fErrorCode(src.fErrorCode) { \
src.fData = nullptr; \
fErrorCode = src.fErrorCode; \
src.fErrorCode = U_INVALID_STATE_ERROR; \
} \
Name::~Name() { \
@ -167,47 +181,51 @@ struct UFormattedValueImpl : public UMemory, public UFormattedValueApiHelper {
return *this; \
} \
UnicodeString Name::toString(UErrorCode& status) const { \
if (U_FAILURE(status)) { \
return ICU_Utility::makeBogusString(); \
} \
if (fData == nullptr) { \
status = fErrorCode; \
return ICU_Utility::makeBogusString(); \
} \
UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString()) \
return fData->toString(status); \
} \
UnicodeString Name::toTempString(UErrorCode& status) const { \
if (U_FAILURE(status)) { \
return ICU_Utility::makeBogusString(); \
} \
if (fData == nullptr) { \
status = fErrorCode; \
return ICU_Utility::makeBogusString(); \
} \
UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString()) \
return fData->toTempString(status); \
} \
Appendable& Name::appendTo(Appendable& appendable, UErrorCode& status) const { \
if (U_FAILURE(status)) { \
return appendable; \
} \
if (fData == nullptr) { \
status = fErrorCode; \
return appendable; \
} \
UPRV_FORMATTED_VALUE_METHOD_GUARD(appendable) \
return fData->appendTo(appendable, status); \
} \
UBool Name::nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const { \
if (U_FAILURE(status)) { \
return FALSE; \
} \
if (fData == nullptr) { \
status = fErrorCode; \
return FALSE; \
} \
UPRV_FORMATTED_VALUE_METHOD_GUARD(FALSE) \
return fData->nextPosition(cfpos, status); \
}
/** Like UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL but without impl type declarations. */
#define UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(CType, ImplType, HelperType, Prefix) \
U_CAPI CType* U_EXPORT2 \
Prefix ## _openResult (UErrorCode* ec) { \
if (U_FAILURE(*ec)) { \
return nullptr; \
} \
ImplType* impl = new ImplType(); \
if (impl == nullptr) { \
*ec = U_MEMORY_ALLOCATION_ERROR; \
return nullptr; \
} \
return static_cast<HelperType*>(impl)->exportForC(); \
} \
U_DRAFT const UFormattedValue* U_EXPORT2 \
Prefix ## _resultAsValue (const CType* uresult, UErrorCode* ec) { \
const ImplType* result = HelperType::validate(uresult, *ec); \
if (U_FAILURE(*ec)) { return nullptr; } \
return static_cast<const UFormattedValueApiHelper*>(result)->exportConstForC(); \
} \
U_CAPI void U_EXPORT2 \
Prefix ## _closeResult (CType* uresult) { \
UErrorCode localStatus = U_ZERO_ERROR; \
const ImplType* impl = HelperType::validate(uresult, localStatus); \
delete impl; \
}
/**
* Implementation of the standard methods for a UFormattedValue "subclass" C API.
* @param CPPType The public C++ type, like FormattedList
@ -232,30 +250,7 @@ struct UFormattedValueImpl : public UMemory, public UFormattedValueApiHelper {
} \
ImplType::~ImplType() {} \
U_NAMESPACE_END \
U_CAPI CType* U_EXPORT2 \
Prefix ## _openResult (UErrorCode* ec) { \
if (U_FAILURE(*ec)) { \
return nullptr; \
} \
ImplType* impl = new ImplType(); \
if (impl == nullptr) { \
*ec = U_MEMORY_ALLOCATION_ERROR; \
return nullptr; \
} \
return static_cast<HelperType*>(impl)->exportForC(); \
} \
U_DRAFT const UFormattedValue* U_EXPORT2 \
Prefix ## _resultAsValue (const CType* uresult, UErrorCode* ec) { \
const ImplType* result = HelperType::validate(uresult, *ec); \
if (U_FAILURE(*ec)) { return nullptr; } \
return static_cast<const UFormattedValueApiHelper*>(result)->exportConstForC(); \
} \
U_CAPI void U_EXPORT2 \
Prefix ## _closeResult (CType* uresult) { \
UErrorCode localStatus = U_ZERO_ERROR; \
const ImplType* impl = HelperType::validate(uresult, localStatus); \
delete impl; \
}
UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(CType, ImplType, HelperType, Prefix)
U_NAMESPACE_END

View file

@ -62,12 +62,12 @@ UnicodeString& LocalizedNumberFormatterAsFormat::format(const Formattable& obj,
// always return first occurrence:
pos.setBeginIndex(0);
pos.setEndIndex(0);
bool found = data.string.nextFieldPosition(pos, status);
bool found = data.getStringRef().nextFieldPosition(pos, status);
if (found && appendTo.length() != 0) {
pos.setBeginIndex(pos.getBeginIndex() + appendTo.length());
pos.setEndIndex(pos.getEndIndex() + appendTo.length());
}
appendTo.append(data.string.toTempUnicodeString());
appendTo.append(data.getStringRef().toTempUnicodeString());
return appendTo;
}
@ -84,10 +84,10 @@ UnicodeString& LocalizedNumberFormatterAsFormat::format(const Formattable& obj,
if (U_FAILURE(status)) {
return appendTo;
}
appendTo.append(data.string.toTempUnicodeString());
appendTo.append(data.getStringRef().toTempUnicodeString());
if (posIter != nullptr) {
FieldPositionIteratorHandler fpih(posIter, status);
data.string.getAllFieldPositions(fpih, status);
data.getStringRef().getAllFieldPositions(fpih, status);
}
return appendTo;
}

View file

@ -54,7 +54,7 @@ UFormattedNumberImpl::UFormattedNumberImpl()
UFormattedNumberImpl::~UFormattedNumberImpl() {
// Disown the data from fImpl so it doesn't get deleted twice
fImpl.fResults = nullptr;
fImpl.fData = nullptr;
}
}
@ -62,6 +62,13 @@ UFormattedNumberImpl::~UFormattedNumberImpl() {
U_NAMESPACE_END
UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(
UFormattedNumber,
UFormattedNumberImpl,
UFormattedNumberApiHelper,
unumf)
const DecimalQuantity* icu::number::impl::validateUFormattedNumberToDecimalQuantity(
const UFormattedNumber* uresult, UErrorCode& status) {
auto* result = UFormattedNumberApiHelper::validate(uresult, status);
@ -101,16 +108,6 @@ unumf_openForSkeletonAndLocaleWithError(const UChar* skeleton, int32_t skeletonL
return impl->exportForC();
}
U_CAPI UFormattedNumber* U_EXPORT2
unumf_openResult(UErrorCode* ec) {
auto* impl = new UFormattedNumberImpl();
if (impl == nullptr) {
*ec = U_MEMORY_ALLOCATION_ERROR;
return nullptr;
}
return static_cast<UFormattedNumberApiHelper*>(impl)->exportForC();
}
U_CAPI void U_EXPORT2
unumf_formatInt(const UNumberFormatter* uformatter, int64_t value, UFormattedNumber* uresult,
UErrorCode* ec) {
@ -118,7 +115,7 @@ unumf_formatInt(const UNumberFormatter* uformatter, int64_t value, UFormattedNum
auto* result = UFormattedNumberApiHelper::validate(uresult, *ec);
if (U_FAILURE(*ec)) { return; }
result->fData.string.clear();
result->fData.getStringRef().clear();
result->fData.quantity.setToLong(value);
formatter->fFormatter.formatImpl(&result->fData, *ec);
}
@ -130,7 +127,7 @@ unumf_formatDouble(const UNumberFormatter* uformatter, double value, UFormattedN
auto* result = UFormattedNumberApiHelper::validate(uresult, *ec);
if (U_FAILURE(*ec)) { return; }
result->fData.string.clear();
result->fData.getStringRef().clear();
result->fData.quantity.setToDouble(value);
formatter->fFormatter.formatImpl(&result->fData, *ec);
}
@ -142,20 +139,12 @@ unumf_formatDecimal(const UNumberFormatter* uformatter, const char* value, int32
auto* result = UFormattedNumberApiHelper::validate(uresult, *ec);
if (U_FAILURE(*ec)) { return; }
result->fData.string.clear();
result->fData.getStringRef().clear();
result->fData.quantity.setToDecNumber({value, valueLen}, *ec);
if (U_FAILURE(*ec)) { return; }
formatter->fFormatter.formatImpl(&result->fData, *ec);
}
U_DRAFT const UFormattedValue* U_EXPORT2
unumf_resultAsFormattedValue(const UFormattedNumber* uresult, UErrorCode* ec) {
const auto* result = UFormattedNumberApiHelper::validate(uresult, *ec);
if (U_FAILURE(*ec)) { return nullptr; }
return static_cast<const UFormattedValueApiHelper*>(result)->exportConstForC();
}
U_CAPI int32_t U_EXPORT2
unumf_resultToString(const UFormattedNumber* uresult, UChar* buffer, int32_t bufferCapacity,
UErrorCode* ec) {
@ -206,13 +195,6 @@ unumf_resultGetAllFieldPositions(const UFormattedNumber* uresult, UFieldPosition
result->fImpl.getAllFieldPositions(*fpi, *ec);
}
U_CAPI void U_EXPORT2
unumf_closeResult(UFormattedNumber* uresult) {
UErrorCode localStatus = U_ZERO_ERROR;
const UFormattedNumberImpl* impl = UFormattedNumberApiHelper::validate(uresult, localStatus);
delete impl;
}
U_CAPI void U_EXPORT2
unumf_close(UNumberFormatter* f) {
UErrorCode localStatus = U_ZERO_ERROR;

View file

@ -684,14 +684,14 @@ LocalizedNumberFormatter::formatDecimalQuantity(const DecimalQuantity& dq, UErro
void LocalizedNumberFormatter::formatImpl(impl::UFormattedNumberData* results, UErrorCode& status) const {
if (computeCompiled(status)) {
fCompiled->format(results->quantity, results->string, status);
fCompiled->format(results->quantity, results->getStringRef(), status);
} else {
NumberFormatterImpl::formatStatic(fMacros, results->quantity, results->string, status);
NumberFormatterImpl::formatStatic(fMacros, results->quantity, results->getStringRef(), status);
}
if (U_FAILURE(status)) {
return;
}
results->string.writeTerminator(status);
results->getStringRef().writeTerminator(status);
}
void LocalizedNumberFormatter::getAffixImpl(bool isPrefix, bool isNegative, UnicodeString& result,

View file

@ -14,79 +14,13 @@ U_NAMESPACE_BEGIN
namespace number {
FormattedNumber::FormattedNumber(FormattedNumber&& src) U_NOEXCEPT
: fResults(src.fResults), fErrorCode(src.fErrorCode) {
// Disown src.fResults to prevent double-deletion
src.fResults = nullptr;
src.fErrorCode = U_INVALID_STATE_ERROR;
}
UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(FormattedNumber)
FormattedNumber& FormattedNumber::operator=(FormattedNumber&& src) U_NOEXCEPT {
delete fResults;
fResults = src.fResults;
fErrorCode = src.fErrorCode;
// Disown src.fResults to prevent double-deletion
src.fResults = nullptr;
src.fErrorCode = U_INVALID_STATE_ERROR;
return *this;
}
UnicodeString FormattedNumber::toString(UErrorCode& status) const {
if (U_FAILURE(status)) {
return ICU_Utility::makeBogusString();
}
if (fResults == nullptr) {
status = fErrorCode;
return ICU_Utility::makeBogusString();
}
return fResults->string.toUnicodeString();
}
UnicodeString FormattedNumber::toTempString(UErrorCode& status) const {
if (U_FAILURE(status)) {
return ICU_Utility::makeBogusString();
}
if (fResults == nullptr) {
status = fErrorCode;
return ICU_Utility::makeBogusString();
}
return fResults->string.toTempUnicodeString();
}
Appendable& FormattedNumber::appendTo(Appendable& appendable, UErrorCode& status) const {
if (U_FAILURE(status)) {
return appendable;
}
if (fResults == nullptr) {
status = fErrorCode;
return appendable;
}
appendable.appendString(fResults->string.chars(), fResults->string.length());
return appendable;
}
UBool FormattedNumber::nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const {
if (U_FAILURE(status)) {
return FALSE;
}
if (fResults == nullptr) {
status = fErrorCode;
return FALSE;
}
// NOTE: MSVC sometimes complains when implicitly converting between bool and UBool
return fResults->string.nextPosition(cfpos, 0, status) ? TRUE : FALSE;
}
UBool FormattedNumber::nextFieldPosition(FieldPosition& fieldPosition, UErrorCode& status) const {
if (U_FAILURE(status)) {
return FALSE;
}
if (fResults == nullptr) {
status = fErrorCode;
return FALSE;
}
UPRV_FORMATTED_VALUE_METHOD_GUARD(FALSE)
// NOTE: MSVC sometimes complains when implicitly converting between bool and UBool
return fResults->string.nextFieldPosition(fieldPosition, status) ? TRUE : FALSE;
return fData->getStringRef().nextFieldPosition(fieldPosition, status) ? TRUE : FALSE;
}
void FormattedNumber::getAllFieldPositions(FieldPositionIterator& iterator, UErrorCode& status) const {
@ -96,30 +30,17 @@ void FormattedNumber::getAllFieldPositions(FieldPositionIterator& iterator, UErr
void FormattedNumber::getAllFieldPositionsImpl(FieldPositionIteratorHandler& fpih,
UErrorCode& status) const {
if (U_FAILURE(status)) {
return;
}
if (fResults == nullptr) {
status = fErrorCode;
return;
}
fResults->string.getAllFieldPositions(fpih, status);
UPRV_FORMATTED_VALUE_METHOD_GUARD()
fData->getStringRef().getAllFieldPositions(fpih, status);
}
void FormattedNumber::getDecimalQuantity(impl::DecimalQuantity& output, UErrorCode& status) const {
if (U_FAILURE(status)) {
return;
}
if (fResults == nullptr) {
status = fErrorCode;
return;
}
output = fResults->quantity;
UPRV_FORMATTED_VALUE_METHOD_GUARD()
output = fData->quantity;
}
FormattedNumber::~FormattedNumber() {
delete fResults;
}
impl::UFormattedNumberData::~UFormattedNumberData() = default;
} // namespace number

View file

@ -11,6 +11,7 @@
#include "number_types.h"
#include "number_decimalquantity.h"
#include "number_stringbuilder.h"
#include "formattedval_impl.h"
U_NAMESPACE_BEGIN namespace number {
namespace impl {
@ -30,9 +31,12 @@ 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.
*/
struct UFormattedNumberData : public UMemory {
class UFormattedNumberData : public FormattedValueNumberStringBuilderImpl {
public:
UFormattedNumberData() : FormattedValueNumberStringBuilderImpl(0) {}
virtual ~UFormattedNumberData();
DecimalQuantity quantity;
NumberStringBuilder string;
};

View file

@ -331,7 +331,7 @@ void LocalizedNumberRangeFormatter::formatImpl(
if (U_FAILURE(status)) {
return;
}
results.string.writeTerminator(status);
results.getStringRef().writeTerminator(status);
}
const impl::NumberRangeFormatterImpl*
@ -375,79 +375,13 @@ LocalizedNumberRangeFormatter::getFormatter(UErrorCode& status) const {
}
FormattedNumberRange::FormattedNumberRange(FormattedNumberRange&& src) U_NOEXCEPT
: fResults(src.fResults), fErrorCode(src.fErrorCode) {
// Disown src.fResults to prevent double-deletion
src.fResults = nullptr;
src.fErrorCode = U_INVALID_STATE_ERROR;
}
UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(FormattedNumberRange)
FormattedNumberRange& FormattedNumberRange::operator=(FormattedNumberRange&& src) U_NOEXCEPT {
delete fResults;
fResults = src.fResults;
fErrorCode = src.fErrorCode;
// Disown src.fResults to prevent double-deletion
src.fResults = nullptr;
src.fErrorCode = U_INVALID_STATE_ERROR;
return *this;
}
UnicodeString FormattedNumberRange::toString(UErrorCode& status) const {
if (U_FAILURE(status)) {
return ICU_Utility::makeBogusString();
}
if (fResults == nullptr) {
status = fErrorCode;
return ICU_Utility::makeBogusString();
}
return fResults->string.toUnicodeString();
}
UnicodeString FormattedNumberRange::toTempString(UErrorCode& status) const {
if (U_FAILURE(status)) {
return ICU_Utility::makeBogusString();
}
if (fResults == nullptr) {
status = fErrorCode;
return ICU_Utility::makeBogusString();
}
return fResults->string.toTempUnicodeString();
}
Appendable& FormattedNumberRange::appendTo(Appendable& appendable, UErrorCode& status) const {
if (U_FAILURE(status)) {
return appendable;
}
if (fResults == nullptr) {
status = fErrorCode;
return appendable;
}
appendable.appendString(fResults->string.chars(), fResults->string.length());
return appendable;
}
UBool FormattedNumberRange::nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const {
if (U_FAILURE(status)) {
return FALSE;
}
if (fResults == nullptr) {
status = fErrorCode;
return FALSE;
}
// NOTE: MSVC sometimes complains when implicitly converting between bool and UBool
return fResults->string.nextPosition(cfpos, 0, status) ? TRUE : FALSE;
}
UBool FormattedNumberRange::nextFieldPosition(FieldPosition& fieldPosition, UErrorCode& status) const {
if (U_FAILURE(status)) {
return FALSE;
}
if (fResults == nullptr) {
status = fErrorCode;
return FALSE;
}
UPRV_FORMATTED_VALUE_METHOD_GUARD(FALSE)
// NOTE: MSVC sometimes complains when implicitly converting between bool and UBool
return fResults->string.nextFieldPosition(fieldPosition, status) ? TRUE : FALSE;
return fData->getStringRef().nextFieldPosition(fieldPosition, status) ? TRUE : FALSE;
}
void FormattedNumberRange::getAllFieldPositions(FieldPositionIterator& iterator, UErrorCode& status) const {
@ -457,52 +391,27 @@ void FormattedNumberRange::getAllFieldPositions(FieldPositionIterator& iterator,
void FormattedNumberRange::getAllFieldPositionsImpl(
FieldPositionIteratorHandler& fpih, UErrorCode& status) const {
if (U_FAILURE(status)) {
return;
}
if (fResults == nullptr) {
status = fErrorCode;
return;
}
fResults->string.getAllFieldPositions(fpih, status);
UPRV_FORMATTED_VALUE_METHOD_GUARD()
fData->getStringRef().getAllFieldPositions(fpih, status);
}
UnicodeString FormattedNumberRange::getFirstDecimal(UErrorCode& status) const {
if (U_FAILURE(status)) {
return ICU_Utility::makeBogusString();
}
if (fResults == nullptr) {
status = fErrorCode;
return ICU_Utility::makeBogusString();
}
return fResults->quantity1.toScientificString();
UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString())
return fData->quantity1.toScientificString();
}
UnicodeString FormattedNumberRange::getSecondDecimal(UErrorCode& status) const {
if (U_FAILURE(status)) {
return ICU_Utility::makeBogusString();
}
if (fResults == nullptr) {
status = fErrorCode;
return ICU_Utility::makeBogusString();
}
return fResults->quantity2.toScientificString();
UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString())
return fData->quantity2.toScientificString();
}
UNumberRangeIdentityResult FormattedNumberRange::getIdentityResult(UErrorCode& status) const {
if (U_FAILURE(status)) {
return UNUM_IDENTITY_RESULT_NOT_EQUAL;
}
if (fResults == nullptr) {
status = fErrorCode;
return UNUM_IDENTITY_RESULT_NOT_EQUAL;
}
return fResults->identityResult;
UPRV_FORMATTED_VALUE_METHOD_GUARD(UNUM_IDENTITY_RESULT_NOT_EQUAL)
return fData->identityResult;
}
FormattedNumberRange::~FormattedNumberRange() {
delete fResults;
}
UFormattedNumberRangeData::~UFormattedNumberRangeData() = default;

View file

@ -279,8 +279,8 @@ void NumberRangeFormatterImpl::formatSingleValue(UFormattedNumberRangeData& data
UErrorCode& status) const {
if (U_FAILURE(status)) { return; }
if (fSameFormatters) {
int32_t length = NumberFormatterImpl::writeNumber(micros1, data.quantity1, data.string, 0, status);
NumberFormatterImpl::writeAffixes(micros1, data.string, 0, length, status);
int32_t length = NumberFormatterImpl::writeNumber(micros1, data.quantity1, data.getStringRef(), 0, status);
NumberFormatterImpl::writeAffixes(micros1, data.getStringRef(), 0, length, status);
} else {
formatRange(data, micros1, micros2, status);
}
@ -292,12 +292,12 @@ void NumberRangeFormatterImpl::formatApproximately (UFormattedNumberRangeData& d
UErrorCode& status) const {
if (U_FAILURE(status)) { return; }
if (fSameFormatters) {
int32_t length = NumberFormatterImpl::writeNumber(micros1, data.quantity1, data.string, 0, status);
int32_t length = NumberFormatterImpl::writeNumber(micros1, data.quantity1, data.getStringRef(), 0, status);
// HEURISTIC: Desired modifier order: inner, middle, approximately, outer.
length += micros1.modInner->apply(data.string, 0, length, status);
length += micros1.modMiddle->apply(data.string, 0, length, status);
length += fApproximatelyModifier.apply(data.string, 0, length, status);
micros1.modOuter->apply(data.string, 0, length, status);
length += micros1.modInner->apply(data.getStringRef(), 0, length, status);
length += micros1.modMiddle->apply(data.getStringRef(), 0, length, status);
length += fApproximatelyModifier.apply(data.getStringRef(), 0, length, status);
micros1.modOuter->apply(data.getStringRef(), 0, length, status);
} else {
formatRange(data, micros1, micros2, status);
}
@ -375,7 +375,7 @@ void NumberRangeFormatterImpl::formatRange(UFormattedNumberRangeData& data,
break;
}
NumberStringBuilder& string = data.string;
NumberStringBuilder& string = data.getStringRef();
int32_t lengthPrefix = 0;
int32_t length1 = 0;
int32_t lengthInfix = 0;

View file

@ -14,6 +14,7 @@
#include "number_decimalquantity.h"
#include "number_formatimpl.h"
#include "number_stringbuilder.h"
#include "formattedval_impl.h"
U_NAMESPACE_BEGIN namespace number {
namespace impl {
@ -24,20 +25,18 @@ namespace impl {
*
* Has incomplete magic number logic that will need to be finished
* if this is to be exposed as C API in the future.
*
* Possible magic number: 0x46445200
* Reads in ASCII as "FDR" (FormatteDnumberRange with room at the end)
*/
struct UFormattedNumberRangeData : public UMemory {
// The magic number to identify incoming objects.
// Reads in ASCII as "FDR" (FormatteDnumberRange with room at the end)
static constexpr int32_t kMagic = 0x46445200;
class UFormattedNumberRangeData : public FormattedValueNumberStringBuilderImpl {
public:
UFormattedNumberRangeData() : FormattedValueNumberStringBuilderImpl(0) {}
virtual ~UFormattedNumberRangeData();
// Data members:
int32_t fMagic = kMagic;
DecimalQuantity quantity1;
DecimalQuantity quantity2;
NumberStringBuilder string;
UNumberRangeIdentityResult identityResult = UNUM_IDENTITY_RESULT_COUNT;
// No C conversion methods (no C API yet)
};

View file

@ -278,7 +278,7 @@ PluralFormat::format(const Formattable& numberObject, double number,
auto *decFmt = dynamic_cast<DecimalFormat *>(numberFormat);
if(decFmt != nullptr) {
decFmt->toNumberFormatter().formatImpl(&data, status); // mutates &data
numberString = data.string.toUnicodeString();
numberString = data.getStringRef().toUnicodeString();
} else {
if (offset == 0) {
numberFormat->format(numberObject, numberString, status);

View file

@ -192,7 +192,7 @@ void QuantityFormatter::formatAndSelect(
if (U_FAILURE(status)) {
return;
}
output = std::move(fn.string);
output = std::move(fn.getStringRef());
pluralKeyword = rules.select(fn.quantity);
} else {
UnicodeString result;

View file

@ -2079,7 +2079,7 @@ SimpleDateFormat::zeroPaddingNumber(
if (U_FAILURE(localStatus)) {
return;
}
appendTo.append(result.string.toTempUnicodeString());
appendTo.append(result.getStringRef().toTempUnicodeString());
return;
}

View file

@ -40,7 +40,7 @@ class DateIntervalFormat;
/**
* An immutable class containing the result of a date interval formatting operation.
*
* Not intended for public subclassing.
* Instances of this class are immutable and thread-safe.
*
* When calling nextPosition():
* The fields are returned from left to right. The special field category
@ -50,6 +50,8 @@ class DateIntervalFormat;
* corresponding fields in UFIELD_CATEGORY_DATE
* in the nextPosition() iterator.
*
* Not intended for public subclassing.
*
* @draft ICU 64
*/
class U_I18N_API FormattedDateInterval : public UMemory, public FormattedValue {

View file

@ -66,6 +66,8 @@ struct ListFormatData : public UMemory {
/**
* An immutable class containing the result of a list formatting operation.
*
* Instances of this class are immutable and thread-safe.
*
* When calling nextPosition():
* The fields are returned from start to end. The special field category
* UFIELD_CATEGORY_LIST_SPAN is used to indicate which argument

View file

@ -131,7 +131,7 @@ class Padder;
struct MacroProps;
struct MicroProps;
class DecimalQuantity;
struct UFormattedNumberData;
class UFormattedNumberData;
class NumberFormatterImpl;
struct ParsedPatternInfo;
class ScientificModifier;
@ -2399,58 +2399,45 @@ class U_I18N_API FormattedNumber : public UMemory, public FormattedValue {
/**
* Default constructor; makes an empty FormattedNumber.
* @draft ICU 60
*/
FormattedNumber()
: fResults(nullptr), fErrorCode(U_INVALID_STATE_ERROR) {};
: fData(nullptr), fErrorCode(U_INVALID_STATE_ERROR) {};
/**
* Copying not supported; use move constructor instead.
*/
FormattedNumber(const FormattedNumber&) = delete;
/**
* Move constructor:
* Leaves the source FormattedNumber in an undefined state.
* Move constructor: Leaves the source FormattedNumber in an undefined state.
* @draft ICU 62
*/
FormattedNumber(FormattedNumber&& src) U_NOEXCEPT;
/**
* Destruct an instance of FormattedNumber, cleaning up any memory it might own.
* Destruct an instance of FormattedNumber.
* @draft ICU 60
*/
virtual ~FormattedNumber() U_OVERRIDE;
/**
* Copying not supported; use move assignment instead.
*/
/** Copying not supported; use move constructor instead. */
FormattedNumber(const FormattedNumber&) = delete;
/** Copying not supported; use move assignment instead. */
FormattedNumber& operator=(const FormattedNumber&) = delete;
/**
* Move assignment:
* Leaves the source FormattedNumber in an undefined state.
* Move assignment: Leaves the source FormattedNumber in an undefined state.
* @draft ICU 62
*/
FormattedNumber& operator=(FormattedNumber&& src) U_NOEXCEPT;
/**
* @copydoc FormattedValue::toString()
*/
/** @copydoc FormattedValue::toString() */
UnicodeString toString(UErrorCode& status) const U_OVERRIDE;
/**
* @copydoc FormattedValue::toTempString()
*/
/** @copydoc FormattedValue::toTempString() */
UnicodeString toTempString(UErrorCode& status) const U_OVERRIDE;
/**
* @copydoc FormattedValue::appendTo()
*/
/** @copydoc FormattedValue::appendTo() */
Appendable &appendTo(Appendable& appendable, UErrorCode& status) const U_OVERRIDE;
/**
* @copydoc FormattedValue::nextPosition()
*/
/** @copydoc FormattedValue::nextPosition() */
UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const U_OVERRIDE;
/**
@ -2523,7 +2510,7 @@ class U_I18N_API FormattedNumber : public UMemory, public FormattedValue {
private:
// Can't use LocalPointer because UFormattedNumberData is forward-declared
impl::UFormattedNumberData *fResults;
const impl::UFormattedNumberData *fData;
// Error code for the terminal methods
UErrorCode fErrorCode;
@ -2533,10 +2520,10 @@ class U_I18N_API FormattedNumber : public UMemory, public FormattedValue {
* @internal
*/
explicit FormattedNumber(impl::UFormattedNumberData *results)
: fResults(results), fErrorCode(U_ZERO_ERROR) {};
: fData(results), fErrorCode(U_ZERO_ERROR) {};
explicit FormattedNumber(UErrorCode errorCode)
: fResults(nullptr), fErrorCode(errorCode) {};
: fData(nullptr), fErrorCode(errorCode) {};
// To give LocalizedNumberFormatter format methods access to this class's constructor:
friend class LocalizedNumberFormatter;

View file

@ -176,7 +176,7 @@ namespace impl {
// Forward declarations:
struct RangeMacroProps;
class DecimalQuantity;
struct UFormattedNumberRangeData;
class UFormattedNumberRangeData;
class NumberRangeFormatterImpl;
} // namespace impl
@ -828,7 +828,7 @@ class U_I18N_API FormattedNumberRange : public UMemory, public FormattedValue {
private:
// Can't use LocalPointer because UFormattedNumberRangeData is forward-declared
const impl::UFormattedNumberRangeData *fResults;
const impl::UFormattedNumberRangeData *fData;
// Error code for the terminal methods
UErrorCode fErrorCode;
@ -838,10 +838,10 @@ class U_I18N_API FormattedNumberRange : public UMemory, public FormattedValue {
* @internal
*/
explicit FormattedNumberRange(impl::UFormattedNumberRangeData *results)
: fResults(results), fErrorCode(U_ZERO_ERROR) {};
: fData(results), fErrorCode(U_ZERO_ERROR) {};
explicit FormattedNumberRange(UErrorCode errorCode)
: fResults(nullptr), fErrorCode(errorCode) {};
: fData(nullptr), fErrorCode(errorCode) {};
void getAllFieldPositionsImpl(FieldPositionIteratorHandler& fpih, UErrorCode& status) const;

View file

@ -252,6 +252,8 @@ class FormattedRelativeDateTimeData;
/**
* An immutable class containing the result of a relative datetime formatting operation.
*
* Instances of this class are immutable and thread-safe.
*
* Not intended for public subclassing.
*
* @draft ICU 64

View file

@ -473,11 +473,9 @@ unumf_openForSkeletonAndLocaleWithError(
/**
* Creates a new UFormattedNumber for holding the result of a number formatting operation.
*
* Objects of type UFormattedNumber are not guaranteed to be threadsafe.
*
* NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead.
* Creates an object to hold the result of a UNumberFormatter
* operation. The object can be used repeatedly; it is cleared whenever
* passed to a format function.
*
* @param ec Set if an error occurs.
* @draft ICU 62
@ -565,7 +563,7 @@ unumf_formatDecimal(const UNumberFormatter* uformatter, const char* value, int32
* @draft ICU 64
*/
U_DRAFT const UFormattedValue* U_EXPORT2
unumf_resultAsFormattedValue(const UFormattedNumber* uresult, UErrorCode* ec);
unumf_resultAsValue(const UFormattedNumber* uresult, UErrorCode* ec);
/**
@ -576,7 +574,7 @@ unumf_resultAsFormattedValue(const UFormattedNumber* uresult, UErrorCode* ec);
* Also see ufmtval_getString, which returns a NUL-terminated string:
*
* int32_t len;
* const UChar* str = ufmtval_getString(unumf_resultAsFormattedValue(uresult, &ec), &len, &ec);
* const UChar* str = ufmtval_getString(unumf_resultAsValue(uresult, &ec), &len, &ec);
*
* NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead.
*
@ -658,8 +656,6 @@ unumf_resultGetAllFieldPositions(const UFormattedNumber* uresult, UFieldPosition
/**
* Releases the UNumberFormatter created by unumf_openForSkeletonAndLocale().
*
* NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead.
*
* @param uformatter An object created by unumf_openForSkeletonAndLocale().
* @draft ICU 62
*/
@ -670,8 +666,6 @@ unumf_close(UNumberFormatter* uformatter);
/**
* Releases the UFormattedNumber created by unumf_openResult().
*
* NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead.
*
* @param uresult An object created by unumf_openResult().
* @draft ICU 62
*/

View file

@ -207,7 +207,7 @@ static void TestFormattedValue() {
unumf_formatInt(uformatter, 55000, uresult, &ec); // "55.00 K"
if (assertSuccessCheck("Should format without error", &ec, TRUE)) {
const UFormattedValue* fv = unumf_resultAsFormattedValue(uresult, &ec);
const UFormattedValue* fv = unumf_resultAsValue(uresult, &ec);
assertSuccess("Should convert without error", &ec);
static const UFieldPosition expectedFieldPositions[] = {
// field, begin index, end index

View file

@ -949,7 +949,7 @@ group: number_output
standardplural.o plurrule.o
deps
# FormattedNumber internals:
number_representation format
number_representation format formatted_value_sbimpl
# PluralRules internals:
unifiedcache

View file

@ -17,6 +17,7 @@ import com.ibm.icu.lang.UCharacter;
import com.ibm.icu.text.Replaceable;
import com.ibm.icu.text.UTF16;
import com.ibm.icu.text.UnicodeMatcher;
import com.ibm.icu.util.ICUUncheckedIOException;
public final class Utility {
@ -1845,4 +1846,16 @@ public final class Utility {
}
return hash;
}
/**
* Appends a CharSequence to an Appendable, converting IOException to ICUUncheckedIOException.
*/
public static <A extends Appendable> A appendTo(CharSequence string, A appendable) {
try {
appendable.append(string);
return appendable;
} catch (IOException e) {
throw new ICUUncheckedIOException(e);
}
}
}

View file

@ -2,18 +2,17 @@
// License & terms of use: http://www.unicode.org/copyright.html#License
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.Utility;
import com.ibm.icu.impl.number.DecimalQuantity;
import com.ibm.icu.impl.number.NumberStringBuilder;
import com.ibm.icu.text.ConstrainedFieldPosition;
import com.ibm.icu.text.FormattedValue;
import com.ibm.icu.text.PluralRules.IFixedDecimal;
import com.ibm.icu.util.ICUUncheckedIOException;
/**
* The result of a number formatting operation. This class allows the result to be exported in several
@ -24,11 +23,11 @@ import com.ibm.icu.util.ICUUncheckedIOException;
* @see NumberFormatter
*/
public class FormattedNumber implements FormattedValue {
final NumberStringBuilder nsb;
final NumberStringBuilder string;
final DecimalQuantity fq;
FormattedNumber(NumberStringBuilder nsb, DecimalQuantity fq) {
this.nsb = nsb;
this.string = nsb;
this.fq = fq;
}
@ -40,35 +39,7 @@ public class FormattedNumber implements FormattedValue {
*/
@Override
public String toString() {
return nsb.toString();
}
/**
* {@inheritDoc}
*
* @return The same Appendable, for chaining.
* @draft ICU 60
*/
@Override
public <A extends Appendable> A appendTo(A appendable) {
try {
appendable.append(nsb);
} catch (IOException e) {
// Throw as an unchecked exception to avoid users needing try/catch
throw new ICUUncheckedIOException(e);
}
return appendable;
}
/**
* {@inheritDoc}
*
* @draft ICU 64
* @provisional This API might change or be removed in a future release.
*/
@Override
public char charAt(int index) {
return nsb.charAt(index);
return string.toString();
}
/**
@ -79,7 +50,18 @@ public class FormattedNumber implements FormattedValue {
*/
@Override
public int length() {
return nsb.length();
return string.length();
}
/**
* {@inheritDoc}
*
* @draft ICU 64
* @provisional This API might change or be removed in a future release.
*/
@Override
public char charAt(int index) {
return string.charAt(index);
}
/**
@ -90,7 +72,18 @@ public class FormattedNumber implements FormattedValue {
*/
@Override
public CharSequence subSequence(int start, int end) {
return nsb.subString(start, end);
return string.subString(start, end);
}
/**
* {@inheritDoc}
*
* @draft ICU 60
* @provisional This API might change or be removed in a future release.
*/
@Override
public <A extends Appendable> A appendTo(A appendable) {
return Utility.appendTo(string, appendable);
}
/**
@ -101,7 +94,18 @@ public class FormattedNumber implements FormattedValue {
*/
@Override
public boolean nextPosition(ConstrainedFieldPosition cfpos) {
return nsb.nextPosition(cfpos, null);
return string.nextPosition(cfpos, null);
}
/**
* {@inheritDoc}
*
* @draft ICU 62
* @provisional This API might change or be removed in a future release.
*/
@Override
public AttributedCharacterIterator toCharacterIterator() {
return string.toCharacterIterator(null);
}
/**
@ -139,18 +143,7 @@ public class FormattedNumber implements FormattedValue {
*/
public boolean nextFieldPosition(FieldPosition fieldPosition) {
fq.populateUFieldPosition(fieldPosition);
return nsb.nextFieldPosition(fieldPosition);
}
/**
* {@inheritDoc}
*
* @draft ICU 62
* @provisional This API might change or be removed in a future release.
*/
@Override
public AttributedCharacterIterator toCharacterIterator() {
return nsb.toCharacterIterator(null);
return string.nextFieldPosition(fieldPosition);
}
/**
@ -186,8 +179,8 @@ public class FormattedNumber implements FormattedValue {
public int hashCode() {
// NumberStringBuilder and BigDecimal are mutable, so we can't call
// #equals() or #hashCode() on them directly.
return Arrays.hashCode(nsb.toCharArray())
^ Arrays.hashCode(nsb.toFieldArray())
return Arrays.hashCode(string.toCharArray())
^ Arrays.hashCode(string.toFieldArray())
^ fq.toBigDecimal().hashCode();
}
@ -208,8 +201,8 @@ public class FormattedNumber implements FormattedValue {
// NumberStringBuilder and BigDecimal are mutable, so we can't call
// #equals() or #hashCode() on them directly.
FormattedNumber _other = (FormattedNumber) other;
return Arrays.equals(nsb.toCharArray(), _other.nsb.toCharArray())
&& Arrays.equals(nsb.toFieldArray(), _other.nsb.toFieldArray())
return Arrays.equals(string.toCharArray(), _other.string.toCharArray())
&& Arrays.equals(string.toFieldArray(), _other.string.toFieldArray())
&& fq.toBigDecimal().equals(_other.fq.toBigDecimal());
}
}

View file

@ -448,6 +448,10 @@ public final class RelativeDateTimeFormatter {
* Represents the result of a formatting operation of a relative datetime.
* Access the string value or field information.
*
* Instances of this class are immutable and thread-safe.
*
* Not intended for public subclassing.
*
* @author sffc
* @draft ICU 64
* @provisional This API might change or be removed in a future release.