ICU-20121 Initial UFormattedList implementation, C.

This commit is contained in:
Shane F. Carr 2019-02-04 22:24:00 -08:00
parent 5c1e3b8aaf
commit 37e589fb3a
4 changed files with 244 additions and 25 deletions

View File

@ -29,9 +29,9 @@ UnicodeString FormattedValueFieldPositionIteratorImpl::toString(
UnicodeString FormattedValueFieldPositionIteratorImpl::toTempString(
UErrorCode&) const {
UnicodeString ret;
ret.fastCopyFrom(fString);
return ret;
// The alias must point to memory owned by this object;
// fastCopyFrom doesn't do this when using a stack buffer.
return UnicodeString(TRUE, fString.getBuffer(), fString.length());
}
Appendable& FormattedValueFieldPositionIteratorImpl::appendTo(

View File

@ -15,6 +15,7 @@
#include "unicode/listformatter.h"
#include "unicode/localpointer.h"
#include "cmemory.h"
#include "formattedval_impl.h"
U_NAMESPACE_USE
@ -40,6 +41,49 @@ ulistfmt_close(UListFormatter *listfmt)
}
// Magic number: FLST in ASCII
UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL(
FormattedList,
UFormattedList,
UFormattedListImpl,
UFormattedListApiHelper,
ulistfmt,
0x464C5354)
static UnicodeString* getUnicodeStrings(
const UChar* const strings[],
const int32_t* stringLengths,
int32_t stringCount,
UnicodeString* length4StackBuffer,
LocalArray<UnicodeString>& maybeOwner,
UErrorCode& status) {
U_ASSERT(U_SUCCESS(status));
if (stringCount < 0 || (strings == NULL && stringCount > 0)) {
status = U_ILLEGAL_ARGUMENT_ERROR;
return nullptr;
}
UnicodeString* ustrings = length4StackBuffer;
if (stringCount > 4) {
maybeOwner.adoptInsteadAndCheckErrorCode(new UnicodeString[stringCount], status);
if (U_FAILURE(status)) {
return nullptr;
}
ustrings = maybeOwner.getAlias();
}
if (stringLengths == NULL) {
for (int32_t stringIndex = 0; stringIndex < stringCount; stringIndex++) {
ustrings[stringIndex].setTo(TRUE, strings[stringIndex], -1);
}
} else {
for (int32_t stringIndex = 0; stringIndex < stringCount; stringIndex++) {
ustrings[stringIndex].setTo(stringLengths[stringIndex] < 0, strings[stringIndex], stringLengths[stringIndex]);
}
}
return ustrings;
}
U_CAPI int32_t U_EXPORT2
ulistfmt_format(const UListFormatter* listfmt,
const UChar* const strings[],
@ -52,27 +96,16 @@ ulistfmt_format(const UListFormatter* listfmt,
if (U_FAILURE(*status)) {
return -1;
}
if (stringCount < 0 || (strings == NULL && stringCount > 0) || ((result == NULL)? resultCapacity != 0 : resultCapacity < 0)) {
if ((result == NULL) ? resultCapacity != 0 : resultCapacity < 0) {
*status = U_ILLEGAL_ARGUMENT_ERROR;
return -1;
}
UnicodeString ustringsStackBuf[4];
UnicodeString* ustrings = ustringsStackBuf;
if (stringCount > UPRV_LENGTHOF(ustringsStackBuf)) {
ustrings = new UnicodeString[stringCount];
if (ustrings == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
return -1;
}
}
if (stringLengths == NULL) {
for (int32_t stringIndex = 0; stringIndex < stringCount; stringIndex++) {
ustrings[stringIndex].setTo(TRUE, strings[stringIndex], -1);
}
} else {
for (int32_t stringIndex = 0; stringIndex < stringCount; stringIndex++) {
ustrings[stringIndex].setTo(stringLengths[stringIndex] < 0, strings[stringIndex], stringLengths[stringIndex]);
}
UnicodeString length4StackBuffer[4];
LocalArray<UnicodeString> maybeOwner;
UnicodeString* ustrings = getUnicodeStrings(
strings, stringLengths, stringCount, length4StackBuffer, maybeOwner, *status);
if (U_FAILURE(*status)) {
return -1;
}
UnicodeString res;
if (result != NULL) {
@ -80,12 +113,33 @@ ulistfmt_format(const UListFormatter* listfmt,
// otherwise, alias the destination buffer (copied from udat_format)
res.setTo(result, 0, resultCapacity);
}
((const ListFormatter*)listfmt)->format( ustrings, stringCount, res, *status );
if (ustrings != ustringsStackBuf) {
delete[] ustrings;
}
reinterpret_cast<const ListFormatter*>(listfmt)->format( ustrings, stringCount, res, *status );
return res.extract(result, resultCapacity, *status);
}
U_CAPI void U_EXPORT2
ulistfmt_formatStringsToValue(
const UListFormatter* listfmt,
const UChar* const strings[],
const int32_t * stringLengths,
int32_t stringCount,
UFormattedList* uresult,
UErrorCode* status) {
auto* result = UFormattedListApiHelper::validate(uresult, *status);
if (U_FAILURE(*status)) {
return;
}
UnicodeString length4StackBuffer[4];
LocalArray<UnicodeString> maybeOwner;
UnicodeString* ustrings = getUnicodeStrings(
strings, stringLengths, stringCount, length4StackBuffer, maybeOwner, *status);
if (U_FAILURE(*status)) {
return;
}
result->fImpl = reinterpret_cast<const ListFormatter*>(listfmt)
->formatStringsToValue(ustrings, stringCount, *status);
}
#endif /* #if !UCONFIG_NO_FORMATTING */

View File

@ -15,6 +15,7 @@
#if !UCONFIG_NO_FORMATTING
#include "unicode/localpointer.h"
#include "unicode/uformattedvalue.h"
/**
* \file
@ -33,6 +34,13 @@
struct UListFormatter;
typedef struct UListFormatter UListFormatter; /**< C typedef for struct UListFormatter. @stable ICU 55 */
struct UFormattedList;
/**
* Opaque struct to contain the results of a UListFormatter operation.
* @draft ICU 64
*/
typedef struct UFormattedList UFormattedList;
#ifndef U_HIDE_DRAFT_API
/**
* FieldPosition and UFieldPosition selectors for format fields
@ -82,6 +90,44 @@ ulistfmt_open(const char* locale,
U_CAPI void U_EXPORT2
ulistfmt_close(UListFormatter *listfmt);
/**
* Creates an object to hold the result of a UListFormatter
* operation. The object can be used repeatedly; it is cleared whenever
* passed to a format function.
*
* @param ec Set if an error occurs.
* @return A pointer needing ownership.
* @draft ICU 64
*/
U_CAPI UFormattedList* U_EXPORT2
ulistfmt_openResult(UErrorCode* ec);
/**
* Returns a representation of a UFormattedList as a UFormattedValue,
* which can be subsequently passed to any API requiring that type.
*
* The returned object is owned by the UFormattedList and is valid
* only as long as the UFormattedList is present and unchanged in memory.
*
* You can think of this method as a cast between types.
*
* @param uresult The object containing the formatted string.
* @param ec Set if an error occurs.
* @return A UFormattedValue owned by the input object.
* @draft ICU 64
*/
U_CAPI const UFormattedValue* U_EXPORT2
ulistfmt_resultAsValue(const UFormattedList* uresult, UErrorCode* ec);
/**
* Releases the UFormattedList created by ulistfmt_openResult().
*
* @param uresult The object to release.
* @draft ICU 64
*/
U_CAPI void U_EXPORT2
ulistfmt_closeResult(UFormattedList* uresult);
#if U_SHOW_CPLUSPLUS_API
@ -98,6 +144,17 @@ U_NAMESPACE_BEGIN
*/
U_DEFINE_LOCAL_OPEN_POINTER(LocalUListFormatterPointer, UListFormatter, ulistfmt_close);
/**
* \class LocalUFormattedListPointer
* "Smart pointer" class, closes a UFormattedList via ulistfmt_closeResult().
* For most methods see the LocalPointerBase base class.
*
* @see LocalPointerBase
* @see LocalPointer
* @stable ICU 55
*/
U_DEFINE_LOCAL_OPEN_POINTER(LocalUFormattedListPointer, UFormattedList, ulistfmt_closeResult);
U_NAMESPACE_END
#endif
@ -145,6 +202,40 @@ ulistfmt_format(const UListFormatter* listfmt,
int32_t resultCapacity,
UErrorCode* status);
/**
* Formats a list of strings to a UFormattedList, which exposes more
* information than the string exported by ulistfmt_format().
*
* @param listfmt
* The UListFormatter object specifying the list conventions.
* @param strings
* An array of pointers to UChar strings; the array length is
* specified by stringCount. Must be non-NULL if stringCount > 0.
* @param stringLengths
* An array of string lengths corresponding to the strings[]
* parameter; any individual length value may be negative to indicate
* that the corresponding strings[] entry is 0-terminated, or
* stringLengths itself may be NULL if all of the strings are
* 0-terminated. If non-NULL, the stringLengths array must have
* stringCount entries.
* @param stringCount
* the number of entries in strings[], and the number of entries
* in the stringLengths array if it is not NULL. Must be >= 0.
* @param uresult
* The object in which to store the result of the list formatting
* operation. See ulistfmt_openResult().
* @param status
* Error code set if an error occurred during formatting.
*/
U_CAPI void U_EXPORT2
ulistfmt_formatStringsToValue(
const UListFormatter* listfmt,
const UChar* const strings[],
const int32_t * stringLengths,
int32_t stringCount,
UFormattedList* uresult,
UErrorCode* status);
#endif /* #if !UCONFIG_NO_FORMATTING */
#endif

View File

@ -15,8 +15,10 @@
#include "cintltst.h"
#include "cmemory.h"
#include "cstring.h"
#include "cformtst.h"
static void TestUListFmt(void);
static void TestUListFmtToValue(void);
void addUListFmtTest(TestNode** root);
@ -25,6 +27,7 @@ void addUListFmtTest(TestNode** root);
void addUListFmtTest(TestNode** root)
{
TESTCASE(TestUListFmt);
TESTCASE(TestUListFmtToValue);
}
static const UChar str0[] = { 0x41,0 }; /* "A" */
@ -126,5 +129,76 @@ static void TestUListFmt() {
}
}
static void TestUListFmtToValue() {
UErrorCode ec = U_ZERO_ERROR;
UListFormatter* fmt = ulistfmt_open("en", &ec);
UFormattedList* fl = ulistfmt_openResult(&ec);
assertSuccess("Opening", &ec);
{
const char* message = "Field position test 1";
const UChar* expectedString = u"hello, wonderful, and world";
const UChar* inputs[] = {
u"hello",
u"wonderful",
u"world"
};
ulistfmt_formatStringsToValue(fmt, inputs, NULL, UPRV_LENGTHOF(inputs), fl, &ec);
assertSuccess("Formatting", &ec);
static const UFieldPositionWithCategory expectedFieldPositions[] = {
// field, begin index, end index
{UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 0, 5},
{UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 7, 16},
{UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 22, 27},
{UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 5, 7},
{UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 16, 22}};
checkMixedFormattedValue(
message,
ulistfmt_resultAsValue(fl, &ec),
expectedString,
expectedFieldPositions,
UPRV_LENGTHOF(expectedFieldPositions));
}
{
const char* message = "Field position test 1";
const UChar* expectedString = u"A, B, C, D, E, F, and G";
const UChar* inputs[] = {
u"A",
u"B",
u"C",
u"D",
u"E",
u"F",
u"G"
};
ulistfmt_formatStringsToValue(fmt, inputs, NULL, UPRV_LENGTHOF(inputs), fl, &ec);
assertSuccess("Formatting", &ec);
static const UFieldPositionWithCategory expectedFieldPositions[] = {
// field, begin index, end index
{UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 0, 1},
{UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 3, 4},
{UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 6, 7},
{UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 9, 10},
{UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 12, 13},
{UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 15, 16},
{UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 22, 23},
{UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 1, 3},
{UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 4, 6},
{UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 7, 9},
{UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 10, 12},
{UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 13, 15},
{UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 16, 22}};
checkMixedFormattedValue(
message,
ulistfmt_resultAsValue(fl, &ec),
expectedString,
expectedFieldPositions,
UPRV_LENGTHOF(expectedFieldPositions));
}
ulistfmt_close(fmt);
ulistfmt_closeResult(fl);
}
#endif /* #if !UCONFIG_NO_FORMATTING */