diff --git a/icu4c/source/i18n/Makefile.in b/icu4c/source/i18n/Makefile.in index 03617fe1b64..d030efa8a7d 100644 --- a/icu4c/source/i18n/Makefile.in +++ b/icu4c/source/i18n/Makefile.in @@ -112,7 +112,7 @@ numparse_stringsegment.o numparse_parsednumber.o numparse_impl.o \ numparse_symbols.o numparse_decimal.o numparse_scientific.o numparse_currency.o \ numparse_affixes.o numparse_compositions.o numparse_validators.o \ numrange_fluent.o numrange_impl.o \ -erarules.o formattedvalue.o +erarules.o formattedvalue.o formattedval_iterimpl.o ## Header files to install HEADERS = $(srcdir)/unicode/*.h diff --git a/icu4c/source/i18n/formattedval_impl.h b/icu4c/source/i18n/formattedval_impl.h new file mode 100644 index 00000000000..f6e00a2b4a2 --- /dev/null +++ b/icu4c/source/i18n/formattedval_impl.h @@ -0,0 +1,55 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#ifndef __FORMVAL_IMPL_H__ +#define __FORMVAL_IMPL_H__ + +#include "unicode/utypes.h" +#if !UCONFIG_NO_FORMATTING + +// This file contains compliant implementations of FormattedValue which can be +// leveraged by ICU formatters. +// +// Each implementation is defined in its own cpp file in order to split +// dependencies more modularly. + +#include "unicode/formattedvalue.h" +#include "fphdlimp.h" +#include "uvectr32.h" +#include "util.h" + +U_NAMESPACE_BEGIN + + +/** Implementation using FieldPositionHandler to accept fields. */ +class FormattedValueFieldPositionIteratorImpl : public UMemory, public FormattedValue { +public: + + /** @param initialFieldCapacity Initially allocate space for this many fields. */ + FormattedValueFieldPositionIteratorImpl(int32_t initialFieldCapacity, UErrorCode& status); + + virtual ~FormattedValueFieldPositionIteratorImpl(); + + // Implementation of FormattedValue (const): + + UnicodeString toString(UErrorCode& status) const U_OVERRIDE; + UnicodeString toTempString(UErrorCode& status) const U_OVERRIDE; + Appendable& appendTo(Appendable& appendable, UErrorCode& status) const U_OVERRIDE; + UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const U_OVERRIDE; + + // Additional methods used during construction phase only (non-const): + + FieldPositionIteratorHandler getHandler(UErrorCode& status); + void appendString(UnicodeString string, UErrorCode& status); + +private: + // Final data: + UnicodeString fString; + UVector32 fFields; +}; + + +U_NAMESPACE_END + +#endif /* #if !UCONFIG_NO_FORMATTING */ +#endif // __FORMVAL_IMPL_H__ diff --git a/icu4c/source/i18n/formattedval_iterimpl.cpp b/icu4c/source/i18n/formattedval_iterimpl.cpp new file mode 100644 index 00000000000..fc981b3b2b9 --- /dev/null +++ b/icu4c/source/i18n/formattedval_iterimpl.cpp @@ -0,0 +1,87 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +// This file contains one implementation of FormattedValue. +// Other independent implementations should go into their own cpp file for +// better dependency modularization. + +#include "formattedval_impl.h" + +U_NAMESPACE_BEGIN + + +FormattedValueFieldPositionIteratorImpl::FormattedValueFieldPositionIteratorImpl( + int32_t initialFieldCapacity, + UErrorCode& status) + : fFields(initialFieldCapacity * 4, status) { +} + +FormattedValueFieldPositionIteratorImpl::~FormattedValueFieldPositionIteratorImpl() = default; + +UnicodeString FormattedValueFieldPositionIteratorImpl::toString( + UErrorCode&) const { + return fString; +} + +UnicodeString FormattedValueFieldPositionIteratorImpl::toTempString( + UErrorCode&) const { + UnicodeString ret; + ret.fastCopyFrom(fString); + return ret; +} + +Appendable& FormattedValueFieldPositionIteratorImpl::appendTo( + Appendable& appendable, + UErrorCode&) const { + appendable.appendString(fString.getBuffer(), fString.length()); + return appendable; +} + +UBool FormattedValueFieldPositionIteratorImpl::nextPosition( + ConstrainedFieldPosition& cfpos, + UErrorCode&) const { + U_ASSERT(fFields.size() % 4 == 0); + int32_t numFields = fFields.size() / 4; + int32_t i = cfpos.getInt64IterationContext(); + for (; i < numFields; i++) { + UFieldCategory category = static_cast(fFields.elementAti(i * 4)); + int32_t field = fFields.elementAti(i * 4 + 1); + if (cfpos.matchesField(category, field)) { + int32_t start = fFields.elementAti(i * 4 + 2); + int32_t limit = fFields.elementAti(i * 4 + 3); + cfpos.setState(category, field, start, limit); + break; + } + } + cfpos.setInt64IterationContext(i == numFields ? i : i + 1); + return i < numFields; +} + + +FieldPositionIteratorHandler FormattedValueFieldPositionIteratorImpl::getHandler( + UErrorCode& status) { + return FieldPositionIteratorHandler(&fFields, status); +} + +void FormattedValueFieldPositionIteratorImpl::appendString( + UnicodeString string, + UErrorCode& status) { + if (U_FAILURE(status)) { + return; + } + fString.append(string); + // Make the string NUL-terminated + if (fString.getTerminatedBuffer() == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + return; + } +} + + +U_NAMESPACE_END + +#endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/icu4c/source/i18n/fphdlimp.cpp b/icu4c/source/i18n/fphdlimp.cpp index c4015fae1bb..68bc1054c0b 100644 --- a/icu4c/source/i18n/fphdlimp.cpp +++ b/icu4c/source/i18n/fphdlimp.cpp @@ -62,12 +62,18 @@ FieldPositionOnlyHandler::isRecording(void) const { FieldPositionIteratorHandler::FieldPositionIteratorHandler(FieldPositionIterator* posIter, UErrorCode& _status) - : iter(posIter), vec(NULL), status(_status) { + : iter(posIter), vec(NULL), status(_status), fCategory(UFIELD_CATEGORY_UNDEFINED) { if (iter && U_SUCCESS(status)) { vec = new UVector32(status); } } +FieldPositionIteratorHandler::FieldPositionIteratorHandler( + UVector32* vec, + UErrorCode& status) + : iter(nullptr), vec(vec), status(status), fCategory(UFIELD_CATEGORY_UNDEFINED) { +} + FieldPositionIteratorHandler::~FieldPositionIteratorHandler() { // setData adopts the vec regardless of status, so it's safe to null it if (iter) { @@ -79,8 +85,9 @@ FieldPositionIteratorHandler::~FieldPositionIteratorHandler() { void FieldPositionIteratorHandler::addAttribute(int32_t id, int32_t start, int32_t limit) { - if (iter && U_SUCCESS(status) && start < limit) { + if (vec && U_SUCCESS(status) && start < limit) { int32_t size = vec->size(); + vec->addElement(fCategory, status); vec->addElement(id, status); vec->addElement(start + fShift, status); vec->addElement(limit + fShift, status); diff --git a/icu4c/source/i18n/fphdlimp.h b/icu4c/source/i18n/fphdlimp.h index 797682f93a9..3cec1e471f0 100644 --- a/icu4c/source/i18n/fphdlimp.h +++ b/icu4c/source/i18n/fphdlimp.h @@ -16,6 +16,7 @@ #include "unicode/fieldpos.h" #include "unicode/fpositer.h" +#include "unicode/formattedvalue.h" U_NAMESPACE_BEGIN @@ -57,6 +58,7 @@ class FieldPositionIteratorHandler : public FieldPositionHandler { FieldPositionIterator* iter; // can be NULL UVector32* vec; UErrorCode status; + UFieldCategory fCategory; // Note, we keep a reference to status, so if status is on the stack, we have // to be destroyed before status goes out of scope. Easiest thing is to @@ -70,11 +72,24 @@ class FieldPositionIteratorHandler : public FieldPositionHandler { public: FieldPositionIteratorHandler(FieldPositionIterator* posIter, UErrorCode& status); + /** If using this constructor, you must call getError() when done formatting! */ + FieldPositionIteratorHandler(UVector32* vec, UErrorCode& status); ~FieldPositionIteratorHandler(); void addAttribute(int32_t id, int32_t start, int32_t limit) U_OVERRIDE; void shiftLast(int32_t delta) U_OVERRIDE; UBool isRecording(void) const U_OVERRIDE; + + /** Copies a failed error code into _status. */ + inline void getError(UErrorCode& _status) { + if (U_SUCCESS(_status) && U_FAILURE(status)) { + _status = status; + } + } + + inline void setCategory(UFieldCategory category) { + fCategory = category; + } }; U_NAMESPACE_END diff --git a/icu4c/source/i18n/fpositer.cpp b/icu4c/source/i18n/fpositer.cpp index 47d4b3f9b14..75d529eb8c9 100644 --- a/icu4c/source/i18n/fpositer.cpp +++ b/icu4c/source/i18n/fpositer.cpp @@ -65,10 +65,10 @@ void FieldPositionIterator::setData(UVector32 *adopt, UErrorCode& status) { if (adopt->size() == 0) { delete adopt; adopt = NULL; - } else if ((adopt->size() % 3) != 0) { + } else if ((adopt->size() % 4) != 0) { status = U_ILLEGAL_ARGUMENT_ERROR; } else { - for (int i = 1; i < adopt->size(); i += 3) { + for (int i = 2; i < adopt->size(); i += 4) { if (adopt->elementAti(i) >= adopt->elementAti(i+1)) { status = U_ILLEGAL_ARGUMENT_ERROR; break; @@ -95,6 +95,8 @@ UBool FieldPositionIterator::next(FieldPosition& fp) { return FALSE; } + // Ignore the first element of the tetrad: used for field category + pos++; fp.setField(data->elementAti(pos++)); fp.setBeginIndex(data->elementAti(pos++)); fp.setEndIndex(data->elementAti(pos++)); diff --git a/icu4c/source/i18n/i18n.vcxproj b/icu4c/source/i18n/i18n.vcxproj index 4cccb5f3e6d..6072a1c3e2c 100644 --- a/icu4c/source/i18n/i18n.vcxproj +++ b/icu4c/source/i18n/i18n.vcxproj @@ -238,6 +238,7 @@ + @@ -559,6 +560,7 @@ + diff --git a/icu4c/source/i18n/i18n.vcxproj.filters b/icu4c/source/i18n/i18n.vcxproj.filters index ee6850555dc..6227485f26a 100644 --- a/icu4c/source/i18n/i18n.vcxproj.filters +++ b/icu4c/source/i18n/i18n.vcxproj.filters @@ -156,6 +156,9 @@ formatting + + formatting + formatting @@ -794,6 +797,9 @@ formatting + + formatting + formatting diff --git a/icu4c/source/i18n/i18n_uwp.vcxproj b/icu4c/source/i18n/i18n_uwp.vcxproj index 93ae76c8a34..bde119f895c 100644 --- a/icu4c/source/i18n/i18n_uwp.vcxproj +++ b/icu4c/source/i18n/i18n_uwp.vcxproj @@ -345,6 +345,7 @@ + @@ -664,6 +665,7 @@ + diff --git a/icu4c/source/test/depstest/dependencies.txt b/icu4c/source/test/depstest/dependencies.txt index 423469f7f26..93c79193cef 100644 --- a/icu4c/source/test/depstest/dependencies.txt +++ b/icu4c/source/test/depstest/dependencies.txt @@ -916,7 +916,7 @@ group: dayperiodrules group: listformatter listformatter.o ulistformatter.o deps - resourcebundle simpleformatter format uclean_i18n + resourcebundle simpleformatter format uclean_i18n formatted_value_iterimpl group: double_conversion double-conversion.o double-conversion-bignum.o double-conversion-bignum-dtoa.o @@ -1046,6 +1046,11 @@ group: formatted_value deps platform +group: formatted_value_iterimpl + formattedval_iterimpl.o + deps + formatted_value format uvector32 + group: format format.o fphdlimp.o fpositer.o ufieldpositer.o deps