Merge pull request #12 from unicode-org/master

Update units-staging with upstream master
This commit is contained in:
Shane F. Carr 2020-01-17 17:28:31 +01:00 committed by GitHub
commit 3baf406d88
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 358 additions and 221 deletions

View file

@ -57,7 +57,11 @@ jobs:
vmImage: 'Ubuntu 16.04'
steps:
- script: |
cd icu4c/source && ICU_DATA_FILTER_FILE=../../.ci-builds/data-filter.json ./runConfigureICU Linux && make -j2
cd icu4c/source && \
ICU_DATA_FILTER_FILE=../../.ci-builds/data-filter.json ./runConfigureICU Linux && \
make -j2 tests && \
\[ ! -d data/out/build/icudt66l/translit \] && \
(cd test/intltest && LD_LIBRARY_PATH=../../lib:../../tools/ctestfw ./intltest translit/TransliteratorTest/TestBasicTransliteratorEvenWithoutData)
displayName: 'Build with Data Filter'
env:
CC: clang

View file

@ -8,16 +8,18 @@
]
},
// Test mixed feature filter and resource filter
// Exlude translit data so we can run test for ICU-20673
"featureFilters": {
"misc": {
"whitelist": ["supplementalData"]
}
},
"translit": "exclude"
},
"resourceFilters": [
{
"categories": ["misc"],
"files": {
"whitelist": ["supplementalData"]
"whitelist": ["supplementalData"]
},
"rules": ["+/*"]
}
@ -27,8 +29,8 @@
"directory": "$SRC",
"replacements": [
{
"src": "translit/Zawgyi_my.txt",
"dest": "translit/Zawgyi_my.txt"
"src": "brkitr/rules/line.txt",
"dest": "brkitr/rules/line_normal.txt"
},
"misc/dayPeriods.txt"
]

View file

@ -31,6 +31,8 @@
#if U_DEBUG
# include <assert.h>
# define U_ASSERT(exp) assert(exp)
#elif U_CPLUSPLUS_VERSION
# define U_ASSERT(exp) void()
#else
# define U_ASSERT(exp)
#endif

View file

@ -8,6 +8,7 @@
#include "formatted_string_builder.h"
#include "unicode/ustring.h"
#include "unicode/utf16.h"
#include "unicode/unum.h" // for UNumberFormatFields literals
namespace {
@ -246,7 +247,7 @@ void FormattedStringBuilder::writeTerminator(UErrorCode& status) {
return;
}
getCharPtr()[position] = 0;
getFieldPtr()[position] = UNUM_FIELD_COUNT;
getFieldPtr()[position] = kUndefinedField;
fLength--;
}
@ -360,11 +361,11 @@ UnicodeString FormattedStringBuilder::toDebugString() const {
sb.append(toUnicodeString());
sb.append(u"] [", -1);
for (int i = 0; i < fLength; i++) {
if (fieldAt(i) == UNUM_FIELD_COUNT) {
if (fieldAt(i) == kUndefinedField) {
sb.append(u'n');
} else {
} else if (fieldAt(i).getCategory() == UFIELD_CATEGORY_NUMBER) {
char16_t c;
switch (fieldAt(i)) {
switch (fieldAt(i).getField()) {
case UNUM_SIGN_FIELD:
c = u'-';
break;
@ -399,10 +400,12 @@ UnicodeString FormattedStringBuilder::toDebugString() const {
c = u'$';
break;
default:
c = u'?';
c = u'0' + fieldAt(i).getField();
break;
}
sb.append(c);
} else {
sb.append(u'0' + fieldAt(i).getCategory());
}
}
sb.append(u"]>", -1);

View file

@ -9,7 +9,8 @@
#include <cstdint>
#include "unicode/unum.h" // for UNUM_FIELD_COUNT
#include <type_traits>
#include "cstring.h"
#include "uassert.h"
#include "fphdlimp.h"
@ -55,7 +56,20 @@ class U_I18N_API FormattedStringBuilder : public UMemory {
// Field category 0 implies the number category so that the number field
// literals can be directly passed as a Field type.
// See the helper functions in "StringBuilderFieldUtils" below.
typedef uint8_t Field;
// Exported as U_I18N_API so it can be used by other exports on Windows.
struct U_I18N_API Field {
uint8_t bits;
Field() = default;
constexpr Field(uint8_t category, uint8_t field);
inline UFieldCategory getCategory() const;
inline int32_t getField() const;
inline bool isNumeric() const;
inline bool isUndefined() const;
inline bool operator==(const Field& other) const;
inline bool operator!=(const Field& other) const;
};
FormattedStringBuilder &operator=(const FormattedStringBuilder &other);
@ -204,46 +218,50 @@ class U_I18N_API FormattedStringBuilder : public UMemory {
friend class FormattedValueStringBuilderImpl;
};
static_assert(
std::is_pod<FormattedStringBuilder::Field>::value,
"Field should be a POD type for efficient initialization");
constexpr FormattedStringBuilder::Field::Field(uint8_t category, uint8_t field)
: bits((
U_ASSERT(category <= 0xf),
U_ASSERT(field <= 0xf),
static_cast<uint8_t>((category << 4) | field)
)) {}
/**
* Helper functions for dealing with the Field typedef, which stores fields
* in a compressed format.
* Internal constant for the undefined field for use in FormattedStringBuilder.
*/
class StringBuilderFieldUtils {
public:
struct CategoryFieldPair {
int32_t category;
int32_t field;
};
constexpr FormattedStringBuilder::Field kUndefinedField = {UFIELD_CATEGORY_UNDEFINED, 0};
/** Compile-time function to construct a Field from a category and a field */
template <int32_t category, int32_t field>
static constexpr FormattedStringBuilder::Field compress() {
static_assert(category != 0, "cannot use Undefined category in FieldUtils");
static_assert(category <= 0xf, "only 4 bits for category");
static_assert(field <= 0xf, "only 4 bits for field");
return static_cast<int8_t>((category << 4) | field);
}
/**
* Internal field to signal "numeric" when fields are not supported in NumberFormat.
*/
constexpr FormattedStringBuilder::Field kGeneralNumericField = {UFIELD_CATEGORY_UNDEFINED, 1};
/** Runtime inline function to unpack the category and field from the Field */
static inline CategoryFieldPair expand(FormattedStringBuilder::Field field) {
if (field == UNUM_FIELD_COUNT) {
return {UFIELD_CATEGORY_UNDEFINED, 0};
}
CategoryFieldPair ret = {
(field >> 4),
(field & 0xf)
};
if (ret.category == 0) {
ret.category = UFIELD_CATEGORY_NUMBER;
}
return ret;
}
inline UFieldCategory FormattedStringBuilder::Field::getCategory() const {
return static_cast<UFieldCategory>(bits >> 4);
}
static inline bool isNumericField(FormattedStringBuilder::Field field) {
int8_t category = field >> 4;
return category == 0 || category == UFIELD_CATEGORY_NUMBER;
}
};
inline int32_t FormattedStringBuilder::Field::getField() const {
return bits & 0xf;
}
inline bool FormattedStringBuilder::Field::isNumeric() const {
return getCategory() == UFIELD_CATEGORY_NUMBER || *this == kGeneralNumericField;
}
inline bool FormattedStringBuilder::Field::isUndefined() const {
return getCategory() == UFIELD_CATEGORY_UNDEFINED;
}
inline bool FormattedStringBuilder::Field::operator==(const Field& other) const {
return bits == other.bits;
}
inline bool FormattedStringBuilder::Field::operator!=(const Field& other) const {
return bits != other.bits;
}
U_NAMESPACE_END

View file

@ -153,7 +153,6 @@ private:
bool nextPositionImpl(ConstrainedFieldPosition& cfpos, FormattedStringBuilder::Field numericField, UErrorCode& status) const;
static bool isIntOrGroup(FormattedStringBuilder::Field field);
static bool isNumericField(FormattedStringBuilder::Field field);
int32_t trimBack(int32_t limit) const;
int32_t trimFront(int32_t start) const;
};

View file

@ -63,7 +63,7 @@ UBool FormattedValueStringBuilderImpl::nextFieldPosition(FieldPosition& fp, UErr
ConstrainedFieldPosition cfpos;
cfpos.constrainField(UFIELD_CATEGORY_NUMBER, rawField);
cfpos.setState(UFIELD_CATEGORY_NUMBER, rawField, fp.getBeginIndex(), fp.getEndIndex());
if (nextPositionImpl(cfpos, 0, status)) {
if (nextPositionImpl(cfpos, kUndefinedField, status)) {
fp.setBeginIndex(cfpos.getStart());
fp.setEndIndex(cfpos.getLimit());
return TRUE;
@ -74,7 +74,7 @@ UBool FormattedValueStringBuilderImpl::nextFieldPosition(FieldPosition& fp, UErr
bool inside = false;
int32_t i = fString.fZero;
for (; i < fString.fZero + fString.fLength; i++) {
if (isIntOrGroup(fString.getFieldPtr()[i]) || fString.getFieldPtr()[i] == UNUM_DECIMAL_SEPARATOR_FIELD) {
if (isIntOrGroup(fString.getFieldPtr()[i]) || fString.getFieldPtr()[i] == Field(UFIELD_CATEGORY_NUMBER, UNUM_DECIMAL_SEPARATOR_FIELD)) {
inside = true;
} else if (inside) {
break;
@ -90,42 +90,40 @@ UBool FormattedValueStringBuilderImpl::nextFieldPosition(FieldPosition& fp, UErr
void FormattedValueStringBuilderImpl::getAllFieldPositions(FieldPositionIteratorHandler& fpih,
UErrorCode& status) const {
ConstrainedFieldPosition cfpos;
while (nextPositionImpl(cfpos, 0, status)) {
while (nextPositionImpl(cfpos, kUndefinedField, status)) {
fpih.addAttribute(cfpos.getField(), cfpos.getStart(), cfpos.getLimit());
}
}
// Signal the end of the string using a field that doesn't exist and that is
// different from UNUM_FIELD_COUNT, which is used for "null number field".
static constexpr Field kEndField = 0xff;
// different from kUndefinedField, which is used for "null field".
static constexpr Field kEndField = Field(0xf, 0xf);
bool FormattedValueStringBuilderImpl::nextPositionImpl(ConstrainedFieldPosition& cfpos, Field numericField, UErrorCode& /*status*/) const {
auto numericCAF = StringBuilderFieldUtils::expand(numericField);
int32_t fieldStart = -1;
Field currField = UNUM_FIELD_COUNT;
Field currField = kUndefinedField;
for (int32_t i = fString.fZero + cfpos.getLimit(); i <= fString.fZero + fString.fLength; i++) {
Field _field = (i < fString.fZero + fString.fLength) ? fString.getFieldPtr()[i] : kEndField;
// Case 1: currently scanning a field.
if (currField != UNUM_FIELD_COUNT) {
if (currField != kUndefinedField) {
if (currField != _field) {
int32_t end = i - fString.fZero;
// Grouping separators can be whitespace; don't throw them out!
if (currField != UNUM_GROUPING_SEPARATOR_FIELD) {
if (currField != Field(UFIELD_CATEGORY_NUMBER, UNUM_GROUPING_SEPARATOR_FIELD)) {
end = trimBack(i - fString.fZero);
}
if (end <= fieldStart) {
// Entire field position is ignorable; skip.
fieldStart = -1;
currField = UNUM_FIELD_COUNT;
currField = kUndefinedField;
i--; // look at this index again
continue;
}
int32_t start = fieldStart;
if (currField != UNUM_GROUPING_SEPARATOR_FIELD) {
if (currField != Field(UFIELD_CATEGORY_NUMBER, UNUM_GROUPING_SEPARATOR_FIELD)) {
start = trimFront(start);
}
auto caf = StringBuilderFieldUtils::expand(currField);
cfpos.setState(caf.category, caf.field, start, end);
cfpos.setState(currField.getCategory(), currField.getField(), start, end);
return true;
}
continue;
@ -147,51 +145,46 @@ bool FormattedValueStringBuilderImpl::nextPositionImpl(ConstrainedFieldPosition&
return true;
}
// Special case: coalesce NUMERIC if we are pointing at the end of the NUMERIC.
if (numericField != 0
&& cfpos.matchesField(numericCAF.category, numericCAF.field)
if (numericField != kUndefinedField
&& cfpos.matchesField(numericField.getCategory(), numericField.getField())
&& i > fString.fZero
// don't return the same field twice in a row:
&& (i - fString.fZero > cfpos.getLimit()
|| cfpos.getCategory() != numericCAF.category
|| cfpos.getField() != numericCAF.field)
&& isNumericField(fString.getFieldPtr()[i - 1])
&& !isNumericField(_field)) {
|| cfpos.getCategory() != numericField.getCategory()
|| cfpos.getField() != numericField.getField())
&& fString.getFieldPtr()[i - 1].isNumeric()
&& !_field.isNumeric()) {
int j = i - 1;
for (; j >= fString.fZero && isNumericField(fString.getFieldPtr()[j]); j--) {}
for (; j >= fString.fZero && fString.getFieldPtr()[j].isNumeric(); j--) {}
cfpos.setState(
numericCAF.category,
numericCAF.field,
numericField.getCategory(),
numericField.getField(),
j - fString.fZero + 1,
i - fString.fZero);
return true;
}
// Special case: skip over INTEGER; will be coalesced later.
if (_field == UNUM_INTEGER_FIELD) {
_field = UNUM_FIELD_COUNT;
if (_field == Field(UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD)) {
_field = kUndefinedField;
}
// Case 2: no field starting at this position.
if (_field == UNUM_FIELD_COUNT || _field == kEndField) {
if (_field.isUndefined() || _field == kEndField) {
continue;
}
// Case 3: check for field starting at this position
auto caf = StringBuilderFieldUtils::expand(_field);
if (cfpos.matchesField(caf.category, caf.field)) {
if (cfpos.matchesField(_field.getCategory(), _field.getField())) {
fieldStart = i - fString.fZero;
currField = _field;
}
}
U_ASSERT(currField == UNUM_FIELD_COUNT);
U_ASSERT(currField == kUndefinedField);
return false;
}
bool FormattedValueStringBuilderImpl::isIntOrGroup(Field field) {
return field == UNUM_INTEGER_FIELD
|| field == UNUM_GROUPING_SEPARATOR_FIELD;
}
bool FormattedValueStringBuilderImpl::isNumericField(Field field) {
return StringBuilderFieldUtils::isNumericField(field);
return field == Field(UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD)
|| field == Field(UFIELD_CATEGORY_NUMBER, UNUM_GROUPING_SEPARATOR_FIELD);
}
int32_t FormattedValueStringBuilderImpl::trimBack(int32_t limit) const {

View file

@ -774,11 +774,6 @@ UnicodeString &MeasureFormat::formatNumeric(
case u's': value = seconds; break;
}
// For undefined field we use UNUM_FIELD_COUNT, for historical reasons.
// See cleanup bug: https://unicode-org.atlassian.net/browse/ICU-20665
// But we give it a clear name, to keep "the ugly part" in one place.
constexpr UNumberFormatFields undefinedField = UNUM_FIELD_COUNT;
// There is not enough info to add Field(s) for the unit because all we have are plain
// text patterns. For example in "21:51" there is no text for something like "hour",
// while in something like "21h51" there is ("h"). But we can't really tell...
@ -787,7 +782,7 @@ UnicodeString &MeasureFormat::formatNumeric(
case u'm':
case u's':
if (protect) {
fsb.appendChar16(c, undefinedField, status);
fsb.appendChar16(c, kUndefinedField, status);
} else {
UnicodeString tmp;
if ((i + 1 < patternLength) && pattern[i + 1] == c) { // doubled
@ -797,20 +792,20 @@ UnicodeString &MeasureFormat::formatNumeric(
numberFormatter->format(value, tmp, status);
}
// TODO: Use proper Field
fsb.append(tmp, undefinedField, status);
fsb.append(tmp, kUndefinedField, status);
}
break;
case u'\'':
// '' is escaped apostrophe
if ((i + 1 < patternLength) && pattern[i + 1] == c) {
fsb.appendChar16(c, undefinedField, status);
fsb.appendChar16(c, kUndefinedField, status);
i++;
} else {
protect = !protect;
}
break;
default:
fsb.appendChar16(c, undefinedField, status);
fsb.appendChar16(c, kUndefinedField, status);
}
}

View file

@ -131,25 +131,25 @@ UnicodeString AffixUtils::escape(const UnicodeString &input) {
Field AffixUtils::getFieldForType(AffixPatternType type) {
switch (type) {
case TYPE_MINUS_SIGN:
return UNUM_SIGN_FIELD;
return {UFIELD_CATEGORY_NUMBER, UNUM_SIGN_FIELD};
case TYPE_PLUS_SIGN:
return UNUM_SIGN_FIELD;
return {UFIELD_CATEGORY_NUMBER, UNUM_SIGN_FIELD};
case TYPE_PERCENT:
return UNUM_PERCENT_FIELD;
return {UFIELD_CATEGORY_NUMBER, UNUM_PERCENT_FIELD};
case TYPE_PERMILLE:
return UNUM_PERMILL_FIELD;
return {UFIELD_CATEGORY_NUMBER, UNUM_PERMILL_FIELD};
case TYPE_CURRENCY_SINGLE:
return UNUM_CURRENCY_FIELD;
return {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD};
case TYPE_CURRENCY_DOUBLE:
return UNUM_CURRENCY_FIELD;
return {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD};
case TYPE_CURRENCY_TRIPLE:
return UNUM_CURRENCY_FIELD;
return {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD};
case TYPE_CURRENCY_QUAD:
return UNUM_CURRENCY_FIELD;
return {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD};
case TYPE_CURRENCY_QUINT:
return UNUM_CURRENCY_FIELD;
return {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD};
case TYPE_CURRENCY_OVERFLOW:
return UNUM_CURRENCY_FIELD;
return {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD};
default:
UPRV_UNREACHABLE;
}
@ -165,7 +165,11 @@ AffixUtils::unescape(const UnicodeString &affixPattern, FormattedStringBuilder &
if (U_FAILURE(status)) { return length; }
if (tag.type == TYPE_CURRENCY_OVERFLOW) {
// Don't go to the provider for this special case
length += output.insertCodePoint(position + length, 0xFFFD, UNUM_CURRENCY_FIELD, status);
length += output.insertCodePoint(
position + length,
0xFFFD,
{UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD},
status);
} else if (tag.type < 0) {
length += output.insert(
position + length, provider.getSymbol(tag.type), getFieldForType(tag.type), status);
@ -218,7 +222,7 @@ bool AffixUtils::hasCurrencySymbols(const UnicodeString &affixPattern, UErrorCod
while (hasNext(tag, affixPattern)) {
tag = nextToken(tag, affixPattern, status);
if (U_FAILURE(status)) { return false; }
if (tag.type < 0 && getFieldForType(tag.type) == UNUM_CURRENCY_FIELD) {
if (tag.type < 0 && getFieldForType(tag.type) == Field(UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD)) {
return true;
}
}

View file

@ -266,7 +266,7 @@ void CompactHandler::precomputeAllModifiers(MutablePatternModifier &buildReferen
ParsedPatternInfo patternInfo;
PatternParser::parseToPatternInfo(UnicodeString(patternString), patternInfo, status);
if (U_FAILURE(status)) { return; }
buildReference.setPatternInfo(&patternInfo, UNUM_COMPACT_FIELD);
buildReference.setPatternInfo(&patternInfo, {UFIELD_CATEGORY_NUMBER, UNUM_COMPACT_FIELD});
info.mod = buildReference.createImmutable(status);
if (U_FAILURE(status)) { return; }
info.patternString = patternString;
@ -315,7 +315,9 @@ void CompactHandler::processQuantity(DecimalQuantity &quantity, MicroProps &micr
// C++ Note: Use unsafePatternInfo for proper lifecycle.
ParsedPatternInfo &patternInfo = const_cast<CompactHandler *>(this)->unsafePatternInfo;
PatternParser::parseToPatternInfo(UnicodeString(patternString), patternInfo, status);
unsafePatternModifier->setPatternInfo(&unsafePatternInfo, UNUM_COMPACT_FIELD);
unsafePatternModifier->setPatternInfo(
&unsafePatternInfo,
{UFIELD_CATEGORY_NUMBER, UNUM_COMPACT_FIELD});
unsafePatternModifier->setNumberProperties(quantity.signum(), StandardPlural::Form::COUNT);
micros.modMiddle = unsafePatternModifier;
}

View file

@ -370,7 +370,7 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps& macros, bool safe,
patternModifier->setPatternInfo(
macros.affixProvider != nullptr ? macros.affixProvider
: static_cast<const AffixPatternProvider*>(fPatternInfo.getAlias()),
UNUM_FIELD_COUNT);
kUndefinedField);
patternModifier->setPatternAttributes(fMicros.sign, isPermille);
if (patternModifier->needsPlurals()) {
patternModifier->setSymbols(
@ -480,14 +480,14 @@ int32_t NumberFormatterImpl::writeNumber(const MicroProps& micros, DecimalQuanti
length += string.insert(
length + index,
micros.symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kInfinitySymbol),
UNUM_INTEGER_FIELD,
{UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD},
status);
} else if (quantity.isNaN()) {
length += string.insert(
length + index,
micros.symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kNaNSymbol),
UNUM_INTEGER_FIELD,
{UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD},
status);
} else {
@ -503,7 +503,7 @@ int32_t NumberFormatterImpl::writeNumber(const MicroProps& micros, DecimalQuanti
.symbols
->getSymbol(
DecimalFormatSymbols::ENumberFormatSymbol::kDecimalSeparatorSymbol),
UNUM_DECIMAL_SEPARATOR_FIELD,
{UFIELD_CATEGORY_NUMBER, UNUM_DECIMAL_SEPARATOR_FIELD},
status);
}
@ -513,7 +513,12 @@ int32_t NumberFormatterImpl::writeNumber(const MicroProps& micros, DecimalQuanti
if (length == 0) {
// Force output of the digit for value 0
length += utils::insertDigitFromSymbols(
string, index, 0, *micros.symbols, UNUM_INTEGER_FIELD, status);
string,
index,
0,
*micros.symbols,
{UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD},
status);
}
}
@ -534,14 +539,20 @@ int32_t NumberFormatterImpl::writeIntegerDigits(const MicroProps& micros, Decima
DecimalFormatSymbols::ENumberFormatSymbol::kMonetaryGroupingSeparatorSymbol)
: micros.symbols->getSymbol(
DecimalFormatSymbols::ENumberFormatSymbol::kGroupingSeparatorSymbol),
UNUM_GROUPING_SEPARATOR_FIELD,
{UFIELD_CATEGORY_NUMBER, UNUM_GROUPING_SEPARATOR_FIELD},
status);
}
// Get and append the next digit value
int8_t nextDigit = quantity.getDigit(i);
length += utils::insertDigitFromSymbols(
string, index, nextDigit, *micros.symbols, UNUM_INTEGER_FIELD, status);
string,
index,
nextDigit,
*micros.symbols,
{UFIELD_CATEGORY_NUMBER,
UNUM_INTEGER_FIELD},
status);
}
return length;
}
@ -555,7 +566,12 @@ int32_t NumberFormatterImpl::writeFractionDigits(const MicroProps& micros, Decim
// Get and append the next digit value
int8_t nextDigit = quantity.getDigit(-i - 1);
length += utils::insertDigitFromSymbols(
string, length + index, nextDigit, *micros.symbols, UNUM_FRACTION_FIELD, status);
string,
length + index,
nextDigit,
*micros.symbols,
{UFIELD_CATEGORY_NUMBER, UNUM_FRACTION_FIELD},
status);
}
return length;
}

View file

@ -209,7 +209,7 @@ LongNameHandler::forMeasureUnit(const Locale &loc, const MeasureUnit &unitRef, c
UnicodeString simpleFormats[ARRAY_LENGTH];
getMeasureData(loc, unit, width, simpleFormats, status);
if (U_FAILURE(status)) { return result; }
result->simpleFormatsToModifiers(simpleFormats, UNUM_MEASURE_UNIT_FIELD, status);
result->simpleFormatsToModifiers(simpleFormats, {UFIELD_CATEGORY_NUMBER, UNUM_MEASURE_UNIT_FIELD}, status);
return result;
}
@ -247,7 +247,7 @@ LongNameHandler::forCompoundUnit(const Locale &loc, const MeasureUnit &unit, con
compiled.format(UnicodeString(u"{0}"), secondaryString, perUnitFormat, status);
if (U_FAILURE(status)) { return result; }
}
result->multiSimpleFormatsToModifiers(primaryData, perUnitFormat, UNUM_MEASURE_UNIT_FIELD, status);
result->multiSimpleFormatsToModifiers(primaryData, perUnitFormat, {UFIELD_CATEGORY_NUMBER, UNUM_MEASURE_UNIT_FIELD}, status);
return result;
}
@ -296,7 +296,7 @@ LongNameHandler* LongNameHandler::forCurrencyLongNames(const Locale &loc, const
UnicodeString simpleFormats[ARRAY_LENGTH];
getCurrencyLongNameData(loc, currency, simpleFormats, status);
if (U_FAILURE(status)) { return nullptr; }
result->simpleFormatsToModifiers(simpleFormats, UNUM_CURRENCY_FIELD, status);
result->simpleFormatsToModifiers(simpleFormats, {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD}, status);
return result;
}

View file

@ -89,7 +89,7 @@ bool ConstantAffixModifier::isStrong() const {
return fStrong;
}
bool ConstantAffixModifier::containsField(UNumberFormatFields field) const {
bool ConstantAffixModifier::containsField(Field field) const {
(void)field;
// This method is not currently used.
UPRV_UNREACHABLE;
@ -151,7 +151,7 @@ SimpleModifier::SimpleModifier(const SimpleFormatter &simpleFormatter, Field fie
}
SimpleModifier::SimpleModifier()
: fField(UNUM_FIELD_COUNT), fStrong(false), fPrefixLength(0), fSuffixLength(0) {
: fField(kUndefinedField), fStrong(false), fPrefixLength(0), fSuffixLength(0) {
}
int32_t SimpleModifier::apply(FormattedStringBuilder &output, int leftIndex, int rightIndex,
@ -178,7 +178,7 @@ bool SimpleModifier::isStrong() const {
return fStrong;
}
bool SimpleModifier::containsField(UNumberFormatFields field) const {
bool SimpleModifier::containsField(Field field) const {
(void)field;
// This method is not currently used.
UPRV_UNREACHABLE;
@ -292,7 +292,7 @@ int32_t ConstantMultiFieldModifier::apply(FormattedStringBuilder &output, int le
leftIndex + length,
rightIndex + length,
UnicodeString(), 0, 0,
UNUM_FIELD_COUNT, status);
kUndefinedField, status);
}
length += output.insert(rightIndex + length, fSuffix, status);
return length;
@ -310,7 +310,7 @@ bool ConstantMultiFieldModifier::isStrong() const {
return fStrong;
}
bool ConstantMultiFieldModifier::containsField(UNumberFormatFields field) const {
bool ConstantMultiFieldModifier::containsField(Field field) const {
return fPrefix.containsField(field) || fSuffix.containsField(field);
}
@ -342,7 +342,7 @@ CurrencySpacingEnabledModifier::CurrencySpacingEnabledModifier(const FormattedSt
: ConstantMultiFieldModifier(prefix, suffix, overwrite, strong) {
// Check for currency spacing. Do not build the UnicodeSets unless there is
// a currency code point at a boundary.
if (prefix.length() > 0 && prefix.fieldAt(prefix.length() - 1) == UNUM_CURRENCY_FIELD) {
if (prefix.length() > 0 && prefix.fieldAt(prefix.length() - 1) == Field(UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD)) {
int prefixCp = prefix.getLastCodePoint();
UnicodeSet prefixUnicodeSet = getUnicodeSet(symbols, IN_CURRENCY, PREFIX, status);
if (prefixUnicodeSet.contains(prefixCp)) {
@ -357,7 +357,7 @@ CurrencySpacingEnabledModifier::CurrencySpacingEnabledModifier(const FormattedSt
fAfterPrefixUnicodeSet.setToBogus();
fAfterPrefixInsert.setToBogus();
}
if (suffix.length() > 0 && suffix.fieldAt(0) == UNUM_CURRENCY_FIELD) {
if (suffix.length() > 0 && suffix.fieldAt(0) == Field(UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD)) {
int suffixCp = suffix.getLastCodePoint();
UnicodeSet suffixUnicodeSet = getUnicodeSet(symbols, IN_CURRENCY, SUFFIX, status);
if (suffixUnicodeSet.contains(suffixCp)) {
@ -381,12 +381,20 @@ int32_t CurrencySpacingEnabledModifier::apply(FormattedStringBuilder &output, in
if (rightIndex - leftIndex > 0 && !fAfterPrefixUnicodeSet.isBogus() &&
fAfterPrefixUnicodeSet.contains(output.codePointAt(leftIndex))) {
// TODO: Should we use the CURRENCY field here?
length += output.insert(leftIndex, fAfterPrefixInsert, UNUM_FIELD_COUNT, status);
length += output.insert(
leftIndex,
fAfterPrefixInsert,
kUndefinedField,
status);
}
if (rightIndex - leftIndex > 0 && !fBeforeSuffixUnicodeSet.isBogus() &&
fBeforeSuffixUnicodeSet.contains(output.codePointBefore(rightIndex))) {
// TODO: Should we use the CURRENCY field here?
length += output.insert(rightIndex + length, fBeforeSuffixInsert, UNUM_FIELD_COUNT, status);
length += output.insert(
rightIndex + length,
fBeforeSuffixInsert,
kUndefinedField,
status);
}
// Call super for the remaining logic
@ -422,7 +430,7 @@ CurrencySpacingEnabledModifier::applyCurrencySpacingAffix(FormattedStringBuilder
// This works even if the last code point in the prefix is 2 code units because the
// field value gets populated to both indices in the field array.
Field affixField = (affix == PREFIX) ? output.fieldAt(index - 1) : output.fieldAt(index);
if (affixField != UNUM_CURRENCY_FIELD) {
if (affixField != Field(UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD)) {
return 0;
}
int affixCp = (affix == PREFIX) ? output.codePointBefore(index) : output.codePointAt(index);
@ -443,7 +451,7 @@ CurrencySpacingEnabledModifier::applyCurrencySpacingAffix(FormattedStringBuilder
// However, the build code path is more efficient, and this is the most natural
// place to put currency spacing in the non-build code path.
// TODO: Should we use the CURRENCY field here?
return output.insert(index, spacingString, UNUM_FIELD_COUNT, status);
return output.insert(index, spacingString, kUndefinedField, status);
}
UnicodeSet

View file

@ -37,7 +37,7 @@ class U_I18N_API ConstantAffixModifier : public Modifier, public UObject {
bool isStrong() const U_OVERRIDE;
bool containsField(UNumberFormatFields field) const U_OVERRIDE;
bool containsField(Field field) const U_OVERRIDE;
void getParameters(Parameters& output) const U_OVERRIDE;
@ -73,7 +73,7 @@ class U_I18N_API SimpleModifier : public Modifier, public UMemory {
bool isStrong() const U_OVERRIDE;
bool containsField(UNumberFormatFields field) const U_OVERRIDE;
bool containsField(Field field) const U_OVERRIDE;
void getParameters(Parameters& output) const U_OVERRIDE;
@ -166,7 +166,7 @@ class U_I18N_API ConstantMultiFieldModifier : public Modifier, public UMemory {
bool isStrong() const U_OVERRIDE;
bool containsField(UNumberFormatFields field) const U_OVERRIDE;
bool containsField(Field field) const U_OVERRIDE;
void getParameters(Parameters& output) const U_OVERRIDE;
@ -255,7 +255,7 @@ class U_I18N_API EmptyModifier : public Modifier, public UMemory {
return fStrong;
}
bool containsField(UNumberFormatFields field) const U_OVERRIDE {
bool containsField(Field field) const U_OVERRIDE {
(void)field;
return false;
}

View file

@ -21,7 +21,7 @@ addPaddingHelper(UChar32 paddingCp, int32_t requiredPadding, FormattedStringBuil
UErrorCode &status) {
for (int32_t i = 0; i < requiredPadding; i++) {
// TODO: If appending to the end, this will cause actual insertion operations. Improve.
string.insertCodePoint(index, paddingCp, UNUM_FIELD_COUNT, status);
string.insertCodePoint(index, paddingCp, kUndefinedField, status);
}
return U16_LENGTH(paddingCp) * requiredPadding;
}

View file

@ -195,7 +195,7 @@ int32_t MutablePatternModifier::apply(FormattedStringBuilder& output, int32_t le
UnicodeString(),
0,
0,
UNUM_FIELD_COUNT,
kUndefinedField,
status);
}
CurrencySpacingEnabledModifier::applyCurrencySpacing(
@ -239,7 +239,7 @@ bool MutablePatternModifier::isStrong() const {
return fStrong;
}
bool MutablePatternModifier::containsField(UNumberFormatFields field) const {
bool MutablePatternModifier::containsField(Field field) const {
(void)field;
// This method is not currently used.
UPRV_UNREACHABLE;

View file

@ -180,7 +180,7 @@ class U_I18N_API MutablePatternModifier
bool isStrong() const U_OVERRIDE;
bool containsField(UNumberFormatFields field) const U_OVERRIDE;
bool containsField(Field field) const U_OVERRIDE;
void getParameters(Parameters& output) const U_OVERRIDE;

View file

@ -44,21 +44,21 @@ int32_t ScientificModifier::apply(FormattedStringBuilder &output, int32_t /*left
i += output.insert(
i,
fHandler->fSymbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kExponentialSymbol),
UNUM_EXPONENT_SYMBOL_FIELD,
{UFIELD_CATEGORY_NUMBER, UNUM_EXPONENT_SYMBOL_FIELD},
status);
if (fExponent < 0 && fHandler->fSettings.fExponentSignDisplay != UNUM_SIGN_NEVER) {
i += output.insert(
i,
fHandler->fSymbols
->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kMinusSignSymbol),
UNUM_EXPONENT_SIGN_FIELD,
{UFIELD_CATEGORY_NUMBER, UNUM_EXPONENT_SIGN_FIELD},
status);
} else if (fExponent >= 0 && fHandler->fSettings.fExponentSignDisplay == UNUM_SIGN_ALWAYS) {
i += output.insert(
i,
fHandler->fSymbols
->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPlusSignSymbol),
UNUM_EXPONENT_SIGN_FIELD,
{UFIELD_CATEGORY_NUMBER, UNUM_EXPONENT_SIGN_FIELD},
status);
}
// Append the exponent digits (using a simple inline algorithm)
@ -70,7 +70,7 @@ int32_t ScientificModifier::apply(FormattedStringBuilder &output, int32_t /*left
i - j,
d,
*fHandler->fSymbols,
UNUM_EXPONENT_FIELD,
{UFIELD_CATEGORY_NUMBER, UNUM_EXPONENT_FIELD},
status);
}
return i - rightIndex;
@ -93,7 +93,7 @@ bool ScientificModifier::isStrong() const {
return true;
}
bool ScientificModifier::containsField(UNumberFormatFields field) const {
bool ScientificModifier::containsField(Field field) const {
(void)field;
// This method is not used for inner modifiers.
UPRV_UNREACHABLE;

View file

@ -30,7 +30,7 @@ class U_I18N_API ScientificModifier : public UMemory, public Modifier {
bool isStrong() const U_OVERRIDE;
bool containsField(UNumberFormatFields field) const U_OVERRIDE;
bool containsField(Field field) const U_OVERRIDE;
void getParameters(Parameters& output) const U_OVERRIDE;

View file

@ -194,7 +194,7 @@ class U_I18N_API Modifier {
/**
* Whether the modifier contains at least one occurrence of the given field.
*/
virtual bool containsField(UNumberFormatFields field) const = 0;
virtual bool containsField(Field field) const = 0;
/**
* A fill-in for getParameters(). obj will always be set; if non-null, the other

View file

@ -33,7 +33,7 @@ const DecimalQuantity* validateUFormattedNumberToDecimalQuantity(
*/
class UFormattedNumberData : public FormattedValueStringBuilderImpl {
public:
UFormattedNumberData() : FormattedValueStringBuilderImpl(0) {}
UFormattedNumberData() : FormattedValueStringBuilderImpl(kUndefinedField) {}
virtual ~UFormattedNumberData();
DecimalQuantity quantity;

View file

@ -210,7 +210,7 @@ NumberRangeFormatterImpl::NumberRangeFormatterImpl(const RangeMacroProps& macros
getNumberRangeData(macros.locale.getName(), nsName, data, status);
if (U_FAILURE(status)) { return; }
fRangeFormatter = data.rangePattern;
fApproximatelyModifier = {data.approximatelyPattern, UNUM_FIELD_COUNT, false};
fApproximatelyModifier = {data.approximatelyPattern, kUndefinedField, false};
// TODO: Get locale from PluralRules instead?
fPluralRanges.initialize(macros.locale, status);
@ -368,7 +368,8 @@ void NumberRangeFormatterImpl::formatRange(UFormattedNumberRangeData& data,
// Only collapse if the modifier is a unit.
// TODO: Make a better way to check for a unit?
// TODO: Handle case where the modifier has both notation and unit (compact currency)?
if (!mm->containsField(UNUM_CURRENCY_FIELD) && !mm->containsField(UNUM_PERCENT_FIELD)) {
if (!mm->containsField({UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD})
&& !mm->containsField({UFIELD_CATEGORY_NUMBER, UNUM_PERCENT_FIELD})) {
collapseMiddle = false;
}
} else if (fCollapse == UNUM_RANGE_COLLAPSE_AUTO) {
@ -416,7 +417,7 @@ void NumberRangeFormatterImpl::formatRange(UFormattedNumberRangeData& data,
0,
&lengthPrefix,
&lengthSuffix,
UNUM_FIELD_COUNT,
kUndefinedField,
status);
if (U_FAILURE(status)) { return; }
lengthInfix = lengthRange - lengthPrefix - lengthSuffix;
@ -434,10 +435,10 @@ void NumberRangeFormatterImpl::formatRange(UFormattedNumberRangeData& data,
if (repeatInner || repeatMiddle || repeatOuter) {
// Add spacing if there is not already spacing
if (!PatternProps::isWhiteSpace(string.charAt(UPRV_INDEX_1))) {
lengthInfix += string.insertCodePoint(UPRV_INDEX_1, u'\u0020', UNUM_FIELD_COUNT, status);
lengthInfix += string.insertCodePoint(UPRV_INDEX_1, u'\u0020', kUndefinedField, status);
}
if (!PatternProps::isWhiteSpace(string.charAt(UPRV_INDEX_2 - 1))) {
lengthInfix += string.insertCodePoint(UPRV_INDEX_2, u'\u0020', UNUM_FIELD_COUNT, status);
lengthInfix += string.insertCodePoint(UPRV_INDEX_2, u'\u0020', kUndefinedField, status);
}
}
}

View file

@ -31,7 +31,7 @@ namespace impl {
*/
class UFormattedNumberRangeData : public FormattedValueStringBuilderImpl {
public:
UFormattedNumberRangeData() : FormattedValueStringBuilderImpl(0) {}
UFormattedNumberRangeData() : FormattedValueStringBuilderImpl(kUndefinedField) {}
virtual ~UFormattedNumberRangeData();
DecimalQuantity quantity1;

View file

@ -204,7 +204,8 @@ void QuantityFormatter::formatAndSelect(
if (U_FAILURE(status)) {
return;
}
output.append(result, UNUM_FIELD_COUNT, status);
// This code path is probably RBNF. Use the generic numeric field.
output.append(result, kGeneralNumericField, status);
if (U_FAILURE(status)) {
return;
}

View file

@ -728,11 +728,11 @@ const RelativeDateTimeCacheData *LocaleCacheKey<RelativeDateTimeCacheData>::crea
static constexpr number::impl::Field kRDTNumericField
= StringBuilderFieldUtils::compress<UFIELD_CATEGORY_RELATIVE_DATETIME, UDAT_REL_NUMERIC_FIELD>();
static constexpr FormattedStringBuilder::Field kRDTNumericField
= {UFIELD_CATEGORY_RELATIVE_DATETIME, UDAT_REL_NUMERIC_FIELD};
static constexpr number::impl::Field kRDTLiteralField
= StringBuilderFieldUtils::compress<UFIELD_CATEGORY_RELATIVE_DATETIME, UDAT_REL_LITERAL_FIELD>();
static constexpr FormattedStringBuilder::Field kRDTLiteralField
= {UFIELD_CATEGORY_RELATIVE_DATETIME, UDAT_REL_LITERAL_FIELD};
class FormattedRelativeDateTimeData : public FormattedValueStringBuilderImpl {
public:

View file

@ -1508,28 +1508,35 @@ UBool Transliterator::initializeRegistry(UErrorCode &status) {
*/
//static const char translit_index[] = "translit_index";
UErrorCode lstatus = U_ZERO_ERROR;
UResourceBundle *bundle, *transIDs, *colBund;
bundle = ures_open(U_ICUDATA_TRANSLIT, NULL/*open default locale*/, &status);
transIDs = ures_getByKey(bundle, RB_RULE_BASED_IDS, 0, &status);
bundle = ures_open(U_ICUDATA_TRANSLIT, NULL/*open default locale*/, &lstatus);
transIDs = ures_getByKey(bundle, RB_RULE_BASED_IDS, 0, &lstatus);
const UnicodeString T_PART = UNICODE_STRING_SIMPLE("-t-");
int32_t row, maxRows;
if (U_SUCCESS(status)) {
if (lstatus == U_MEMORY_ALLOCATION_ERROR) {
delete registry;
registry = nullptr;
status = U_MEMORY_ALLOCATION_ERROR;
return FALSE;
}
if (U_SUCCESS(lstatus)) {
maxRows = ures_getSize(transIDs);
for (row = 0; row < maxRows; row++) {
colBund = ures_getByIndex(transIDs, row, 0, &status);
if (U_SUCCESS(status)) {
colBund = ures_getByIndex(transIDs, row, 0, &lstatus);
if (U_SUCCESS(lstatus)) {
UnicodeString id(ures_getKey(colBund), -1, US_INV);
if(id.indexOf(T_PART) != -1) {
ures_close(colBund);
continue;
}
UResourceBundle* res = ures_getNextResource(colBund, NULL, &status);
UResourceBundle* res = ures_getNextResource(colBund, NULL, &lstatus);
const char* typeStr = ures_getKey(res);
UChar type;
u_charsToUChars(typeStr, &type, 1);
if (U_SUCCESS(status)) {
if (U_SUCCESS(lstatus)) {
int32_t len = 0;
const UChar *resString;
switch (type) {
@ -1539,19 +1546,19 @@ UBool Transliterator::initializeRegistry(UErrorCode &status) {
// row[2]=resource, row[3]=direction
{
resString = ures_getStringByKey(res, "resource", &len, &status);
resString = ures_getStringByKey(res, "resource", &len, &lstatus);
UBool visible = (type == 0x0066 /*f*/);
UTransDirection dir =
(ures_getUnicodeStringByKey(res, "direction", &status).charAt(0) ==
(ures_getUnicodeStringByKey(res, "direction", &lstatus).charAt(0) ==
0x0046 /*F*/) ?
UTRANS_FORWARD : UTRANS_REVERSE;
registry->put(id, UnicodeString(TRUE, resString, len), dir, TRUE, visible, status);
registry->put(id, UnicodeString(TRUE, resString, len), dir, TRUE, visible, lstatus);
}
break;
case 0x61: // 'a'
// 'alias'; row[2]=createInstance argument
resString = ures_getString(res, &len, &status);
registry->put(id, UnicodeString(TRUE, resString, len), TRUE, TRUE, status);
resString = ures_getString(res, &len, &lstatus);
registry->put(id, UnicodeString(TRUE, resString, len), TRUE, TRUE, lstatus);
break;
}
}

View file

@ -10,6 +10,7 @@
#include "intltest.h"
#include "formatted_string_builder.h"
#include "formattedval_impl.h"
#include "unicode/unum.h"
class FormattedStringBuilderTest : public IntlTest {
@ -61,10 +62,9 @@ void FormattedStringBuilderTest::testInsertAppendUnicodeString() {
FormattedStringBuilder sb3;
sb1.append(str);
// Note: UNUM_FIELD_COUNT is like passing null in Java
sb2.append(str, UNUM_FIELD_COUNT, status);
sb2.append(str, kUndefinedField, status);
assertSuccess("Appending to sb2", status);
sb3.append(str, UNUM_FIELD_COUNT, status);
sb3.append(str, kUndefinedField, status);
assertSuccess("Appending to sb3", status);
assertEqualsImpl(sb1, sb2);
assertEqualsImpl(str, sb3);
@ -74,16 +74,16 @@ void FormattedStringBuilderTest::testInsertAppendUnicodeString() {
sb4.append(u"😇");
sb4.append(str);
sb4.append(u"xx");
sb5.append(u"😇xx", UNUM_FIELD_COUNT, status);
sb5.append(u"😇xx", kUndefinedField, status);
assertSuccess("Appending to sb5", status);
sb5.insert(2, str, UNUM_FIELD_COUNT, status);
sb5.insert(2, str, kUndefinedField, status);
assertSuccess("Inserting into sb5", status);
assertEqualsImpl(sb4, sb5);
int start = uprv_min(1, str.length());
int end = uprv_min(10, str.length());
sb4.insert(3, str, start, end - start); // UnicodeString uses length instead of end index
sb5.insert(3, str, start, end, UNUM_FIELD_COUNT, status);
sb5.insert(3, str, start, end, kUndefinedField, status);
assertSuccess("Inserting into sb5 again", status);
assertEqualsImpl(sb4, sb5);
@ -124,8 +124,8 @@ void FormattedStringBuilderTest::testSplice() {
sb1.append(cas.input);
sb1.replace(cas.startThis, cas.endThis - cas.startThis, replacement);
sb2.clear();
sb2.append(cas.input, UNUM_FIELD_COUNT, status);
sb2.splice(cas.startThis, cas.endThis, replacement, 0, replacement.length(), UNUM_FIELD_COUNT, status);
sb2.append(cas.input, kUndefinedField, status);
sb2.splice(cas.startThis, cas.endThis, replacement, 0, replacement.length(), kUndefinedField, status);
assertSuccess("Splicing into sb2 first time", status);
assertEqualsImpl(sb1, sb2);
@ -137,8 +137,8 @@ void FormattedStringBuilderTest::testSplice() {
sb1.append(cas.input);
sb1.replace(cas.startThis, cas.endThis - cas.startThis, UnicodeString(replacement, 1, 2));
sb2.clear();
sb2.append(cas.input, UNUM_FIELD_COUNT, status);
sb2.splice(cas.startThis, cas.endThis, replacement, 1, 3, UNUM_FIELD_COUNT, status);
sb2.append(cas.input, kUndefinedField, status);
sb2.splice(cas.startThis, cas.endThis, replacement, 1, 3, kUndefinedField, status);
assertSuccess("Splicing into sb2 second time", status);
assertEqualsImpl(sb1, sb2);
}
@ -154,9 +154,9 @@ void FormattedStringBuilderTest::testInsertAppendCodePoint() {
for (UChar32 cas : cases) {
FormattedStringBuilder sb3;
sb1.append(cas);
sb2.appendCodePoint(cas, UNUM_FIELD_COUNT, status);
sb2.appendCodePoint(cas, kUndefinedField, status);
assertSuccess("Appending to sb2", status);
sb3.appendCodePoint(cas, UNUM_FIELD_COUNT, status);
sb3.appendCodePoint(cas, kUndefinedField, status);
assertSuccess("Appending to sb3", status);
assertEqualsImpl(sb1, sb2);
assertEquals("Length of sb3", U16_LENGTH(cas), sb3.length());
@ -170,9 +170,9 @@ void FormattedStringBuilderTest::testInsertAppendCodePoint() {
FormattedStringBuilder sb5;
sb4.append(u"😇xx");
sb4.insert(2, cas);
sb5.append(u"😇xx", UNUM_FIELD_COUNT, status);
sb5.append(u"😇xx", kUndefinedField, status);
assertSuccess("Appending to sb5", status);
sb5.insertCodePoint(2, cas, UNUM_FIELD_COUNT, status);
sb5.insertCodePoint(2, cas, kUndefinedField, status);
assertSuccess("Inserting into sb5", status);
assertEqualsImpl(sb4, sb5);
@ -180,10 +180,10 @@ void FormattedStringBuilderTest::testInsertAppendCodePoint() {
FormattedStringBuilder sb7;
sb6.append(cas);
if (U_IS_SUPPLEMENTARY(cas)) {
sb7.appendChar16(U16_TRAIL(cas), UNUM_FIELD_COUNT, status);
sb7.insertChar16(0, U16_LEAD(cas), UNUM_FIELD_COUNT, status);
sb7.appendChar16(U16_TRAIL(cas), kUndefinedField, status);
sb7.insertChar16(0, U16_LEAD(cas), kUndefinedField, status);
} else {
sb7.insertChar16(0, cas, UNUM_FIELD_COUNT, status);
sb7.insertChar16(0, cas, kUndefinedField, status);
}
assertSuccess("Insert/append into sb7", status);
assertEqualsImpl(sb6, sb7);
@ -194,33 +194,35 @@ void FormattedStringBuilderTest::testCopy() {
UErrorCode status = U_ZERO_ERROR;
for (UnicodeString str : EXAMPLE_STRINGS) {
FormattedStringBuilder sb1;
sb1.append(str, UNUM_FIELD_COUNT, status);
sb1.append(str, kUndefinedField, status);
assertSuccess("Appending to sb1 first time", status);
FormattedStringBuilder sb2(sb1);
assertTrue("Content should equal itself", sb1.contentEquals(sb2));
sb1.append("12345", UNUM_FIELD_COUNT, status);
sb1.append("12345", kUndefinedField, status);
assertSuccess("Appending to sb1 second time", status);
assertFalse("Content should no longer equal itself", sb1.contentEquals(sb2));
}
}
void FormattedStringBuilderTest::testFields() {
typedef FormattedStringBuilder::Field Field;
UErrorCode status = U_ZERO_ERROR;
// Note: This is a C++11 for loop that calls the UnicodeString constructor on each iteration.
for (UnicodeString str : EXAMPLE_STRINGS) {
FormattedValueStringBuilderImpl sbi(0);
FormattedValueStringBuilderImpl sbi(kUndefinedField);
FormattedStringBuilder& sb = sbi.getStringRef();
sb.append(str, UNUM_FIELD_COUNT, status);
sb.append(str, kUndefinedField, status);
assertSuccess("Appending to sb", status);
sb.append(str, UNUM_CURRENCY_FIELD, status);
sb.append(str, {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD}, status);
assertSuccess("Appending to sb", status);
assertEquals("Reference string copied twice", str.length() * 2, sb.length());
for (int32_t i = 0; i < str.length(); i++) {
assertEquals("Null field first",
(FormattedStringBuilder::Field) UNUM_FIELD_COUNT, sb.fieldAt(i));
kUndefinedField.bits, sb.fieldAt(i).bits);
assertEquals("Currency field second",
(FormattedStringBuilder::Field) UNUM_CURRENCY_FIELD, sb.fieldAt(i + str.length()));
Field(UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD).bits,
sb.fieldAt(i + str.length()).bits);
}
// Very basic FieldPosition test. More robust tests happen in NumberFormatTest.
@ -232,10 +234,12 @@ void FormattedStringBuilderTest::testFields() {
assertEquals("Currency end position", str.length() * 2, fp.getEndIndex());
if (str.length() > 0) {
sb.insertCodePoint(2, 100, UNUM_INTEGER_FIELD, status);
sb.insertCodePoint(2, 100, {UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD}, status);
assertSuccess("Inserting code point into sb", status);
assertEquals("New length", str.length() * 2 + 1, sb.length());
assertEquals("Integer field", (FormattedStringBuilder::Field) UNUM_INTEGER_FIELD, sb.fieldAt(2));
assertEquals("Integer field",
Field(UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD).bits,
sb.fieldAt(2).bits);
}
FormattedStringBuilder old(sb);
@ -245,13 +249,14 @@ void FormattedStringBuilderTest::testFields() {
int32_t numCurr = 0;
int32_t numInt = 0;
for (int32_t i = 0; i < sb.length(); i++) {
FormattedStringBuilder::Field field = sb.fieldAt(i);
assertEquals("Field should equal location in old", old.fieldAt(i % old.length()), field);
if (field == UNUM_FIELD_COUNT) {
auto field = sb.fieldAt(i);
assertEquals("Field should equal location in old",
old.fieldAt(i % old.length()).bits, field.bits);
if (field == kUndefinedField) {
numNull++;
} else if (field == UNUM_CURRENCY_FIELD) {
} else if (field == Field(UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD)) {
numCurr++;
} else if (field == UNUM_INTEGER_FIELD) {
} else if (field == Field(UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD)) {
numInt++;
} else {
errln("Encountered unknown field");
@ -271,7 +276,7 @@ void FormattedStringBuilderTest::testUnlimitedCapacity() {
UnicodeString message("Iteration #");
message += Int64ToUnicodeString(i);
assertEquals(message, builder.length(), i);
builder.appendCodePoint(u'x', UNUM_FIELD_COUNT, status);
builder.appendCodePoint(u'x', kUndefinedField, status);
assertSuccess(message, status);
assertEquals(message, builder.length(), i + 1);
}
@ -284,7 +289,7 @@ void FormattedStringBuilderTest::testCodePoints() {
assertEquals("Last is -1 on empty string", -1, nsb.getLastCodePoint());
assertEquals("Length is 0 on empty string", 0, nsb.codePointCount());
nsb.append(u"q", UNUM_FIELD_COUNT, status);
nsb.append(u"q", kUndefinedField, status);
assertSuccess("Spot 1", status);
assertEquals("First is q", u'q', nsb.getFirstCodePoint());
assertEquals("Last is q", u'q', nsb.getLastCodePoint());
@ -293,7 +298,7 @@ void FormattedStringBuilderTest::testCodePoints() {
assertEquals("Code point count is 1", 1, nsb.codePointCount());
// 🚀 is two char16s
nsb.append(u"🚀", UNUM_FIELD_COUNT, status);
nsb.append(u"🚀", kUndefinedField, status);
assertSuccess("Spot 2" ,status);
assertEquals("First is still q", u'q', nsb.getFirstCodePoint());
assertEquals("Last is space ship", 128640, nsb.getLastCodePoint());

View file

@ -222,7 +222,7 @@ void AffixUtilsTest::testUnescapeWithSymbolProvider() {
UnicodeString input(cas[0]);
UnicodeString expected(cas[1]);
sb.clear();
AffixUtils::unescape(input, sb, 0, provider, UNUM_FIELD_COUNT, status);
AffixUtils::unescape(input, sb, 0, provider, kUndefinedField, status);
assertSuccess("Spot 1", status);
assertEquals(input, expected, sb.toUnicodeString());
assertEquals(input, expected, sb.toTempUnicodeString());
@ -230,9 +230,9 @@ void AffixUtilsTest::testUnescapeWithSymbolProvider() {
// Test insertion position
sb.clear();
sb.append(u"abcdefg", UNUM_FIELD_COUNT, status);
sb.append(u"abcdefg", kUndefinedField, status);
assertSuccess("Spot 2", status);
AffixUtils::unescape(u"-+%", sb, 4, provider, UNUM_FIELD_COUNT, status);
AffixUtils::unescape(u"-+%", sb, 4, provider, kUndefinedField, status);
assertSuccess("Spot 3", status);
assertEquals(u"Symbol provider into middle", u"abcd123efg", sb.toUnicodeString());
}
@ -240,7 +240,7 @@ void AffixUtilsTest::testUnescapeWithSymbolProvider() {
UnicodeString AffixUtilsTest::unescapeWithDefaults(const SymbolProvider &defaultProvider,
UnicodeString input, UErrorCode &status) {
FormattedStringBuilder nsb;
int32_t length = AffixUtils::unescape(input, nsb, 0, defaultProvider, UNUM_FIELD_COUNT, status);
int32_t length = AffixUtils::unescape(input, nsb, 0, defaultProvider, kUndefinedField, status);
assertEquals("Return value of unescape", nsb.length(), length);
return nsb.toUnicodeString();
}

View file

@ -25,11 +25,11 @@ void ModifiersTest::runIndexedTest(int32_t index, UBool exec, const char *&name,
void ModifiersTest::testConstantAffixModifier() {
UErrorCode status = U_ZERO_ERROR;
ConstantAffixModifier mod0(u"", u"", UNUM_PERCENT_FIELD, true);
ConstantAffixModifier mod0(u"", u"", {UFIELD_CATEGORY_NUMBER, UNUM_PERCENT_FIELD}, true);
assertModifierEquals(mod0, 0, true, u"|", u"n", status);
assertSuccess("Spot 1", status);
ConstantAffixModifier mod1(u"a📻", u"b", UNUM_PERCENT_FIELD, true);
ConstantAffixModifier mod1(u"a📻", u"b", {UFIELD_CATEGORY_NUMBER, UNUM_PERCENT_FIELD}, true);
assertModifierEquals(mod1, 3, true, u"a📻|b", u"%%%n%", status);
assertSuccess("Spot 2", status);
}
@ -42,8 +42,8 @@ void ModifiersTest::testConstantMultiFieldModifier() {
assertModifierEquals(mod1, 0, true, u"|", u"n", status);
assertSuccess("Spot 1", status);
prefix.append(u"a📻", UNUM_PERCENT_FIELD, status);
suffix.append(u"b", UNUM_CURRENCY_FIELD, status);
prefix.append(u"a📻", {UFIELD_CATEGORY_NUMBER, UNUM_PERCENT_FIELD}, status);
suffix.append(u"b", {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD}, status);
ConstantMultiFieldModifier mod2(prefix, suffix, false, true);
assertModifierEquals(mod2, 3, true, u"a📻|b", u"%%%n$", status);
assertSuccess("Spot 2", status);
@ -80,7 +80,7 @@ void ModifiersTest::testSimpleModifier() {
const UnicodeString pattern(patterns[i]);
SimpleFormatter compiledFormatter(pattern, 1, 1, status);
assertSuccess("Spot 1", status);
SimpleModifier mod(compiledFormatter, UNUM_PERCENT_FIELD, false);
SimpleModifier mod(compiledFormatter, {UFIELD_CATEGORY_NUMBER, UNUM_PERCENT_FIELD}, false);
assertModifierEquals(
mod, prefixLens[i], false, expectedCharFields[i][0], expectedCharFields[i][1], status);
assertSuccess("Spot 2", status);
@ -88,7 +88,7 @@ void ModifiersTest::testSimpleModifier() {
// Test strange insertion positions
for (int32_t j = 0; j < NUM_OUTPUTS; j++) {
FormattedStringBuilder output;
output.append(outputs[j].baseString, UNUM_FIELD_COUNT, status);
output.append(outputs[j].baseString, kUndefinedField, status);
mod.apply(output, outputs[j].leftIndex, outputs[j].rightIndex, status);
UnicodeString expected = expecteds[j][i];
UnicodeString actual = output.toUnicodeString();
@ -112,7 +112,7 @@ void ModifiersTest::testCurrencySpacingEnabledModifier() {
assertModifierEquals(mod1, 0, true, u"|", u"n", status);
assertSuccess("Spot 3", status);
prefix.append(u"USD", UNUM_CURRENCY_FIELD, status);
prefix.append(u"USD", {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD}, status);
assertSuccess("Spot 4", status);
CurrencySpacingEnabledModifier mod2(prefix, suffix, false, true, symbols, status);
assertSuccess("Spot 5", status);
@ -121,7 +121,7 @@ void ModifiersTest::testCurrencySpacingEnabledModifier() {
// Test the default currency spacing rules
FormattedStringBuilder sb;
sb.append("123", UNUM_INTEGER_FIELD, status);
sb.append("123", {UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD}, status);
assertSuccess("Spot 7", status);
FormattedStringBuilder sb1(sb);
assertModifierEquals(mod2, sb1, 3, true, u"USD\u00A0123", u"$$$niii", status);
@ -129,7 +129,7 @@ void ModifiersTest::testCurrencySpacingEnabledModifier() {
// Compare with the unsafe code path
FormattedStringBuilder sb2(sb);
sb2.insert(0, "USD", UNUM_CURRENCY_FIELD, status);
sb2.insert(0, "USD", {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD}, status);
assertSuccess("Spot 9", status);
CurrencySpacingEnabledModifier::applyCurrencySpacing(sb2, 0, 3, 6, 0, symbols, status);
assertSuccess("Spot 10", status);
@ -138,7 +138,7 @@ void ModifiersTest::testCurrencySpacingEnabledModifier() {
// Test custom patterns
// The following line means that the last char of the number should be a | (rather than a digit)
symbols.setPatternForCurrencySpacing(UNUM_CURRENCY_SURROUNDING_MATCH, true, u"[|]");
suffix.append("XYZ", UNUM_CURRENCY_FIELD, status);
suffix.append("XYZ", {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD}, status);
assertSuccess("Spot 11", status);
CurrencySpacingEnabledModifier mod3(prefix, suffix, false, true, symbols, status);
assertSuccess("Spot 12", status);
@ -150,7 +150,7 @@ void ModifiersTest::assertModifierEquals(const Modifier &mod, int32_t expectedPr
bool expectedStrong, UnicodeString expectedChars,
UnicodeString expectedFields, UErrorCode &status) {
FormattedStringBuilder sb;
sb.appendCodePoint('|', UNUM_FIELD_COUNT, status);
sb.appendCodePoint('|', kUndefinedField, status);
assertModifierEquals(
mod, sb, expectedPrefixLength, expectedStrong, expectedChars, expectedFields, status);

View file

@ -26,7 +26,7 @@ void PatternModifierTest::testBasic() {
ParsedPatternInfo patternInfo;
PatternParser::parseToPatternInfo(u"a0b", patternInfo, status);
assertSuccess("Spot 1", status);
mod.setPatternInfo(&patternInfo, UNUM_FIELD_COUNT);
mod.setPatternInfo(&patternInfo, kUndefinedField);
mod.setPatternAttributes(UNUM_SIGN_AUTO, false);
DecimalFormatSymbols symbols(Locale::getEnglish(), status);
CurrencySymbols currencySymbols({u"USD", status}, "en", status);
@ -61,7 +61,7 @@ void PatternModifierTest::testBasic() {
ParsedPatternInfo patternInfo2;
PatternParser::parseToPatternInfo(u"a0b;c-0d", patternInfo2, status);
assertSuccess("Spot 4", status);
mod.setPatternInfo(&patternInfo2, UNUM_FIELD_COUNT);
mod.setPatternInfo(&patternInfo2, kUndefinedField);
mod.setPatternAttributes(UNUM_SIGN_AUTO, false);
mod.setNumberProperties(SIGNUM_POS, StandardPlural::Form::COUNT);
assertEquals("Pattern a0b;c-0d", u"a", getPrefix(mod, status));
@ -93,7 +93,7 @@ void PatternModifierTest::testPatternWithNoPlaceholder() {
ParsedPatternInfo patternInfo;
PatternParser::parseToPatternInfo(u"abc", patternInfo, status);
assertSuccess("Spot 1", status);
mod.setPatternInfo(&patternInfo, UNUM_FIELD_COUNT);
mod.setPatternInfo(&patternInfo, kUndefinedField);
mod.setPatternAttributes(UNUM_SIGN_AUTO, false);
DecimalFormatSymbols symbols(Locale::getEnglish(), status);
CurrencySymbols currencySymbols({u"USD", status}, "en", status);
@ -105,7 +105,7 @@ void PatternModifierTest::testPatternWithNoPlaceholder() {
// Unsafe Code Path
FormattedStringBuilder nsb;
nsb.append(u"x123y", UNUM_FIELD_COUNT, status);
nsb.append(u"x123y", kUndefinedField, status);
assertSuccess("Spot 3", status);
mod.apply(nsb, 1, 4, status);
assertSuccess("Spot 4", status);
@ -113,7 +113,7 @@ void PatternModifierTest::testPatternWithNoPlaceholder() {
// Safe Code Path
nsb.clear();
nsb.append(u"x123y", UNUM_FIELD_COUNT, status);
nsb.append(u"x123y", kUndefinedField, status);
assertSuccess("Spot 5", status);
MicroProps micros;
LocalPointer<ImmutablePatternModifier> imod(mod.createImmutable(status), status);
@ -136,7 +136,7 @@ void PatternModifierTest::testMutableEqualsImmutable() {
ParsedPatternInfo patternInfo;
PatternParser::parseToPatternInfo("a0b;c-0d", patternInfo, status);
assertSuccess("Spot 1", status);
mod.setPatternInfo(&patternInfo, UNUM_FIELD_COUNT);
mod.setPatternInfo(&patternInfo, kUndefinedField);
mod.setPatternAttributes(UNUM_SIGN_AUTO, false);
DecimalFormatSymbols symbols(Locale::getEnglish(), status);
CurrencySymbols currencySymbols({u"USD", status}, "en", status);

View file

@ -196,6 +196,7 @@ TransliteratorTest::runIndexedTest(int32_t index, UBool exec,
TESTCASE(82,TestHalfwidthFullwidth);
TESTCASE(83,TestThai);
TESTCASE(84,TestAny);
TESTCASE(85,TestBasicTransliteratorEvenWithoutData);
default: name = ""; break;
}
}
@ -1508,6 +1509,81 @@ void TransliteratorTest::TestNormalizationTransliterator() {
delete t;
}
/**
* Test we can create basic transliterator even without data.
*/
void TransliteratorTest::TestBasicTransliteratorEvenWithoutData() {
const char16_t* TEST_DATA = u"\u0124e\u0301 \uFB01nd x";
const char16_t* EXPECTED_RESULTS[] = {
u"H\u0302e\u0301 \uFB01nd x", // NFD
u"\u0124\u00E9 \uFB01nd x", // NFC
u"H\u0302e\u0301 find x", // NFKD
u"\u0124\u00E9 find x", // NFKC
u"\u0124e\u0301 \uFB01nd x", // Hex-Any
u"\u0125e\u0301 \uFB01nd x", // Lower
u"\u0124e\uFB01ndx", // [:^L:]Remove
u"H\u0302e\u0301 \uFB01nd ", // NFD; [x]Remove
u"h\u0302e\u0301 find x", // Lower; NFKD;
u"hefindx", // Lower; NFKD; [:^L:]Remove; NFC;
u"\u0124e \uFB01nd x", // [:Nonspacing Mark:] Remove;
u"He \uFB01nd x", // NFD; [:Nonspacing Mark:] Remove; NFC;
// end
0
};
const char* BASIC_TRANSLITERATOR_ID[] = {
"NFD",
"NFC",
"NFKD",
"NFKC",
"Hex-Any",
"Lower",
"[:^L:]Remove",
"NFD; [x]Remove",
"Lower; NFKD;",
"Lower; NFKD; [:^L:]Remove; NFC;",
"[:Nonspacing Mark:] Remove;",
"NFD; [:Nonspacing Mark:] Remove; NFC;",
// end
0
};
const char* BASIC_TRANSLITERATOR_RULES[] = {
"::Lower; ::NFKD;",
"::Lower; ::NFKD; ::[:^L:]Remove; ::NFC;",
"::[:Nonspacing Mark:] Remove;",
"::NFD; ::[:Nonspacing Mark:] Remove; ::NFC;",
// end
0
};
for (int32_t i=0; BASIC_TRANSLITERATOR_ID[i]; i++) {
UErrorCode status = U_ZERO_ERROR;
UParseError parseError;
std::unique_ptr<Transliterator> translit(Transliterator::createInstance(
BASIC_TRANSLITERATOR_ID[i], UTRANS_FORWARD, parseError, status));
if (translit.get() == nullptr || !U_SUCCESS(status)) {
dataerrln("FAIL: createInstance %s failed", BASIC_TRANSLITERATOR_ID[i]);
}
UnicodeString data(TEST_DATA);
UnicodeString expected(EXPECTED_RESULTS[i]);
translit->transliterate(data);
if (data != expected) {
dataerrln(UnicodeString("FAIL: expected translit(") +
BASIC_TRANSLITERATOR_ID[i] + ") = '" +
EXPECTED_RESULTS[i] + "' but got '" + data);
}
}
for (int32_t i=0; BASIC_TRANSLITERATOR_RULES[i]; i++) {
UErrorCode status = U_ZERO_ERROR;
UParseError parseError;
std::unique_ptr<Transliterator> translit(Transliterator::createFromRules(
"Test",
BASIC_TRANSLITERATOR_RULES[i], UTRANS_FORWARD, parseError, status));
if (translit.get() == nullptr || !U_SUCCESS(status)) {
dataerrln("FAIL: createFromRules %s failed", BASIC_TRANSLITERATOR_RULES[i]);
}
}
}
/**
* Test compound RBT rules.
*/

View file

@ -369,6 +369,7 @@ private:
*/
void TestRegisterAlias(void);
void TestBasicTransliteratorEvenWithoutData(void);
//======================================================================
// Support methods
//======================================================================