ICU-11303 Bring MeasureFormat per unit formatting out of tech preview.
X-SVN-Rev: 36813
This commit is contained in:
parent
3d248f9875
commit
79964e6bc7
@ -248,9 +248,10 @@ ListFormatter::~ListFormatter() {
|
||||
* On entry offset is an offset into first or -1 if offset unspecified.
|
||||
* On exit offset is offset of second in result if recordOffset was set
|
||||
* Otherwise if it was >=0 it is set to point into result where it used
|
||||
* to point into first.
|
||||
* to point into first. On exit, result is the join of first and second
|
||||
* according to pat. Any previous value of result gets replaced.
|
||||
*/
|
||||
static void joinStrings(
|
||||
static void joinStringsAndReplace(
|
||||
const SimplePatternFormatter& pat,
|
||||
const UnicodeString& first,
|
||||
const UnicodeString& second,
|
||||
@ -263,7 +264,7 @@ static void joinStrings(
|
||||
}
|
||||
const UnicodeString *params[2] = {&first, &second};
|
||||
int32_t offsets[2];
|
||||
pat.format(
|
||||
pat.formatAndReplace(
|
||||
params,
|
||||
UPRV_LENGTHOF(params),
|
||||
result,
|
||||
@ -319,69 +320,43 @@ UnicodeString& ListFormatter::format(
|
||||
appendTo.append(items[0]);
|
||||
return appendTo;
|
||||
}
|
||||
if (nItems == 2) {
|
||||
UnicodeString result(items[0]);
|
||||
if (index == 0) {
|
||||
offset = 0;
|
||||
}
|
||||
joinStrings(
|
||||
data->twoPattern,
|
||||
items[0],
|
||||
joinStringsAndReplace(
|
||||
nItems == 2 ? data->twoPattern : data->startPattern,
|
||||
result,
|
||||
items[1],
|
||||
appendTo,
|
||||
result,
|
||||
index == 1,
|
||||
offset,
|
||||
errorCode);
|
||||
return appendTo;
|
||||
}
|
||||
UnicodeString temp[2];
|
||||
if (index == 0) {
|
||||
offset = 0;
|
||||
}
|
||||
joinStrings(
|
||||
data->startPattern,
|
||||
items[0],
|
||||
items[1],
|
||||
temp[0],
|
||||
index == 1,
|
||||
offset,
|
||||
errorCode);
|
||||
int32_t i;
|
||||
int32_t pos = 0;
|
||||
int32_t npos = 0;
|
||||
UBool startsWithZeroPlaceholder =
|
||||
data->middlePattern.startsWithPlaceholder(0);
|
||||
for (i = 2; i < nItems - 1; ++i) {
|
||||
if (!startsWithZeroPlaceholder) {
|
||||
npos = (pos + 1) & 1;
|
||||
temp[npos].remove();
|
||||
}
|
||||
joinStrings(
|
||||
if (nItems > 2) {
|
||||
for (int32_t i = 2; i < nItems - 1; ++i) {
|
||||
joinStringsAndReplace(
|
||||
data->middlePattern,
|
||||
temp[pos],
|
||||
result,
|
||||
items[i],
|
||||
temp[npos],
|
||||
result,
|
||||
index == i,
|
||||
offset,
|
||||
errorCode);
|
||||
pos = npos;
|
||||
}
|
||||
if (!data->endPattern.startsWithPlaceholder(0)) {
|
||||
npos = (pos + 1) & 1;
|
||||
temp[npos].remove();
|
||||
}
|
||||
joinStrings(
|
||||
joinStringsAndReplace(
|
||||
data->endPattern,
|
||||
temp[pos],
|
||||
result,
|
||||
items[nItems - 1],
|
||||
temp[npos],
|
||||
result,
|
||||
index == nItems - 1,
|
||||
offset,
|
||||
errorCode);
|
||||
}
|
||||
if (U_SUCCESS(errorCode)) {
|
||||
if (offset >= 0) {
|
||||
offset += appendTo.length();
|
||||
}
|
||||
appendTo += temp[npos];
|
||||
appendTo += result;
|
||||
}
|
||||
return appendTo;
|
||||
}
|
||||
|
@ -11,20 +11,38 @@
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
static UBool isInvalidArray(const void *array, int32_t size) {
|
||||
return (size < 0 || (size > 0 && array == NULL));
|
||||
}
|
||||
|
||||
typedef enum SimplePatternFormatterCompileState {
|
||||
INIT,
|
||||
APOSTROPHE,
|
||||
PLACEHOLDER
|
||||
} SimplePatternFormatterCompileState;
|
||||
|
||||
// Handles parsing placeholders in the pattern string, e.g {4} or {35}
|
||||
class SimplePatternFormatterIdBuilder {
|
||||
public:
|
||||
SimplePatternFormatterIdBuilder() : id(0), idLen(0) { }
|
||||
~SimplePatternFormatterIdBuilder() { }
|
||||
|
||||
// Resets so that this object has seen no placeholder ID.
|
||||
void reset() { id = 0; idLen = 0; }
|
||||
|
||||
// Returns the numeric placeholder ID parsed so far
|
||||
int32_t getId() const { return id; }
|
||||
|
||||
// Appends the numeric placeholder ID parsed so far back to a
|
||||
// UChar buffer. Used to recover if parser using this object finds
|
||||
// no closing curly brace.
|
||||
void appendTo(UChar *buffer, int32_t *len) const;
|
||||
|
||||
// Returns true if this object has seen a placeholder ID.
|
||||
UBool isValid() const { return (idLen > 0); }
|
||||
|
||||
// Processes a single digit character. Pattern string parser calls this
|
||||
// as it processes digits after an opening curly brace.
|
||||
void add(UChar ch);
|
||||
private:
|
||||
int32_t id;
|
||||
@ -52,18 +70,81 @@ void SimplePatternFormatterIdBuilder::add(UChar ch) {
|
||||
idLen++;
|
||||
}
|
||||
|
||||
// Represents placeholder values.
|
||||
class SimplePatternFormatterPlaceholderValues : public UMemory {
|
||||
public:
|
||||
SimplePatternFormatterPlaceholderValues(
|
||||
const UnicodeString * const *values,
|
||||
int32_t valuesCount);
|
||||
|
||||
// Returns TRUE if appendTo value is at any index besides exceptIndex.
|
||||
UBool isAppendToInAnyIndexExcept(
|
||||
const UnicodeString &appendTo, int32_t exceptIndex) const;
|
||||
|
||||
// For each appendTo value, stores the snapshot of it in its place.
|
||||
void snapshotAppendTo(const UnicodeString &appendTo);
|
||||
|
||||
// Returns the placeholder value at index. No range checking performed.
|
||||
// Returned reference is valid for as long as this object exists.
|
||||
const UnicodeString &get(int32_t index) const;
|
||||
private:
|
||||
const UnicodeString * const *fValues;
|
||||
int32_t fValuesCount;
|
||||
const UnicodeString *fAppendTo;
|
||||
UnicodeString fAppendToCopy;
|
||||
SimplePatternFormatterPlaceholderValues(
|
||||
const SimplePatternFormatterPlaceholderValues &);
|
||||
SimplePatternFormatterPlaceholderValues &operator=(
|
||||
const SimplePatternFormatterPlaceholderValues &);
|
||||
};
|
||||
|
||||
SimplePatternFormatterPlaceholderValues::SimplePatternFormatterPlaceholderValues(
|
||||
const UnicodeString * const *values,
|
||||
int32_t valuesCount)
|
||||
: fValues(values),
|
||||
fValuesCount(valuesCount),
|
||||
fAppendTo(NULL),
|
||||
fAppendToCopy() {
|
||||
}
|
||||
|
||||
UBool SimplePatternFormatterPlaceholderValues::isAppendToInAnyIndexExcept(
|
||||
const UnicodeString &appendTo, int32_t exceptIndex) const {
|
||||
for (int32_t i = 0; i < fValuesCount; ++i) {
|
||||
if (i != exceptIndex && fValues[i] == &appendTo) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void SimplePatternFormatterPlaceholderValues::snapshotAppendTo(
|
||||
const UnicodeString &appendTo) {
|
||||
fAppendTo = &appendTo;
|
||||
fAppendToCopy = appendTo;
|
||||
}
|
||||
|
||||
const UnicodeString &SimplePatternFormatterPlaceholderValues::get(
|
||||
int32_t index) const {
|
||||
if (fAppendTo == NULL || fAppendTo != fValues[index]) {
|
||||
return *fValues[index];
|
||||
}
|
||||
return fAppendToCopy;
|
||||
}
|
||||
|
||||
SimplePatternFormatter::SimplePatternFormatter() :
|
||||
noPlaceholders(),
|
||||
placeholders(),
|
||||
placeholderSize(0),
|
||||
placeholderCount(0) {
|
||||
placeholderCount(0),
|
||||
firstPlaceholderReused(FALSE) {
|
||||
}
|
||||
|
||||
SimplePatternFormatter::SimplePatternFormatter(const UnicodeString &pattern) :
|
||||
noPlaceholders(),
|
||||
placeholders(),
|
||||
placeholderSize(0),
|
||||
placeholderCount(0) {
|
||||
placeholderCount(0),
|
||||
firstPlaceholderReused(FALSE) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
compile(pattern, status);
|
||||
}
|
||||
@ -73,7 +154,8 @@ SimplePatternFormatter::SimplePatternFormatter(
|
||||
noPlaceholders(other.noPlaceholders),
|
||||
placeholders(),
|
||||
placeholderSize(0),
|
||||
placeholderCount(other.placeholderCount) {
|
||||
placeholderCount(other.placeholderCount),
|
||||
firstPlaceholderReused(other.firstPlaceholderReused) {
|
||||
placeholderSize = ensureCapacity(other.placeholderSize);
|
||||
uprv_memcpy(
|
||||
placeholders.getAlias(),
|
||||
@ -89,6 +171,7 @@ SimplePatternFormatter &SimplePatternFormatter::operator=(
|
||||
noPlaceholders = other.noPlaceholders;
|
||||
placeholderSize = ensureCapacity(other.placeholderSize);
|
||||
placeholderCount = other.placeholderCount;
|
||||
firstPlaceholderReused = other.firstPlaceholderReused;
|
||||
uprv_memcpy(
|
||||
placeholders.getAlias(),
|
||||
other.placeholders.getAlias(),
|
||||
@ -175,19 +258,12 @@ UBool SimplePatternFormatter::compile(
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
UBool SimplePatternFormatter::startsWithPlaceholder(int32_t id) const {
|
||||
if (placeholderSize == 0) {
|
||||
return FALSE;
|
||||
}
|
||||
return (placeholders[0].offset == 0 && placeholders[0].id == id);
|
||||
}
|
||||
|
||||
UnicodeString& SimplePatternFormatter::format(
|
||||
const UnicodeString &arg0,
|
||||
UnicodeString &appendTo,
|
||||
UErrorCode &status) const {
|
||||
const UnicodeString *params[] = {&arg0};
|
||||
return format(
|
||||
return formatAndAppend(
|
||||
params,
|
||||
UPRV_LENGTHOF(params),
|
||||
appendTo,
|
||||
@ -202,7 +278,7 @@ UnicodeString& SimplePatternFormatter::format(
|
||||
UnicodeString &appendTo,
|
||||
UErrorCode &status) const {
|
||||
const UnicodeString *params[] = {&arg0, &arg1};
|
||||
return format(
|
||||
return formatAndAppend(
|
||||
params,
|
||||
UPRV_LENGTHOF(params),
|
||||
appendTo,
|
||||
@ -218,7 +294,7 @@ UnicodeString& SimplePatternFormatter::format(
|
||||
UnicodeString &appendTo,
|
||||
UErrorCode &status) const {
|
||||
const UnicodeString *params[] = {&arg0, &arg1, &arg2};
|
||||
return format(
|
||||
return formatAndAppend(
|
||||
params,
|
||||
UPRV_LENGTHOF(params),
|
||||
appendTo,
|
||||
@ -242,10 +318,14 @@ static void appendRange(
|
||||
int32_t start,
|
||||
int32_t end,
|
||||
UnicodeString &dest) {
|
||||
// This check improves performance significantly.
|
||||
if (start == end) {
|
||||
return;
|
||||
}
|
||||
dest.append(src, start, end - start);
|
||||
}
|
||||
|
||||
UnicodeString& SimplePatternFormatter::format(
|
||||
UnicodeString& SimplePatternFormatter::formatAndAppend(
|
||||
const UnicodeString * const *placeholderValues,
|
||||
int32_t placeholderValueCount,
|
||||
UnicodeString &appendTo,
|
||||
@ -255,10 +335,102 @@ UnicodeString& SimplePatternFormatter::format(
|
||||
if (U_FAILURE(status)) {
|
||||
return appendTo;
|
||||
}
|
||||
if (isInvalidArray(placeholderValues, placeholderValueCount)
|
||||
|| isInvalidArray(offsetArray, offsetArrayLength)) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return appendTo;
|
||||
}
|
||||
if (placeholderValueCount < placeholderCount) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return appendTo;
|
||||
}
|
||||
|
||||
// Since we are disallowing parameter values that are the same as
|
||||
// appendTo, we have to check all placeholderValues as opposed to
|
||||
// the first placeholderCount placeholder values.
|
||||
SimplePatternFormatterPlaceholderValues values(
|
||||
placeholderValues, placeholderValueCount);
|
||||
if (values.isAppendToInAnyIndexExcept(appendTo, -1)) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return appendTo;
|
||||
}
|
||||
return formatAndAppend(
|
||||
values,
|
||||
appendTo,
|
||||
offsetArray,
|
||||
offsetArrayLength);
|
||||
}
|
||||
|
||||
UnicodeString& SimplePatternFormatter::formatAndReplace(
|
||||
const UnicodeString * const *placeholderValues,
|
||||
int32_t placeholderValueCount,
|
||||
UnicodeString &result,
|
||||
int32_t *offsetArray,
|
||||
int32_t offsetArrayLength,
|
||||
UErrorCode &status) const {
|
||||
if (U_FAILURE(status)) {
|
||||
return result;
|
||||
}
|
||||
if (isInvalidArray(placeholderValues, placeholderValueCount)
|
||||
|| isInvalidArray(offsetArray, offsetArrayLength)) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return result;
|
||||
}
|
||||
if (placeholderValueCount < placeholderCount) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return result;
|
||||
}
|
||||
SimplePatternFormatterPlaceholderValues values(
|
||||
placeholderValues, placeholderCount);
|
||||
int32_t placeholderAtStart = getUniquePlaceholderAtStart();
|
||||
|
||||
// If pattern starts with a unique placeholder and that placeholder
|
||||
// value is result, we may be able to optimize by just appending to result.
|
||||
if (placeholderAtStart >= 0
|
||||
&& placeholderValues[placeholderAtStart] == &result) {
|
||||
|
||||
// If result is the value for other placeholders, call off optimization.
|
||||
if (values.isAppendToInAnyIndexExcept(result, placeholderAtStart)) {
|
||||
values.snapshotAppendTo(result);
|
||||
result.remove();
|
||||
return formatAndAppend(
|
||||
values,
|
||||
result,
|
||||
offsetArray,
|
||||
offsetArrayLength);
|
||||
}
|
||||
|
||||
// Otherwise we can optimize
|
||||
formatAndAppend(
|
||||
values,
|
||||
result,
|
||||
offsetArray,
|
||||
offsetArrayLength);
|
||||
|
||||
// We have to make the offset for the placeholderAtStart
|
||||
// placeholder be 0. Otherwise it would be the length of the
|
||||
// previous value of result.
|
||||
if (offsetArrayLength > placeholderAtStart) {
|
||||
offsetArray[placeholderAtStart] = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
if (values.isAppendToInAnyIndexExcept(result, -1)) {
|
||||
values.snapshotAppendTo(result);
|
||||
}
|
||||
result.remove();
|
||||
return formatAndAppend(
|
||||
values,
|
||||
result,
|
||||
offsetArray,
|
||||
offsetArrayLength);
|
||||
}
|
||||
|
||||
UnicodeString& SimplePatternFormatter::formatAndAppend(
|
||||
const SimplePatternFormatterPlaceholderValues &values,
|
||||
UnicodeString &appendTo,
|
||||
int32_t *offsetArray,
|
||||
int32_t offsetArrayLength) const {
|
||||
for (int32_t i = 0; i < offsetArrayLength; ++i) {
|
||||
offsetArray[i] = -1;
|
||||
}
|
||||
@ -266,8 +438,6 @@ UnicodeString& SimplePatternFormatter::format(
|
||||
appendTo.append(noPlaceholders);
|
||||
return appendTo;
|
||||
}
|
||||
if (placeholders[0].offset > 0 ||
|
||||
placeholderValues[placeholders[0].id] != &appendTo) {
|
||||
appendRange(
|
||||
noPlaceholders,
|
||||
0,
|
||||
@ -278,13 +448,9 @@ UnicodeString& SimplePatternFormatter::format(
|
||||
appendTo.length(),
|
||||
offsetArray,
|
||||
offsetArrayLength);
|
||||
appendTo.append(*placeholderValues[placeholders[0].id]);
|
||||
} else {
|
||||
updatePlaceholderOffset(
|
||||
placeholders[0].id,
|
||||
0,
|
||||
offsetArray,
|
||||
offsetArrayLength);
|
||||
const UnicodeString *placeholderValue = &values.get(placeholders[0].id);
|
||||
if (placeholderValue != &appendTo) {
|
||||
appendTo.append(*placeholderValue);
|
||||
}
|
||||
for (int32_t i = 1; i < placeholderSize; ++i) {
|
||||
appendRange(
|
||||
@ -297,7 +463,10 @@ UnicodeString& SimplePatternFormatter::format(
|
||||
appendTo.length(),
|
||||
offsetArray,
|
||||
offsetArrayLength);
|
||||
appendTo.append(*placeholderValues[placeholders[i].id]);
|
||||
placeholderValue = &values.get(placeholders[i].id);
|
||||
if (placeholderValue != &appendTo) {
|
||||
appendTo.append(*placeholderValue);
|
||||
}
|
||||
}
|
||||
appendRange(
|
||||
noPlaceholders,
|
||||
@ -307,6 +476,14 @@ UnicodeString& SimplePatternFormatter::format(
|
||||
return appendTo;
|
||||
}
|
||||
|
||||
int32_t SimplePatternFormatter::getUniquePlaceholderAtStart() const {
|
||||
if (placeholderSize == 0
|
||||
|| firstPlaceholderReused || placeholders[0].offset != 0) {
|
||||
return -1;
|
||||
}
|
||||
return placeholders[0].id;
|
||||
}
|
||||
|
||||
int32_t SimplePatternFormatter::ensureCapacity(
|
||||
int32_t desiredCapacity, int32_t allocationSize) {
|
||||
if (allocationSize < desiredCapacity) {
|
||||
@ -333,6 +510,10 @@ UBool SimplePatternFormatter::addPlaceholder(int32_t id, int32_t offset) {
|
||||
if (id >= placeholderCount) {
|
||||
placeholderCount = id + 1;
|
||||
}
|
||||
if (placeholderSize > 1
|
||||
&& placeholders[placeholderSize - 1].id == placeholders[0].id) {
|
||||
firstPlaceholderReused = TRUE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,8 @@
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
class SimplePatternFormatterPlaceholderValues;
|
||||
|
||||
struct PlaceholderInfo {
|
||||
int32_t id;
|
||||
int32_t offset;
|
||||
@ -39,7 +41,7 @@ struct PlaceholderInfo {
|
||||
* UnicodeString result;
|
||||
* UErrorCode status = U_ZERO_ERROR;
|
||||
* // Evaluates to: "paul {born} in england"
|
||||
* fmt.format("englad", "paul", result, status);
|
||||
* fmt.format("england", "paul", result, status);
|
||||
* </pre>
|
||||
*/
|
||||
class U_COMMON_API SimplePatternFormatter : public UMemory {
|
||||
@ -90,12 +92,6 @@ public:
|
||||
return placeholderCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the pattern this object represents starts with
|
||||
* placeholder id; otherwise, returns false.
|
||||
*/
|
||||
UBool startsWithPlaceholder(int32_t id) const;
|
||||
|
||||
/**
|
||||
* Returns this pattern with none of the placeholders.
|
||||
*/
|
||||
@ -104,7 +100,7 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats given value.
|
||||
* Formats given value. arg0 cannot be appendTo.
|
||||
*/
|
||||
UnicodeString &format(
|
||||
const UnicodeString &args0,
|
||||
@ -112,7 +108,7 @@ public:
|
||||
UErrorCode &status) const;
|
||||
|
||||
/**
|
||||
* Formats given values.
|
||||
* Formats given values. Neither arg0 nor arg1 can be appendTo.
|
||||
*/
|
||||
UnicodeString &format(
|
||||
const UnicodeString &args0,
|
||||
@ -121,7 +117,7 @@ public:
|
||||
UErrorCode &status) const;
|
||||
|
||||
/**
|
||||
* Formats given values.
|
||||
* Formats given values. Neither arg0, arg1, nor arg2 can be appendTo.
|
||||
*/
|
||||
UnicodeString &format(
|
||||
const UnicodeString &args0,
|
||||
@ -135,37 +131,82 @@ public:
|
||||
*
|
||||
* The caller retains ownership of all pointers.
|
||||
* @param placeholderValues 1st one corresponds to {0}; 2nd to {1};
|
||||
* 3rd to {2} etc.
|
||||
* 3rd to {2} etc. If any of these point to appendTo, this method
|
||||
* sets status to U_ILLEGAL_ARGUMENT_ERROR.
|
||||
* @param placeholderValueCount the number of placeholder values
|
||||
* must be at least large enough to provide values for all placeholders
|
||||
* in this object. Otherwise status set to U_ILLEGAL_ARGUMENT_ERROR.
|
||||
* @param appendTo resulting string appended here. Optimization: If
|
||||
* the pattern this object represents starts with a placeholder AND
|
||||
* appendTo references the value of that same placeholder, then that
|
||||
* placeholder value is not copied to appendTo (Its already there).
|
||||
* If the value of the starting placeholder is a very large string,
|
||||
* this optimization can offer huge savings.
|
||||
* @param appendTo resulting string appended here.
|
||||
* @param offsetArray The offset of each placeholder value in appendTo
|
||||
* stored here. The first value gets the offset of the value for {0};
|
||||
* the 2nd for {1}; the 3rd for {2} etc. -1 means that the corresponding
|
||||
* placeholder does not exist in this object. If caller is not
|
||||
* interested in offsets, it may pass NULL and 0 for the length.
|
||||
* @param offsetArrayLength the size of offsetArray may be less than
|
||||
* placeholderValueCount.
|
||||
* @param offsetArrayLength the size of offsetArray. If less than
|
||||
* placeholderValueCount only the first offsets get recorded. If
|
||||
* greater than placeholderValueCount, then extra values in offset
|
||||
* array are set to -1.
|
||||
* @param status any error stored here.
|
||||
*/
|
||||
UnicodeString &format(
|
||||
UnicodeString &formatAndAppend(
|
||||
const UnicodeString * const *placeholderValues,
|
||||
int32_t placeholderValueCount,
|
||||
UnicodeString &appendTo,
|
||||
int32_t *offsetArray,
|
||||
int32_t offsetArrayLength,
|
||||
UErrorCode &status) const;
|
||||
|
||||
/**
|
||||
* Formats given values.
|
||||
*
|
||||
* The caller retains ownership of all pointers.
|
||||
* @param placeholderValues 1st one corresponds to {0}; 2nd to {1};
|
||||
* 3rd to {2} etc. May include pointer to result in which case
|
||||
* the previous value of result is used for the corresponding
|
||||
* placeholder.
|
||||
* @param placeholderValueCount the number of placeholder values
|
||||
* must be at least large enough to provide values for all placeholders
|
||||
* in this object. Otherwise status set to U_ILLEGAL_ARGUMENT_ERROR.
|
||||
* @param result resulting string stored here overwriting any previous
|
||||
* value.
|
||||
* @param offsetArray The offset of each placeholder value in result
|
||||
* stored here. The first value gets the offset of the value for {0};
|
||||
* the 2nd for {1}; the 3rd for {2} etc. -1 means that the corresponding
|
||||
* placeholder does not exist in this object. If caller is not
|
||||
* interested in offsets, it may pass NULL and 0 for the length.
|
||||
* @param offsetArrayLength the size of offsetArray. If less than
|
||||
* placeholderValueCount only the first offsets get recorded. If
|
||||
* greater than placeholderValueCount, then extra values in offset
|
||||
* array are set to -1.
|
||||
* @param status any error stored here.
|
||||
*/
|
||||
UnicodeString &formatAndReplace(
|
||||
const UnicodeString * const *placeholderValues,
|
||||
int32_t placeholderValueCount,
|
||||
UnicodeString &result,
|
||||
int32_t *offsetArray,
|
||||
int32_t offsetArrayLength,
|
||||
UErrorCode &status) const;
|
||||
private:
|
||||
UnicodeString noPlaceholders;
|
||||
MaybeStackArray<PlaceholderInfo, 3> placeholders;
|
||||
int32_t placeholderSize;
|
||||
int32_t placeholderCount;
|
||||
UBool firstPlaceholderReused;
|
||||
|
||||
// A Placeholder value that is the same as appendTo is treated as the
|
||||
// empty string.
|
||||
UnicodeString &formatAndAppend(
|
||||
const SimplePatternFormatterPlaceholderValues &placeholderValues,
|
||||
UnicodeString &appendTo,
|
||||
int32_t *offsetArray,
|
||||
int32_t offsetArrayLength) const;
|
||||
|
||||
// Returns the placeholder at the beginning of this pattern
|
||||
// (e.g 3 for placeholder {3}). Returns -1 if the beginning of pattern
|
||||
// is text or if the placeholder at the beginning of this pattern
|
||||
// is used again in the middle of the pattern.
|
||||
int32_t getUniquePlaceholderAtStart() const;
|
||||
|
||||
// ensureCapacity ensures that the capacity of the placeholders array
|
||||
// is desiredCapacity. If ensureCapacity must resize the placeholders
|
||||
|
@ -590,18 +590,27 @@ void MeasureFormat::parseObject(
|
||||
return;
|
||||
}
|
||||
|
||||
UnicodeString &MeasureFormat::formatMeasuresPer(
|
||||
const Measure *measures,
|
||||
int32_t measureCount,
|
||||
UnicodeString &MeasureFormat::formatMeasurePerUnit(
|
||||
const Measure &measure,
|
||||
const MeasureUnit &perUnit,
|
||||
UnicodeString &appendTo,
|
||||
FieldPosition &pos,
|
||||
UErrorCode &status) const {
|
||||
if (U_FAILURE(status)) {
|
||||
return appendTo;
|
||||
}
|
||||
MeasureUnit *resolvedUnit =
|
||||
MeasureUnit::resolveUnitPerUnit(measure.getUnit(), perUnit);
|
||||
if (resolvedUnit != NULL) {
|
||||
Measure newMeasure(measure.getNumber(), resolvedUnit, status);
|
||||
return formatMeasure(
|
||||
newMeasure, **numberFormat, appendTo, pos, status);
|
||||
}
|
||||
FieldPosition fpos(pos.getField());
|
||||
UnicodeString measuresString;
|
||||
int32_t offset = withPerUnit(
|
||||
formatMeasures(
|
||||
measures, measureCount, measuresString, fpos, status),
|
||||
UnicodeString result;
|
||||
int32_t offset = withPerUnitAndAppend(
|
||||
formatMeasure(
|
||||
measure, **numberFormat, result, fpos, status),
|
||||
perUnit,
|
||||
appendTo,
|
||||
status);
|
||||
@ -979,7 +988,7 @@ static void getPerUnitString(
|
||||
result.trim();
|
||||
}
|
||||
|
||||
int32_t MeasureFormat::withPerUnit(
|
||||
int32_t MeasureFormat::withPerUnitAndAppend(
|
||||
const UnicodeString &formatted,
|
||||
const MeasureUnit &perUnit,
|
||||
UnicodeString &appendTo,
|
||||
@ -992,7 +1001,7 @@ int32_t MeasureFormat::withPerUnit(
|
||||
perUnit.getIndex(), widthToIndex(width));
|
||||
if (perUnitFormatter != NULL) {
|
||||
const UnicodeString *params[] = {&formatted};
|
||||
perUnitFormatter->format(
|
||||
perUnitFormatter->formatAndAppend(
|
||||
params,
|
||||
UPRV_LENGTHOF(params),
|
||||
appendTo,
|
||||
@ -1011,7 +1020,7 @@ int32_t MeasureFormat::withPerUnit(
|
||||
UnicodeString perUnitString;
|
||||
getPerUnitString(*qf, perUnitString);
|
||||
const UnicodeString *params[] = {&formatted, &perUnitString};
|
||||
perFormatter->format(
|
||||
perFormatter->formatAndAppend(
|
||||
params,
|
||||
UPRV_LENGTHOF(params),
|
||||
appendTo,
|
||||
|
@ -27,7 +27,7 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MeasureUnit)
|
||||
// the "End generated code" comment is auto generated code
|
||||
// and must not be edited manually. For instructions on how to correctly
|
||||
// update this code, refer to:
|
||||
// https://sites.google.com/site/icusite/design/formatting/measureformat/updating-measure-unit
|
||||
// http://site.icu-project.org/design/formatting/measureformat/updating-measure-unit
|
||||
//
|
||||
// Start generated code
|
||||
|
||||
@ -77,6 +77,7 @@ static const int32_t gIndexes[] = {
|
||||
121
|
||||
};
|
||||
|
||||
// Must be sorted alphabetically.
|
||||
static const char * const gTypes[] = {
|
||||
"acceleration",
|
||||
"angle",
|
||||
@ -99,6 +100,7 @@ static const char * const gTypes[] = {
|
||||
"volume"
|
||||
};
|
||||
|
||||
// Must be grouped by type and sorted alphabetically within each type.
|
||||
static const char * const gSubTypes[] = {
|
||||
"g-force",
|
||||
"meter-per-second-squared",
|
||||
@ -483,6 +485,16 @@ static const char * const gSubTypes[] = {
|
||||
"teaspoon"
|
||||
};
|
||||
|
||||
// Must be sorted by first value and then second value.
|
||||
static int32_t unitPerUnitToSingleUnit[][4] = {
|
||||
{318, 288, 16, 0},
|
||||
{320, 294, 16, 1},
|
||||
{322, 288, 16, 2},
|
||||
{322, 372, 3, 1},
|
||||
{338, 10, 14, 4},
|
||||
{374, 318, 3, 0}
|
||||
};
|
||||
|
||||
MeasureUnit *MeasureUnit::createGForce(UErrorCode &status) {
|
||||
return MeasureUnit::create(0, 0, status);
|
||||
}
|
||||
@ -1100,6 +1112,34 @@ int32_t MeasureUnit::getIndexCount() {
|
||||
return gIndexes[UPRV_LENGTHOF(gIndexes) - 1];
|
||||
}
|
||||
|
||||
MeasureUnit *MeasureUnit::resolveUnitPerUnit(
|
||||
const MeasureUnit &unit, const MeasureUnit &perUnit) {
|
||||
int32_t unitOffset = unit.getOffset();
|
||||
int32_t perUnitOffset = perUnit.getOffset();
|
||||
|
||||
// binary search for (unitOffset, perUnitOffset)
|
||||
int32_t start = 0;
|
||||
int32_t end = UPRV_LENGTHOF(unitPerUnitToSingleUnit);
|
||||
while (start < end) {
|
||||
int32_t mid = (start + end) / 2;
|
||||
int32_t *midRow = unitPerUnitToSingleUnit[mid];
|
||||
if (unitOffset < midRow[0]) {
|
||||
end = mid;
|
||||
} else if (unitOffset > midRow[0]) {
|
||||
start = mid + 1;
|
||||
} else if (perUnitOffset < midRow[1]) {
|
||||
end = mid;
|
||||
} else if (perUnitOffset > midRow[1]) {
|
||||
start = mid + 1;
|
||||
} else {
|
||||
// We found a resolution for our unit / per-unit combo
|
||||
// return it.
|
||||
return new MeasureUnit(midRow[2], midRow[3]);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MeasureUnit *MeasureUnit::create(int typeId, int subTypeId, UErrorCode &status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return NULL;
|
||||
|
@ -170,7 +170,13 @@ UnicodeString &QuantityFormatter::format(
|
||||
fmt.format(quantity, formattedNumber, fpos, status);
|
||||
const UnicodeString *params[1] = {&formattedNumber};
|
||||
int32_t offsets[1];
|
||||
pattern->format(params, UPRV_LENGTHOF(params), appendTo, offsets, UPRV_LENGTHOF(offsets), status);
|
||||
pattern->formatAndAppend(
|
||||
params,
|
||||
UPRV_LENGTHOF(params),
|
||||
appendTo,
|
||||
offsets,
|
||||
UPRV_LENGTHOF(offsets),
|
||||
status);
|
||||
if (offsets[0] != -1) {
|
||||
if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) {
|
||||
pos.setBeginIndex(fpos.getBeginIndex() + offsets[0]);
|
||||
|
@ -190,31 +190,28 @@ class U_I18N_API MeasureFormat : public Format {
|
||||
UnicodeString &appendTo,
|
||||
FieldPosition &pos,
|
||||
UErrorCode &status) const;
|
||||
#endif /* U_HIDE_DRAFT_API */
|
||||
|
||||
#ifndef U_HIDE_INTERNAL_API
|
||||
/**
|
||||
* Works like formatMeasures but adds a per unit. An example of such a
|
||||
* formatted string is 3 meters, 3.5 centimeters per second.
|
||||
* @param measures array of measure objects.
|
||||
* @param measureCount the number of measure objects.
|
||||
* @param perUnit The per unit. In the example formatted string,
|
||||
* it is *MeasureUnit::createSecond(status).
|
||||
* Formats a single measure per unit. An example of such a
|
||||
* formatted string is 3.5 meters per second.
|
||||
* @param measure The measure object. In above example, 3.5 meters.
|
||||
* @param perUnit The per unit. In above example, it is
|
||||
* *MeasureUnit::createSecond(status).
|
||||
* @param appendTo formatted string appended here.
|
||||
* @param pos the field position.
|
||||
* @param status the error.
|
||||
* @return appendTo reference
|
||||
*
|
||||
* @internal Technology preview
|
||||
* @draft ICU 55
|
||||
*/
|
||||
UnicodeString &formatMeasuresPer(
|
||||
const Measure *measures,
|
||||
int32_t measureCount,
|
||||
UnicodeString &formatMeasurePerUnit(
|
||||
const Measure &measure,
|
||||
const MeasureUnit &perUnit,
|
||||
UnicodeString &appendTo,
|
||||
FieldPosition &pos,
|
||||
UErrorCode &status) const;
|
||||
#endif /* U_HIDE_INTERNAL_API */
|
||||
|
||||
#endif /* U_HIDE_DRAFT_API */
|
||||
|
||||
/**
|
||||
* Return a formatter for CurrencyAmount objects in the given
|
||||
@ -347,7 +344,7 @@ class U_I18N_API MeasureFormat : public Format {
|
||||
int32_t widthIndex,
|
||||
UErrorCode &status) const;
|
||||
|
||||
int32_t withPerUnit(
|
||||
int32_t withPerUnitAndAppend(
|
||||
const UnicodeString &formatted,
|
||||
const MeasureUnit &perUnit,
|
||||
UnicodeString &appendTo,
|
||||
|
@ -184,13 +184,20 @@ class U_I18N_API MeasureUnit: public UObject {
|
||||
* @internal
|
||||
*/
|
||||
static int32_t getIndexCount();
|
||||
|
||||
/**
|
||||
* ICU use only.
|
||||
* @internal
|
||||
*/
|
||||
static MeasureUnit *resolveUnitPerUnit(
|
||||
const MeasureUnit &unit, const MeasureUnit &perUnit);
|
||||
#endif /* U_HIDE_INTERNAL_API */
|
||||
|
||||
// All code between the "Start generated createXXX methods" comment and
|
||||
// the "End generated createXXX methods" comment is auto generated code
|
||||
// and must not be edited manually. For instructions on how to correctly
|
||||
// update this code, refer to:
|
||||
// https://sites.google.com/site/icusite/design/formatting/measureformat/updating-measure-unit
|
||||
// http://site.icu-project.org/design/formatting/measureformat/updating-measure-unit
|
||||
//
|
||||
// Start generated createXXX methods
|
||||
|
||||
|
@ -47,7 +47,6 @@ private:
|
||||
void TestGreek();
|
||||
void TestFormatSingleArg();
|
||||
void TestFormatMeasuresZeroArg();
|
||||
void TestMultiplesWithPer();
|
||||
void TestSimplePer();
|
||||
void TestNumeratorPlurals();
|
||||
void TestMultiples();
|
||||
@ -55,11 +54,11 @@ private:
|
||||
void TestCurrencies();
|
||||
void TestFieldPosition();
|
||||
void TestFieldPositionMultiple();
|
||||
void TestFieldPositionMultipleWithPer();
|
||||
void TestBadArg();
|
||||
void TestEquality();
|
||||
void TestGroupingSeparator();
|
||||
void TestDoubleZero();
|
||||
void TestUnitPerUnitResolution();
|
||||
void verifyFormat(
|
||||
const char *description,
|
||||
const MeasureFormat &fmt,
|
||||
@ -85,11 +84,16 @@ private:
|
||||
const MeasureUnit &unit,
|
||||
const MeasureUnit &perUnit,
|
||||
const char *expected);
|
||||
void helperTestMultiplesWithPer(
|
||||
void helperTestSimplePer(
|
||||
const Locale &locale,
|
||||
UMeasureFormatWidth width,
|
||||
double value,
|
||||
const MeasureUnit &unit,
|
||||
const char *expected);
|
||||
const MeasureUnit &perUnit,
|
||||
const char *expected,
|
||||
int32_t field,
|
||||
int32_t expected_start,
|
||||
int32_t expected_end);
|
||||
void helperTestMultiples(
|
||||
const Locale &locale,
|
||||
UMeasureFormatWidth width,
|
||||
@ -103,16 +107,6 @@ private:
|
||||
NumberFormat::EAlignmentFields field,
|
||||
int32_t start,
|
||||
int32_t end);
|
||||
void verifyFieldPositionWithPer(
|
||||
const char *description,
|
||||
const MeasureFormat &fmt,
|
||||
const UnicodeString &prefix,
|
||||
const Measure *measures,
|
||||
int32_t measureCount,
|
||||
const MeasureUnit &perUnit,
|
||||
NumberFormat::EAlignmentFields field,
|
||||
int32_t start,
|
||||
int32_t end);
|
||||
};
|
||||
|
||||
void MeasureFormatTest::runIndexedTest(
|
||||
@ -131,7 +125,6 @@ void MeasureFormatTest::runIndexedTest(
|
||||
TESTCASE_AUTO(TestGreek);
|
||||
TESTCASE_AUTO(TestFormatSingleArg);
|
||||
TESTCASE_AUTO(TestFormatMeasuresZeroArg);
|
||||
TESTCASE_AUTO(TestMultiplesWithPer);
|
||||
TESTCASE_AUTO(TestSimplePer);
|
||||
TESTCASE_AUTO(TestNumeratorPlurals);
|
||||
TESTCASE_AUTO(TestMultiples);
|
||||
@ -139,11 +132,11 @@ void MeasureFormatTest::runIndexedTest(
|
||||
TESTCASE_AUTO(TestCurrencies);
|
||||
TESTCASE_AUTO(TestFieldPosition);
|
||||
TESTCASE_AUTO(TestFieldPositionMultiple);
|
||||
TESTCASE_AUTO(TestFieldPositionMultipleWithPer);
|
||||
TESTCASE_AUTO(TestBadArg);
|
||||
TESTCASE_AUTO(TestEquality);
|
||||
TESTCASE_AUTO(TestGroupingSeparator);
|
||||
TESTCASE_AUTO(TestDoubleZero);
|
||||
TESTCASE_AUTO(TestUnitPerUnitResolution);
|
||||
TESTCASE_AUTO_END;
|
||||
}
|
||||
|
||||
@ -871,32 +864,6 @@ void MeasureFormatTest::TestFormatMeasuresZeroArg() {
|
||||
verifyFormat("TestFormatMeasuresZeroArg", fmt, NULL, 0, "");
|
||||
}
|
||||
|
||||
void MeasureFormatTest::TestMultiplesWithPer() {
|
||||
Locale en("en");
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
LocalPointer<MeasureUnit> second(MeasureUnit::createSecond(status));
|
||||
LocalPointer<MeasureUnit> minute(MeasureUnit::createMinute(status));
|
||||
if (!assertSuccess("", status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Per unit test.
|
||||
helperTestMultiplesWithPer(
|
||||
en, UMEASFMT_WIDTH_WIDE, *second, "2 miles, 1 foot, 2.3 inches per second");
|
||||
helperTestMultiplesWithPer(
|
||||
en, UMEASFMT_WIDTH_SHORT, *second, "2 mi, 1 ft, 2.3 inps");
|
||||
helperTestMultiplesWithPer(
|
||||
en, UMEASFMT_WIDTH_NARROW, *second, "2mi 1\\u2032 2.3\\u2033/s");
|
||||
|
||||
// Fallback compound per test
|
||||
helperTestMultiplesWithPer(
|
||||
en, UMEASFMT_WIDTH_WIDE, *minute, "2 miles, 1 foot, 2.3 inches per minute");
|
||||
helperTestMultiplesWithPer(
|
||||
en, UMEASFMT_WIDTH_SHORT, *minute, "2 mi, 1 ft, 2.3 in/min");
|
||||
helperTestMultiplesWithPer(
|
||||
en, UMEASFMT_WIDTH_NARROW, *minute, "2mi 1\\u2032 2.3\\u2033/m");
|
||||
}
|
||||
|
||||
void MeasureFormatTest::TestSimplePer() {
|
||||
Locale en("en");
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
@ -907,6 +874,19 @@ void MeasureFormatTest::TestSimplePer() {
|
||||
return;
|
||||
}
|
||||
|
||||
helperTestSimplePer(
|
||||
en, UMEASFMT_WIDTH_WIDE,
|
||||
1.0, *pound, *second, "1 pound per second");
|
||||
helperTestSimplePer(
|
||||
en, UMEASFMT_WIDTH_WIDE,
|
||||
2.0, *pound, *second, "2 pounds per second");
|
||||
helperTestSimplePer(
|
||||
en, UMEASFMT_WIDTH_WIDE,
|
||||
1.0, *pound, *minute, "1 pound per minute");
|
||||
helperTestSimplePer(
|
||||
en, UMEASFMT_WIDTH_WIDE,
|
||||
2.0, *pound, *minute, "2 pounds per minute");
|
||||
|
||||
helperTestSimplePer(
|
||||
en, UMEASFMT_WIDTH_SHORT, 1.0, *pound, *second, "1 lbps");
|
||||
helperTestSimplePer(
|
||||
@ -915,6 +895,39 @@ void MeasureFormatTest::TestSimplePer() {
|
||||
en, UMEASFMT_WIDTH_SHORT, 1.0, *pound, *minute, "1 lb/min");
|
||||
helperTestSimplePer(
|
||||
en, UMEASFMT_WIDTH_SHORT, 2.0, *pound, *minute, "2 lb/min");
|
||||
|
||||
helperTestSimplePer(
|
||||
en, UMEASFMT_WIDTH_NARROW, 1.0, *pound, *second, "1#/s");
|
||||
helperTestSimplePer(
|
||||
en, UMEASFMT_WIDTH_NARROW, 2.0, *pound, *second, "2#/s");
|
||||
helperTestSimplePer(
|
||||
en, UMEASFMT_WIDTH_NARROW, 1.0, *pound, *minute, "1#/m");
|
||||
helperTestSimplePer(
|
||||
en, UMEASFMT_WIDTH_NARROW, 2.0, *pound, *minute, "2#/m");
|
||||
|
||||
helperTestSimplePer(
|
||||
en, UMEASFMT_WIDTH_SHORT,
|
||||
23.3, *pound, *second, "23.3 lbps",
|
||||
NumberFormat::kDecimalSeparatorField,
|
||||
2, 3);
|
||||
|
||||
helperTestSimplePer(
|
||||
en, UMEASFMT_WIDTH_SHORT,
|
||||
23.3, *pound, *second, "23.3 lbps",
|
||||
NumberFormat::kIntegerField,
|
||||
0, 2);
|
||||
|
||||
helperTestSimplePer(
|
||||
en, UMEASFMT_WIDTH_SHORT,
|
||||
23.3, *pound, *minute, "23.3 lb/min",
|
||||
NumberFormat::kDecimalSeparatorField,
|
||||
2, 3);
|
||||
|
||||
helperTestSimplePer(
|
||||
en, UMEASFMT_WIDTH_SHORT,
|
||||
23.3, *pound, *minute, "23.3 lb/min",
|
||||
NumberFormat::kIntegerField,
|
||||
0, 2);
|
||||
}
|
||||
|
||||
void MeasureFormatTest::TestNumeratorPlurals() {
|
||||
@ -927,13 +940,20 @@ void MeasureFormatTest::TestNumeratorPlurals() {
|
||||
}
|
||||
|
||||
helperTestSimplePer(
|
||||
pl, UMEASFMT_WIDTH_WIDE, 1.0, *foot, *second, "1 stopa na sekund\\u0119");
|
||||
pl,
|
||||
UMEASFMT_WIDTH_WIDE,
|
||||
1.0, *foot, *second, "1 stopa na sekund\\u0119");
|
||||
helperTestSimplePer(
|
||||
pl, UMEASFMT_WIDTH_WIDE, 2.0, *foot, *second, "2 stopy na sekund\\u0119");
|
||||
pl,
|
||||
UMEASFMT_WIDTH_WIDE,
|
||||
2.0, *foot, *second, "2 stopy na sekund\\u0119");
|
||||
helperTestSimplePer(
|
||||
pl, UMEASFMT_WIDTH_WIDE, 5.0, *foot, *second, "5 st\\u00f3p na sekund\\u0119");
|
||||
pl,
|
||||
UMEASFMT_WIDTH_WIDE,
|
||||
5.0, *foot, *second, "5 st\\u00f3p na sekund\\u0119");
|
||||
helperTestSimplePer(
|
||||
pl, UMEASFMT_WIDTH_WIDE, 1.5, *foot, *second, "1,5 stopy na sekund\\u0119");
|
||||
pl, UMEASFMT_WIDTH_WIDE,
|
||||
1.5, *foot, *second, "1,5 stopy na sekund\\u0119");
|
||||
}
|
||||
|
||||
void MeasureFormatTest::helperTestSimplePer(
|
||||
@ -943,8 +963,30 @@ void MeasureFormatTest::helperTestSimplePer(
|
||||
const MeasureUnit &unit,
|
||||
const MeasureUnit &perUnit,
|
||||
const char *expected) {
|
||||
helperTestSimplePer(
|
||||
locale,
|
||||
width,
|
||||
value,
|
||||
unit,
|
||||
perUnit,
|
||||
expected,
|
||||
FieldPosition::DONT_CARE,
|
||||
0,
|
||||
0);
|
||||
}
|
||||
|
||||
void MeasureFormatTest::helperTestSimplePer(
|
||||
const Locale &locale,
|
||||
UMeasureFormatWidth width,
|
||||
double value,
|
||||
const MeasureUnit &unit,
|
||||
const MeasureUnit &perUnit,
|
||||
const char *expected,
|
||||
int32_t field,
|
||||
int32_t expected_start,
|
||||
int32_t expected_end) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
FieldPosition pos(0);
|
||||
FieldPosition pos(field);
|
||||
MeasureFormat fmt(locale, width, status);
|
||||
if (!assertSuccess("Error creating format object", status)) {
|
||||
return;
|
||||
@ -953,10 +995,10 @@ void MeasureFormatTest::helperTestSimplePer(
|
||||
if (!assertSuccess("Error creating measure object", status)) {
|
||||
return;
|
||||
}
|
||||
UnicodeString buffer;
|
||||
fmt.formatMeasuresPer(
|
||||
&measure,
|
||||
1,
|
||||
UnicodeString prefix("prefix: ");
|
||||
UnicodeString buffer(prefix);
|
||||
fmt.formatMeasurePerUnit(
|
||||
measure,
|
||||
perUnit,
|
||||
buffer,
|
||||
pos,
|
||||
@ -964,45 +1006,18 @@ void MeasureFormatTest::helperTestSimplePer(
|
||||
if (!assertSuccess("Error formatting measures with per", status)) {
|
||||
return;
|
||||
}
|
||||
UnicodeString uexpected(expected);
|
||||
uexpected = prefix + uexpected;
|
||||
assertEquals(
|
||||
"TestSimplePer",
|
||||
UnicodeString(expected).unescape(),
|
||||
uexpected.unescape(),
|
||||
buffer);
|
||||
}
|
||||
|
||||
void MeasureFormatTest::helperTestMultiplesWithPer(
|
||||
const Locale &locale,
|
||||
UMeasureFormatWidth width,
|
||||
const MeasureUnit &perUnit,
|
||||
const char *expected) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
FieldPosition pos(0);
|
||||
MeasureFormat fmt(locale, width, status);
|
||||
if (!assertSuccess("Error creating format object", status)) {
|
||||
return;
|
||||
}
|
||||
Measure measures[] = {
|
||||
Measure(2, MeasureUnit::createMile(status), status),
|
||||
Measure(1, MeasureUnit::createFoot(status), status),
|
||||
Measure(2.3, MeasureUnit::createInch(status), status)};
|
||||
if (!assertSuccess("Error creating measures", status)) {
|
||||
return;
|
||||
}
|
||||
UnicodeString buffer;
|
||||
fmt.formatMeasuresPer(
|
||||
measures,
|
||||
UPRV_LENGTHOF(measures),
|
||||
perUnit,
|
||||
buffer,
|
||||
pos,
|
||||
status);
|
||||
if (!assertSuccess("Error formatting measures with per", status)) {
|
||||
return;
|
||||
}
|
||||
if (field != FieldPosition::DONT_CARE) {
|
||||
assertEquals(
|
||||
"TestMultiplesWithPer",
|
||||
UnicodeString(expected).unescape(),
|
||||
buffer);
|
||||
"Start", expected_start, pos.getBeginIndex() - prefix.length());
|
||||
assertEquals(
|
||||
"End", expected_end, pos.getEndIndex() - prefix.length());
|
||||
}
|
||||
}
|
||||
|
||||
void MeasureFormatTest::TestMultiples() {
|
||||
@ -1181,99 +1196,6 @@ void MeasureFormatTest::TestFieldPositionMultiple() {
|
||||
0);
|
||||
}
|
||||
|
||||
void MeasureFormatTest::TestFieldPositionMultipleWithPer() {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
MeasureFormat fmt("en", UMEASFMT_WIDTH_SHORT, status);
|
||||
if (!assertSuccess("Error creating format object", status)) {
|
||||
return;
|
||||
}
|
||||
Measure first[] = {
|
||||
Measure(354, MeasureUnit::createMeter(status), status),
|
||||
Measure(23, MeasureUnit::createCentimeter(status), status)};
|
||||
Measure second[] = {
|
||||
Measure(354, MeasureUnit::createMeter(status), status),
|
||||
Measure(23, MeasureUnit::createCentimeter(status), status),
|
||||
Measure(5.4, MeasureUnit::createMillimeter(status), status)};
|
||||
Measure third[] = {
|
||||
Measure(3, MeasureUnit::createMeter(status), status),
|
||||
Measure(23, MeasureUnit::createCentimeter(status), status),
|
||||
Measure(5, MeasureUnit::createMillimeter(status), status)};
|
||||
if (!assertSuccess("Error creating measure objects", status)) {
|
||||
return;
|
||||
}
|
||||
UnicodeString prefix("123456: ");
|
||||
|
||||
LocalPointer<MeasureUnit> secondUnit(MeasureUnit::createSecond(status));
|
||||
LocalPointer<MeasureUnit> minuteUnit(MeasureUnit::createMinute(status));
|
||||
if (!assertSuccess("Error creating format object", status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// per unit test
|
||||
verifyFieldPositionWithPer(
|
||||
"Integer",
|
||||
fmt,
|
||||
prefix,
|
||||
first,
|
||||
UPRV_LENGTHOF(first),
|
||||
*secondUnit,
|
||||
NumberFormat::kIntegerField,
|
||||
8,
|
||||
11);
|
||||
verifyFieldPositionWithPer(
|
||||
"Decimal separator",
|
||||
fmt,
|
||||
prefix,
|
||||
second,
|
||||
UPRV_LENGTHOF(second),
|
||||
*secondUnit,
|
||||
NumberFormat::kDecimalSeparatorField,
|
||||
23,
|
||||
24);
|
||||
verifyFieldPositionWithPer(
|
||||
"no decimal separator",
|
||||
fmt,
|
||||
prefix,
|
||||
third,
|
||||
UPRV_LENGTHOF(third),
|
||||
*secondUnit,
|
||||
NumberFormat::kDecimalSeparatorField,
|
||||
0,
|
||||
0);
|
||||
|
||||
// Fallback to compound per test
|
||||
verifyFieldPositionWithPer(
|
||||
"Integer",
|
||||
fmt,
|
||||
prefix,
|
||||
first,
|
||||
UPRV_LENGTHOF(first),
|
||||
*minuteUnit,
|
||||
NumberFormat::kIntegerField,
|
||||
8,
|
||||
11);
|
||||
verifyFieldPositionWithPer(
|
||||
"Decimal separator",
|
||||
fmt,
|
||||
prefix,
|
||||
second,
|
||||
UPRV_LENGTHOF(second),
|
||||
*minuteUnit,
|
||||
NumberFormat::kDecimalSeparatorField,
|
||||
23,
|
||||
24);
|
||||
verifyFieldPositionWithPer(
|
||||
"no decimal separator",
|
||||
fmt,
|
||||
prefix,
|
||||
third,
|
||||
UPRV_LENGTHOF(third),
|
||||
*minuteUnit,
|
||||
NumberFormat::kDecimalSeparatorField,
|
||||
0,
|
||||
0);
|
||||
}
|
||||
|
||||
void MeasureFormatTest::TestBadArg() {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
MeasureFormat fmt("en", UMEASFMT_WIDTH_SHORT, status);
|
||||
@ -1379,6 +1301,26 @@ void MeasureFormatTest::TestDoubleZero() {
|
||||
appendTo);
|
||||
}
|
||||
|
||||
void MeasureFormatTest::TestUnitPerUnitResolution() {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
Locale en("en");
|
||||
MeasureFormat fmt("en", UMEASFMT_WIDTH_SHORT, status);
|
||||
Measure measure(50, MeasureUnit::createPound(status), status);
|
||||
LocalPointer<MeasureUnit> sqInch(MeasureUnit::createSquareInch(status));
|
||||
if (!assertSuccess("Create of format unit and per unit", status)) {
|
||||
return;
|
||||
}
|
||||
FieldPosition pos(0);
|
||||
UnicodeString actual;
|
||||
fmt.formatMeasurePerUnit(
|
||||
measure,
|
||||
*sqInch,
|
||||
actual,
|
||||
pos,
|
||||
status);
|
||||
assertEquals("", "50 psi", actual);
|
||||
}
|
||||
|
||||
void MeasureFormatTest::verifyFieldPosition(
|
||||
const char *description,
|
||||
const MeasureFormat &fmt,
|
||||
@ -1407,40 +1349,6 @@ void MeasureFormatTest::verifyFieldPosition(
|
||||
assertEquals(endIndex.data(), end, pos.getEndIndex());
|
||||
}
|
||||
|
||||
void MeasureFormatTest::verifyFieldPositionWithPer(
|
||||
const char *description,
|
||||
const MeasureFormat &fmt,
|
||||
const UnicodeString &prefix,
|
||||
const Measure *measures,
|
||||
int32_t measureCount,
|
||||
const MeasureUnit &perUnit,
|
||||
NumberFormat::EAlignmentFields field,
|
||||
int32_t start,
|
||||
int32_t end) {
|
||||
UnicodeString result(prefix);
|
||||
FieldPosition pos(field);
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
CharString ch;
|
||||
const char *descPrefix = ch.append(description, status)
|
||||
.append(": ", status).data();
|
||||
CharString beginIndex;
|
||||
beginIndex.append(descPrefix, status).append("beginIndex", status);
|
||||
CharString endIndex;
|
||||
endIndex.append(descPrefix, status).append("endIndex", status);
|
||||
fmt.formatMeasuresPer(
|
||||
measures,
|
||||
measureCount,
|
||||
perUnit,
|
||||
result,
|
||||
pos,
|
||||
status);
|
||||
if (!assertSuccess("Error formatting", status)) {
|
||||
return;
|
||||
}
|
||||
assertEquals(beginIndex.data(), start, pos.getBeginIndex());
|
||||
assertEquals(endIndex.data(), end, pos.getEndIndex());
|
||||
}
|
||||
|
||||
void MeasureFormatTest::verifyFormat(
|
||||
const char *description,
|
||||
const MeasureFormat &fmt,
|
||||
|
@ -19,10 +19,21 @@ public:
|
||||
void TestNoPlaceholders();
|
||||
void TestOnePlaceholder();
|
||||
void TestManyPlaceholders();
|
||||
void TestTooFewPlaceholderValues();
|
||||
void TestBadArguments();
|
||||
void TestGetPatternWithNoPlaceholders();
|
||||
void TestOptimization();
|
||||
void TestFormatReplaceNoOptimization();
|
||||
void TestFormatReplaceNoOptimizationLeadingText();
|
||||
void TestFormatReplaceOptimization();
|
||||
void TestFormatReplaceNoOptimizationLeadingPlaceholderUsedTwice();
|
||||
void TestFormatReplaceOptimizationNoOffsets();
|
||||
void TestFormatReplaceNoOptimizationNoOffsets();
|
||||
void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par=0);
|
||||
private:
|
||||
void verifyOffsets(
|
||||
const int32_t *expected,
|
||||
const int32_t *actual,
|
||||
int32_t count);
|
||||
};
|
||||
|
||||
void SimplePatternFormatterTest::runIndexedTest(int32_t index, UBool exec, const char* &name, char* /*par*/) {
|
||||
@ -30,8 +41,15 @@ void SimplePatternFormatterTest::runIndexedTest(int32_t index, UBool exec, const
|
||||
TESTCASE_AUTO(TestNoPlaceholders);
|
||||
TESTCASE_AUTO(TestOnePlaceholder);
|
||||
TESTCASE_AUTO(TestManyPlaceholders);
|
||||
TESTCASE_AUTO(TestTooFewPlaceholderValues);
|
||||
TESTCASE_AUTO(TestBadArguments);
|
||||
TESTCASE_AUTO(TestGetPatternWithNoPlaceholders);
|
||||
TESTCASE_AUTO(TestOptimization);
|
||||
TESTCASE_AUTO(TestFormatReplaceNoOptimization);
|
||||
TESTCASE_AUTO(TestFormatReplaceNoOptimizationLeadingText);
|
||||
TESTCASE_AUTO(TestFormatReplaceOptimization);
|
||||
TESTCASE_AUTO(TestFormatReplaceNoOptimizationLeadingPlaceholderUsedTwice);
|
||||
TESTCASE_AUTO(TestFormatReplaceOptimizationNoOffsets);
|
||||
TESTCASE_AUTO(TestFormatReplaceNoOptimizationNoOffsets);
|
||||
TESTCASE_AUTO_END;
|
||||
}
|
||||
|
||||
@ -58,13 +76,15 @@ void SimplePatternFormatterTest::TestOnePlaceholder() {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
SimplePatternFormatter fmt;
|
||||
fmt.compile("{0} meter", status);
|
||||
if (!assertSuccess("Status", status)) {
|
||||
return;
|
||||
}
|
||||
assertEquals("PlaceholderCount", 1, fmt.getPlaceholderCount());
|
||||
UnicodeString appendTo;
|
||||
assertEquals(
|
||||
"format",
|
||||
"1 meter",
|
||||
fmt.format("1", appendTo, status));
|
||||
assertSuccess("Status", status);
|
||||
|
||||
// assignment
|
||||
SimplePatternFormatter s;
|
||||
@ -90,8 +110,9 @@ void SimplePatternFormatterTest::TestManyPlaceholders() {
|
||||
SimplePatternFormatter fmt;
|
||||
fmt.compile(
|
||||
"Templates {2}{1}{5} and {4} are out of order.", status);
|
||||
assertSuccess("Status", status);
|
||||
assertFalse("startsWithPlaceholder", fmt.startsWithPlaceholder(2));
|
||||
if (!assertSuccess("Status", status)) {
|
||||
return;
|
||||
}
|
||||
assertEquals("PlaceholderCount", 6, fmt.getPlaceholderCount());
|
||||
UnicodeString values[] = {
|
||||
"freddy", "tommy", "frog", "billy", "leg", "{0}"};
|
||||
@ -103,38 +124,24 @@ void SimplePatternFormatterTest::TestManyPlaceholders() {
|
||||
assertEquals(
|
||||
"format",
|
||||
"Prefix: Templates frogtommy{0} and leg are out of order.",
|
||||
fmt.format(
|
||||
fmt.formatAndAppend(
|
||||
params,
|
||||
UPRV_LENGTHOF(params),
|
||||
appendTo,
|
||||
offsets,
|
||||
UPRV_LENGTHOF(offsets),
|
||||
status));
|
||||
assertSuccess("Status", status);
|
||||
for (int32_t i = 0; i < UPRV_LENGTHOF(expectedOffsets); ++i) {
|
||||
if (expectedOffsets[i] != offsets[i]) {
|
||||
errln("Expected %d, got %d", expectedOffsets[i], offsets[i]);
|
||||
}
|
||||
if (!assertSuccess("Status", status)) {
|
||||
return;
|
||||
}
|
||||
verifyOffsets(expectedOffsets, offsets, UPRV_LENGTHOF(expectedOffsets));
|
||||
appendTo.remove();
|
||||
|
||||
// Not having enough placeholder params results in error.
|
||||
fmt.format(
|
||||
params,
|
||||
UPRV_LENGTHOF(params) - 1,
|
||||
appendTo,
|
||||
offsets,
|
||||
UPRV_LENGTHOF(offsets),
|
||||
status);
|
||||
if (status != U_ILLEGAL_ARGUMENT_ERROR) {
|
||||
errln("Expected U_ILLEGAL_ARGUMENT_ERROR");
|
||||
}
|
||||
|
||||
// Ensure we don't write to offsets array beyond its length.
|
||||
status = U_ZERO_ERROR;
|
||||
offsets[UPRV_LENGTHOF(offsets) - 1] = 289;
|
||||
appendTo.remove();
|
||||
fmt.format(
|
||||
fmt.formatAndAppend(
|
||||
params,
|
||||
UPRV_LENGTHOF(params),
|
||||
appendTo,
|
||||
@ -150,7 +157,7 @@ void SimplePatternFormatterTest::TestManyPlaceholders() {
|
||||
assertEquals(
|
||||
"Assignment",
|
||||
"Templates frogtommy{0} and leg are out of order.",
|
||||
s.format(
|
||||
s.formatAndAppend(
|
||||
params,
|
||||
UPRV_LENGTHOF(params),
|
||||
appendTo,
|
||||
@ -164,7 +171,7 @@ void SimplePatternFormatterTest::TestManyPlaceholders() {
|
||||
assertEquals(
|
||||
"Copy constructor",
|
||||
"Templates frogtommy{0} and leg are out of order.",
|
||||
r.format(
|
||||
r.formatAndAppend(
|
||||
params,
|
||||
UPRV_LENGTHOF(params),
|
||||
appendTo,
|
||||
@ -195,42 +202,265 @@ void SimplePatternFormatterTest::TestManyPlaceholders() {
|
||||
assertSuccess("Status", status);
|
||||
}
|
||||
|
||||
void SimplePatternFormatterTest::TestTooFewPlaceholderValues() {
|
||||
SimplePatternFormatter fmt("{0} and {1}");
|
||||
UnicodeString appendTo;
|
||||
UnicodeString firstValue;
|
||||
UnicodeString *params[] = {&firstValue};
|
||||
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
fmt.format(
|
||||
firstValue, appendTo, status);
|
||||
if (status != U_ILLEGAL_ARGUMENT_ERROR) {
|
||||
errln("Expected U_ILLEGAL_ARGUMENT_ERROR");
|
||||
}
|
||||
|
||||
status = U_ZERO_ERROR;
|
||||
fmt.formatAndAppend(
|
||||
params, UPRV_LENGTHOF(params), appendTo, NULL, 0, status);
|
||||
if (status != U_ILLEGAL_ARGUMENT_ERROR) {
|
||||
errln("Expected U_ILLEGAL_ARGUMENT_ERROR");
|
||||
}
|
||||
|
||||
status = U_ZERO_ERROR;
|
||||
fmt.formatAndReplace(
|
||||
params, UPRV_LENGTHOF(params), appendTo, NULL, 0, status);
|
||||
if (status != U_ILLEGAL_ARGUMENT_ERROR) {
|
||||
errln("Expected U_ILLEGAL_ARGUMENT_ERROR");
|
||||
}
|
||||
}
|
||||
|
||||
void SimplePatternFormatterTest::TestBadArguments() {
|
||||
SimplePatternFormatter fmt("pickle");
|
||||
UnicodeString appendTo;
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
int32_t offsets[1];
|
||||
|
||||
// These succeed
|
||||
fmt.formatAndAppend(
|
||||
NULL, 0, appendTo, NULL, 0, status);
|
||||
fmt.formatAndReplace(
|
||||
NULL, 0, appendTo, NULL, 0, status);
|
||||
assertSuccess("", status);
|
||||
status = U_ZERO_ERROR;
|
||||
|
||||
// fails
|
||||
fmt.formatAndAppend(
|
||||
NULL, 1, appendTo, NULL, 0, status);
|
||||
if (status != U_ILLEGAL_ARGUMENT_ERROR) {
|
||||
errln("Expected U_ILLEGAL_ARGUMENT_ERROR");
|
||||
}
|
||||
status = U_ZERO_ERROR;
|
||||
|
||||
// fails
|
||||
fmt.formatAndAppend(
|
||||
NULL, 0, appendTo, NULL, 1, status);
|
||||
if (status != U_ILLEGAL_ARGUMENT_ERROR) {
|
||||
errln("Expected U_ILLEGAL_ARGUMENT_ERROR");
|
||||
}
|
||||
status = U_ZERO_ERROR;
|
||||
|
||||
// fails because appendTo used as a parameter value
|
||||
const UnicodeString *params[] = {&appendTo};
|
||||
fmt.formatAndAppend(
|
||||
params, UPRV_LENGTHOF(params), appendTo, NULL, 0, status);
|
||||
if (status != U_ILLEGAL_ARGUMENT_ERROR) {
|
||||
errln("Expected U_ILLEGAL_ARGUMENT_ERROR");
|
||||
}
|
||||
status = U_ZERO_ERROR;
|
||||
|
||||
|
||||
// fails
|
||||
fmt.formatAndReplace(
|
||||
NULL, 1, appendTo, NULL, 0, status);
|
||||
if (status != U_ILLEGAL_ARGUMENT_ERROR) {
|
||||
errln("Expected U_ILLEGAL_ARGUMENT_ERROR");
|
||||
}
|
||||
status = U_ZERO_ERROR;
|
||||
|
||||
// fails
|
||||
fmt.formatAndReplace(
|
||||
NULL, 0, appendTo, NULL, 1, status);
|
||||
if (status != U_ILLEGAL_ARGUMENT_ERROR) {
|
||||
errln("Expected U_ILLEGAL_ARGUMENT_ERROR");
|
||||
}
|
||||
}
|
||||
|
||||
void SimplePatternFormatterTest::TestGetPatternWithNoPlaceholders() {
|
||||
SimplePatternFormatter fmt("{0} has no {1} placeholders.");
|
||||
assertEquals(
|
||||
"", " has no placeholders.", fmt.getPatternWithNoPlaceholders());
|
||||
}
|
||||
|
||||
void SimplePatternFormatterTest::TestOptimization() {
|
||||
void SimplePatternFormatterTest::TestFormatReplaceNoOptimization() {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
SimplePatternFormatter fmt;
|
||||
fmt.compile("{2}, {0}, {1} and {3}", status);
|
||||
assertSuccess("Status", status);
|
||||
assertTrue("startsWithPlaceholder", fmt.startsWithPlaceholder(2));
|
||||
assertFalse("startsWithPlaceholder", fmt.startsWithPlaceholder(0));
|
||||
UnicodeString values[] = {
|
||||
"freddy", "frog", "leg", "by"};
|
||||
UnicodeString *params[] = {
|
||||
&values[0], &values[1], &values[2], &values[3]};
|
||||
int32_t offsets[4];
|
||||
int32_t expectedOffsets[4] = {5, 13, 0, 22};
|
||||
|
||||
// The pattern starts with {2}, so format should append the result of
|
||||
// the rest of the pattern to values[2], the value for {2}.
|
||||
if (!assertSuccess("Status", status)) {
|
||||
return;
|
||||
}
|
||||
UnicodeString result("original");
|
||||
int offsets[4];
|
||||
UnicodeString freddy("freddy");
|
||||
UnicodeString frog("frog");
|
||||
UnicodeString by("by");
|
||||
const UnicodeString *params[] = {&result, &freddy, &frog, &by};
|
||||
assertEquals(
|
||||
"format",
|
||||
"leg, freddy, frog and by",
|
||||
fmt.format(
|
||||
"",
|
||||
"frog, original, freddy and by",
|
||||
fmt.formatAndReplace(
|
||||
params,
|
||||
UPRV_LENGTHOF(params),
|
||||
values[2],
|
||||
result,
|
||||
offsets,
|
||||
UPRV_LENGTHOF(offsets),
|
||||
status));
|
||||
if (!assertSuccess("Status", status)) {
|
||||
return;
|
||||
}
|
||||
int32_t expectedOffsets[] = {6, 16, 0, 27};
|
||||
verifyOffsets(expectedOffsets, offsets, UPRV_LENGTHOF(expectedOffsets));
|
||||
}
|
||||
|
||||
void SimplePatternFormatterTest::TestFormatReplaceNoOptimizationLeadingText() {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
SimplePatternFormatter fmt;
|
||||
fmt.compile("boo {2}, {0}, {1} and {3}", status);
|
||||
if (!assertSuccess("Status", status)) {
|
||||
return;
|
||||
}
|
||||
UnicodeString result("original");
|
||||
int offsets[4];
|
||||
UnicodeString freddy("freddy");
|
||||
UnicodeString frog("frog");
|
||||
UnicodeString by("by");
|
||||
const UnicodeString *params[] = {&freddy, &frog, &result, &by};
|
||||
assertEquals(
|
||||
"",
|
||||
"boo original, freddy, frog and by",
|
||||
fmt.formatAndReplace(
|
||||
params,
|
||||
UPRV_LENGTHOF(params),
|
||||
result,
|
||||
offsets,
|
||||
UPRV_LENGTHOF(offsets),
|
||||
status));
|
||||
if (!assertSuccess("Status", status)) {
|
||||
return;
|
||||
}
|
||||
int32_t expectedOffsets[] = {14, 22, 4, 31};
|
||||
verifyOffsets(expectedOffsets, offsets, UPRV_LENGTHOF(expectedOffsets));
|
||||
}
|
||||
|
||||
void SimplePatternFormatterTest::TestFormatReplaceOptimization() {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
SimplePatternFormatter fmt;
|
||||
fmt.compile("{2}, {0}, {1} and {3}", status);
|
||||
if (!assertSuccess("Status", status)) {
|
||||
return;
|
||||
}
|
||||
UnicodeString result("original");
|
||||
int offsets[4];
|
||||
UnicodeString freddy("freddy");
|
||||
UnicodeString frog("frog");
|
||||
UnicodeString by("by");
|
||||
const UnicodeString *params[] = {&freddy, &frog, &result, &by};
|
||||
assertEquals(
|
||||
"",
|
||||
"original, freddy, frog and by",
|
||||
fmt.formatAndReplace(
|
||||
params,
|
||||
UPRV_LENGTHOF(params),
|
||||
result,
|
||||
offsets,
|
||||
UPRV_LENGTHOF(offsets),
|
||||
status));
|
||||
if (!assertSuccess("Status", status)) {
|
||||
return;
|
||||
}
|
||||
int32_t expectedOffsets[] = {10, 18, 0, 27};
|
||||
verifyOffsets(expectedOffsets, offsets, UPRV_LENGTHOF(expectedOffsets));
|
||||
}
|
||||
|
||||
void SimplePatternFormatterTest::TestFormatReplaceNoOptimizationLeadingPlaceholderUsedTwice() {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
SimplePatternFormatter fmt;
|
||||
fmt.compile("{2}, {0}, {1} and {3} {2}", status);
|
||||
if (!assertSuccess("Status", status)) {
|
||||
return;
|
||||
}
|
||||
UnicodeString result("original");
|
||||
int offsets[4];
|
||||
UnicodeString freddy("freddy");
|
||||
UnicodeString frog("frog");
|
||||
UnicodeString by("by");
|
||||
const UnicodeString *params[] = {&freddy, &frog, &result, &by};
|
||||
assertEquals(
|
||||
"",
|
||||
"original, freddy, frog and by original",
|
||||
fmt.formatAndReplace(
|
||||
params,
|
||||
UPRV_LENGTHOF(params),
|
||||
result,
|
||||
offsets,
|
||||
UPRV_LENGTHOF(offsets),
|
||||
status));
|
||||
if (!assertSuccess("Status", status)) {
|
||||
return;
|
||||
}
|
||||
int32_t expectedOffsets[] = {10, 18, 30, 27};
|
||||
verifyOffsets(expectedOffsets, offsets, UPRV_LENGTHOF(expectedOffsets));
|
||||
}
|
||||
|
||||
void SimplePatternFormatterTest::TestFormatReplaceOptimizationNoOffsets() {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
SimplePatternFormatter fmt;
|
||||
fmt.compile("{2}, {0}, {1} and {3}", status);
|
||||
if (!assertSuccess("Status", status)) {
|
||||
return;
|
||||
}
|
||||
UnicodeString result("original");
|
||||
UnicodeString freddy("freddy");
|
||||
UnicodeString frog("frog");
|
||||
UnicodeString by("by");
|
||||
const UnicodeString *params[] = {&freddy, &frog, &result, &by};
|
||||
assertEquals(
|
||||
"",
|
||||
"original, freddy, frog and by",
|
||||
fmt.formatAndReplace(
|
||||
params,
|
||||
UPRV_LENGTHOF(params),
|
||||
result,
|
||||
NULL,
|
||||
0,
|
||||
status));
|
||||
assertSuccess("Status", status);
|
||||
for (int32_t i = 0; i < UPRV_LENGTHOF(expectedOffsets); ++i) {
|
||||
if (expectedOffsets[i] != offsets[i]) {
|
||||
errln("Expected %d, got %d", expectedOffsets[i], offsets[i]);
|
||||
}
|
||||
|
||||
void SimplePatternFormatterTest::TestFormatReplaceNoOptimizationNoOffsets() {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
SimplePatternFormatter fmt("Placeholders {0} and {1}");
|
||||
UnicodeString result("previous:");
|
||||
UnicodeString frog("frog");
|
||||
const UnicodeString *params[] = {&result, &frog};
|
||||
assertEquals(
|
||||
"",
|
||||
"Placeholders previous: and frog",
|
||||
fmt.formatAndReplace(
|
||||
params,
|
||||
UPRV_LENGTHOF(params),
|
||||
result,
|
||||
NULL,
|
||||
0,
|
||||
status));
|
||||
assertSuccess("Status", status);
|
||||
}
|
||||
|
||||
void SimplePatternFormatterTest::verifyOffsets(
|
||||
const int32_t *expected, const int32_t *actual, int32_t count) {
|
||||
for (int32_t i = 0; i < count; ++i) {
|
||||
if (expected[i] != actual[i]) {
|
||||
errln("Expected %d, got %d", expected[i], actual[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -238,3 +468,4 @@ void SimplePatternFormatterTest::TestOptimization() {
|
||||
extern IntlTest *createSimplePatternFormatterTest() {
|
||||
return new SimplePatternFormatterTest();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user