ICU-20138 Adding FormattedValue helper implementation for FPI handlers.

- Changes FieldPositionIterator (FPI) to use tetrads in the UVector32.
This commit is contained in:
Shane F. Carr 2019-02-04 18:45:56 -08:00
parent 9bb910b8d0
commit 1624176dd9
10 changed files with 187 additions and 6 deletions

View file

@ -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

View file

@ -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__

View file

@ -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<UFieldCategory>(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 */

View file

@ -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);

View file

@ -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

View file

@ -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++));

View file

@ -238,6 +238,7 @@
<ClCompile Include="fmtable.cpp" />
<ClCompile Include="fmtable_cnv.cpp" />
<ClCompile Include="format.cpp" />
<ClCompile Include="formattedval_iterimpl.cpp" />
<ClCompile Include="formattedvalue.cpp" />
<ClCompile Include="fphdlimp.cpp" />
<ClCompile Include="fpositer.cpp" />
@ -559,6 +560,7 @@
<ClInclude Include="numparse_types.h" />
<ClInclude Include="numparse_utils.h" />
<ClInclude Include="numrange_impl.h" />
<ClInclude Include="formattedval_impl.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="i18n.rc" />

View file

@ -156,6 +156,9 @@
<ClCompile Include="format.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="formattedval_iterimpl.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="formattedvalue.cpp">
<Filter>formatting</Filter>
</ClCompile>
@ -794,6 +797,9 @@
<ClInclude Include="ethpccal.h">
<Filter>formatting</Filter>
</ClInclude>
<ClInclude Include="formattedval_impl.h">
<Filter>formatting</Filter>
</ClInclude>
<ClInclude Include="fphdlimp.h">
<Filter>formatting</Filter>
</ClInclude>

View file

@ -345,6 +345,7 @@
<ClCompile Include="fmtable.cpp" />
<ClCompile Include="fmtable_cnv.cpp" />
<ClCompile Include="format.cpp" />
<ClCompile Include="formattedval_iterimpl.cpp" />
<ClCompile Include="formattedvalue.cpp" />
<ClCompile Include="fphdlimp.cpp" />
<ClCompile Include="fpositer.cpp" />
@ -664,6 +665,7 @@
<ClInclude Include="numparse_types.h" />
<ClInclude Include="numparse_utils.h" />
<ClInclude Include="numrange_impl.h" />
<ClInclude Include="formattedval_impl.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="i18n.rc" />

View file

@ -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