aboutsummaryrefslogtreecommitdiff
path: root/deps/icu-small/source/i18n
diff options
context:
space:
mode:
Diffstat (limited to 'deps/icu-small/source/i18n')
-rw-r--r--deps/icu-small/source/i18n/alphaindex.cpp8
-rw-r--r--deps/icu-small/source/i18n/anytrans.cpp6
-rw-r--r--deps/icu-small/source/i18n/calendar.cpp2
-rw-r--r--deps/icu-small/source/i18n/coll.cpp11
-rw-r--r--deps/icu-small/source/i18n/collationkeys.cpp12
-rw-r--r--deps/icu-small/source/i18n/csrmbcs.cpp2
-rw-r--r--deps/icu-small/source/i18n/currpinf.cpp278
-rw-r--r--deps/icu-small/source/i18n/currunit.cpp7
-rw-r--r--deps/icu-small/source/i18n/dcfmtsym.cpp2
-rw-r--r--deps/icu-small/source/i18n/decimfmt.cpp32
-rw-r--r--deps/icu-small/source/i18n/dtfmtsym.cpp6
-rw-r--r--deps/icu-small/source/i18n/dtitvfmt.cpp6
-rw-r--r--deps/icu-small/source/i18n/dtitvinf.cpp6
-rw-r--r--deps/icu-small/source/i18n/dtptngen.cpp690
-rw-r--r--deps/icu-small/source/i18n/dtptngen_impl.h46
-rw-r--r--deps/icu-small/source/i18n/erarules.cpp307
-rw-r--r--deps/icu-small/source/i18n/erarules.h92
-rw-r--r--deps/icu-small/source/i18n/fphdlimp.h3
-rw-r--r--deps/icu-small/source/i18n/gregocal.cpp6
-rw-r--r--deps/icu-small/source/i18n/gregoimp.h4
-rw-r--r--deps/icu-small/source/i18n/indiancal.cpp105
-rw-r--r--deps/icu-small/source/i18n/indiancal.h49
-rw-r--r--deps/icu-small/source/i18n/japancal.cpp466
-rw-r--r--deps/icu-small/source/i18n/japancal.h14
-rw-r--r--deps/icu-small/source/i18n/listformatter.cpp525
-rw-r--r--deps/icu-small/source/i18n/measfmt.cpp35
-rw-r--r--deps/icu-small/source/i18n/measunit.cpp112
-rw-r--r--deps/icu-small/source/i18n/msgfmt.cpp2
-rw-r--r--deps/icu-small/source/i18n/nfrule.cpp104
-rw-r--r--deps/icu-small/source/i18n/nfrule.h2
-rw-r--r--deps/icu-small/source/i18n/number_compact.cpp4
-rw-r--r--deps/icu-small/source/i18n/number_decimalquantity.cpp27
-rw-r--r--deps/icu-small/source/i18n/number_decimfmtprops.cpp1
-rw-r--r--deps/icu-small/source/i18n/number_fluent.cpp31
-rw-r--r--deps/icu-small/source/i18n/number_formatimpl.cpp128
-rw-r--r--deps/icu-small/source/i18n/number_formatimpl.h52
-rw-r--r--deps/icu-small/source/i18n/number_grouping.cpp2
-rw-r--r--deps/icu-small/source/i18n/number_longnames.cpp52
-rw-r--r--deps/icu-small/source/i18n/number_longnames.h17
-rw-r--r--deps/icu-small/source/i18n/number_mapper.cpp16
-rw-r--r--deps/icu-small/source/i18n/number_modifiers.cpp178
-rw-r--r--deps/icu-small/source/i18n/number_modifiers.h155
-rw-r--r--deps/icu-small/source/i18n/number_multiplier.cpp8
-rw-r--r--deps/icu-small/source/i18n/number_multiplier.h4
-rw-r--r--deps/icu-small/source/i18n/number_padding.cpp2
-rw-r--r--deps/icu-small/source/i18n/number_patternmodifier.cpp111
-rw-r--r--deps/icu-small/source/i18n/number_patternmodifier.h38
-rw-r--r--deps/icu-small/source/i18n/number_scientific.cpp34
-rw-r--r--deps/icu-small/source/i18n/number_scientific.h10
-rw-r--r--deps/icu-small/source/i18n/number_stringbuilder.cpp12
-rw-r--r--deps/icu-small/source/i18n/number_stringbuilder.h2
-rw-r--r--deps/icu-small/source/i18n/number_types.h58
-rw-r--r--deps/icu-small/source/i18n/numfmt.cpp50
-rw-r--r--deps/icu-small/source/i18n/numparse_currency.cpp4
-rw-r--r--deps/icu-small/source/i18n/numparse_impl.cpp4
-rw-r--r--deps/icu-small/source/i18n/numparse_scientific.cpp5
-rw-r--r--deps/icu-small/source/i18n/numrange_fluent.cpp472
-rw-r--r--deps/icu-small/source/i18n/numrange_impl.cpp486
-rw-r--r--deps/icu-small/source/i18n/numrange_impl.h114
-rw-r--r--deps/icu-small/source/i18n/numsys.cpp144
-rw-r--r--deps/icu-small/source/i18n/numsys_impl.h2
-rw-r--r--deps/icu-small/source/i18n/olsontz.cpp6
-rw-r--r--deps/icu-small/source/i18n/plurrule.cpp456
-rw-r--r--deps/icu-small/source/i18n/plurrule_impl.h52
-rw-r--r--deps/icu-small/source/i18n/rbnf.cpp183
-rw-r--r--deps/icu-small/source/i18n/rbt.h258
-rw-r--r--deps/icu-small/source/i18n/rbt_pars.cpp12
-rw-r--r--deps/icu-small/source/i18n/regexcmp.cpp361
-rw-r--r--deps/icu-small/source/i18n/region.cpp56
-rw-r--r--deps/icu-small/source/i18n/reldatefmt.cpp247
-rw-r--r--deps/icu-small/source/i18n/reldtfmt.cpp6
-rw-r--r--deps/icu-small/source/i18n/reldtfmt.h1
-rw-r--r--deps/icu-small/source/i18n/rematch.cpp74
-rw-r--r--deps/icu-small/source/i18n/rulebasedcollator.cpp10
-rw-r--r--deps/icu-small/source/i18n/scriptset.cpp2
-rw-r--r--deps/icu-small/source/i18n/shareddateformatsymbols.h5
-rw-r--r--deps/icu-small/source/i18n/smpdtfmt.cpp66
-rw-r--r--deps/icu-small/source/i18n/timezone.cpp10
-rw-r--r--deps/icu-small/source/i18n/transreg.cpp6
-rw-r--r--deps/icu-small/source/i18n/tzfmt.cpp6
-rw-r--r--deps/icu-small/source/i18n/tzgnames.cpp2
-rw-r--r--deps/icu-small/source/i18n/tznames.cpp2
-rw-r--r--deps/icu-small/source/i18n/tznames_impl.cpp14
-rw-r--r--deps/icu-small/source/i18n/ucln_in.h2
-rw-r--r--deps/icu-small/source/i18n/ucol_res.cpp14
-rw-r--r--deps/icu-small/source/i18n/udat.cpp2
-rw-r--r--deps/icu-small/source/i18n/ulistformatter.cpp91
-rw-r--r--deps/icu-small/source/i18n/ulocdata.cpp2
-rw-r--r--deps/icu-small/source/i18n/unicode/alphaindex.h11
-rw-r--r--deps/icu-small/source/i18n/unicode/calendar.h161
-rw-r--r--deps/icu-small/source/i18n/unicode/coll.h14
-rw-r--r--deps/icu-small/source/i18n/unicode/compactdecimalformat.h19
-rw-r--r--deps/icu-small/source/i18n/unicode/currpinf.h15
-rw-r--r--deps/icu-small/source/i18n/unicode/currunit.h6
-rw-r--r--deps/icu-small/source/i18n/unicode/datefmt.h10
-rw-r--r--deps/icu-small/source/i18n/unicode/dcfmtsym.h8
-rw-r--r--deps/icu-small/source/i18n/unicode/decimfmt.h69
-rw-r--r--deps/icu-small/source/i18n/unicode/dtptngen.h16
-rw-r--r--deps/icu-small/source/i18n/unicode/fmtable.h2
-rw-r--r--deps/icu-small/source/i18n/unicode/gender.h7
-rw-r--r--deps/icu-small/source/i18n/unicode/listformatter.h203
-rw-r--r--deps/icu-small/source/i18n/unicode/measfmt.h14
-rw-r--r--deps/icu-small/source/i18n/unicode/measunit.h40
-rw-r--r--deps/icu-small/source/i18n/unicode/msgfmt.h11
-rw-r--r--deps/icu-small/source/i18n/unicode/numberformatter.h119
-rw-r--r--deps/icu-small/source/i18n/unicode/numberrangeformatter.h866
-rw-r--r--deps/icu-small/source/i18n/unicode/numfmt.h23
-rw-r--r--deps/icu-small/source/i18n/unicode/plurfmt.h12
-rw-r--r--deps/icu-small/source/i18n/unicode/plurrule.h8
-rw-r--r--deps/icu-small/source/i18n/unicode/rbnf.h9
-rw-r--r--deps/icu-small/source/i18n/unicode/region.h2
-rw-r--r--deps/icu-small/source/i18n/unicode/reldatefmt.h14
-rw-r--r--deps/icu-small/source/i18n/unicode/smpdtfmt.h4
-rw-r--r--deps/icu-small/source/i18n/unicode/translit.h291
-rw-r--r--deps/icu-small/source/i18n/unicode/tzfmt.h6
-rw-r--r--deps/icu-small/source/i18n/unicode/ucal.h13
-rw-r--r--deps/icu-small/source/i18n/unicode/ucol.h3
-rw-r--r--deps/icu-small/source/i18n/unicode/ugender.h4
-rw-r--r--deps/icu-small/source/i18n/unicode/ulistformatter.h150
-rw-r--r--deps/icu-small/source/i18n/unicode/unumberformatter.h36
-rw-r--r--deps/icu-small/source/i18n/unicode/usearch.h7
-rw-r--r--deps/icu-small/source/i18n/unicode/uspoof.h23
-rw-r--r--deps/icu-small/source/i18n/uregex.cpp4
-rw-r--r--deps/icu-small/source/i18n/usearch.cpp2
-rw-r--r--deps/icu-small/source/i18n/uspoof_impl.h2
-rw-r--r--deps/icu-small/source/i18n/vtzone.cpp2
-rw-r--r--deps/icu-small/source/i18n/zonemeta.cpp16
127 files changed, 6621 insertions, 2710 deletions
diff --git a/deps/icu-small/source/i18n/alphaindex.cpp b/deps/icu-small/source/i18n/alphaindex.cpp
index f4a082c5b2..99f70114cb 100644
--- a/deps/icu-small/source/i18n/alphaindex.cpp
+++ b/deps/icu-small/source/i18n/alphaindex.cpp
@@ -511,8 +511,8 @@ BucketList *AlphabeticIndex::createBucketList(UErrorCode &errorCode) const {
ces, errorCode) &&
current.charAt(current.length() - 1) != 0xFFFF /* !current.endsWith("\uffff") */) {
// "AE-ligature" or "Sch" etc.
- for (int32_t i = bucketList->size() - 2;; --i) {
- Bucket *singleBucket = getBucket(*bucketList, i);
+ for (int32_t j = bucketList->size() - 2;; --j) {
+ Bucket *singleBucket = getBucket(*bucketList, j);
if (singleBucket->labelType_ != U_ALPHAINDEX_NORMAL) {
// There is no single-character bucket since the last
// underflow or inflow label.
@@ -608,8 +608,8 @@ BucketList *AlphabeticIndex::createBucketList(UErrorCode &errorCode) const {
}
// Do not call publicBucketList->setDeleter():
// This vector shares its objects with the bucketList.
- for (int32_t i = 0; i < bucketList->size(); ++i) {
- bucket = getBucket(*bucketList, i);
+ for (int32_t j = 0; j < bucketList->size(); ++j) {
+ bucket = getBucket(*bucketList, j);
if (bucket->displayBucket_ == NULL) {
publicBucketList->addElement(bucket, errorCode);
}
diff --git a/deps/icu-small/source/i18n/anytrans.cpp b/deps/icu-small/source/i18n/anytrans.cpp
index d06469e2ae..6e382b824b 100644
--- a/deps/icu-small/source/i18n/anytrans.cpp
+++ b/deps/icu-small/source/i18n/anytrans.cpp
@@ -391,12 +391,12 @@ void AnyTransliterator::registerIDs() {
UnicodeString id;
TransliteratorIDParser::STVtoID(UnicodeString(TRUE, ANY, 3), target, variant, id);
ec = U_ZERO_ERROR;
- AnyTransliterator* t = new AnyTransliterator(id, target, variant,
+ AnyTransliterator* tl = new AnyTransliterator(id, target, variant,
targetScript, ec);
if (U_FAILURE(ec)) {
- delete t;
+ delete tl;
} else {
- Transliterator::_registerInstance(t);
+ Transliterator::_registerInstance(tl);
Transliterator::_registerSpecialInverse(target, UnicodeString(TRUE, NULL_ID, 4), FALSE);
}
}
diff --git a/deps/icu-small/source/i18n/calendar.cpp b/deps/icu-small/source/i18n/calendar.cpp
index 61757cb250..24c2fb964e 100644
--- a/deps/icu-small/source/i18n/calendar.cpp
+++ b/deps/icu-small/source/i18n/calendar.cpp
@@ -3797,7 +3797,7 @@ Calendar::setWeekData(const Locale& desiredLocale, const char *type, UErrorCode&
Locale max = Locale::createFromName(maxLocaleID);
useLocale = Locale(max.getLanguage(),max.getCountry());
} else {
- useLocale = Locale(desiredLocale);
+ useLocale = desiredLocale;
}
/* The code here is somewhat of a hack, since week data and weekend data aren't really tied to
diff --git a/deps/icu-small/source/i18n/coll.cpp b/deps/icu-small/source/i18n/coll.cpp
index b7348a1d16..2a614fac5d 100644
--- a/deps/icu-small/source/i18n/coll.cpp
+++ b/deps/icu-small/source/i18n/coll.cpp
@@ -448,6 +448,13 @@ Collator* U_EXPORT2 Collator::createInstance(const Locale& desiredLocale,
#endif
{
coll = makeInstance(desiredLocale, status);
+ // Either returns NULL with U_FAILURE(status), or non-NULL with U_SUCCESS(status)
+ }
+ // The use of *coll in setAttributesFromKeywords can cause the NULL check to be
+ // optimized out of the delete even though setAttributesFromKeywords returns
+ // immediately if U_FAILURE(status), so we add a check here.
+ if (U_FAILURE(status)) {
+ return NULL;
}
setAttributesFromKeywords(desiredLocale, *coll, status);
if (U_FAILURE(status)) {
@@ -986,8 +993,8 @@ Collator::internalCompareUTF8(const char *left, int32_t leftLength,
return UCOL_EQUAL;
}
return compareUTF8(
- StringPiece(left, (leftLength < 0) ? uprv_strlen(left) : leftLength),
- StringPiece(right, (rightLength < 0) ? uprv_strlen(right) : rightLength),
+ StringPiece(left, (leftLength < 0) ? static_cast<int32_t>(uprv_strlen(left)) : leftLength),
+ StringPiece(right, (rightLength < 0) ? static_cast<int32_t>(uprv_strlen(right)) : rightLength),
errorCode);
}
diff --git a/deps/icu-small/source/i18n/collationkeys.cpp b/deps/icu-small/source/i18n/collationkeys.cpp
index 4b9e6b5907..b5c322fb44 100644
--- a/deps/icu-small/source/i18n/collationkeys.cpp
+++ b/deps/icu-small/source/i18n/collationkeys.cpp
@@ -403,13 +403,13 @@ CollationKeys::writeSortKeyUpToQuaternary(CollationIterator &iter,
uint8_t *secs = secondaries.data();
int32_t last = secondaries.length() - 1;
if(secSegmentStart < last) {
- uint8_t *p = secs + secSegmentStart;
- uint8_t *q = secs + last;
+ uint8_t *q = secs + secSegmentStart;
+ uint8_t *r = secs + last;
do {
- uint8_t b = *p;
- *p++ = *q;
- *q-- = b;
- } while(p < q);
+ uint8_t b = *q;
+ *q++ = *r;
+ *r-- = b;
+ } while(q < r);
}
secondaries.appendByte(p == Collation::NO_CE_PRIMARY ?
Collation::LEVEL_SEPARATOR_BYTE : Collation::MERGE_SEPARATOR_BYTE);
diff --git a/deps/icu-small/source/i18n/csrmbcs.cpp b/deps/icu-small/source/i18n/csrmbcs.cpp
index 0c2df594d5..46d626bb3f 100644
--- a/deps/icu-small/source/i18n/csrmbcs.cpp
+++ b/deps/icu-small/source/i18n/csrmbcs.cpp
@@ -166,7 +166,7 @@ int32_t CharsetRecog_mbcs::match_mbcs(InputText *det, const uint16_t commonChars
doubleByteCharCount++;
if (commonChars != 0) {
- if (binarySearch(commonChars, commonCharsLen, iter.charValue) >= 0){
+ if (binarySearch(commonChars, commonCharsLen, static_cast<uint16_t>(iter.charValue)) >= 0){
commonCharCount += 1;
}
}
diff --git a/deps/icu-small/source/i18n/currpinf.cpp b/deps/icu-small/source/i18n/currpinf.cpp
index 6b1efd5f4d..f5d27e28d8 100644
--- a/deps/icu-small/source/i18n/currpinf.cpp
+++ b/deps/icu-small/source/i18n/currpinf.cpp
@@ -17,7 +17,6 @@
#include <iostream>
#endif
-
#include "unicode/locid.h"
#include "unicode/plurrule.h"
#include "unicode/strenum.h"
@@ -30,7 +29,6 @@
U_NAMESPACE_BEGIN
-
static const UChar gNumberPatternSeparator = 0x3B; // ;
U_CDECL_BEGIN
@@ -65,66 +63,86 @@ static const char gDecimalFormatTag[]="decimalFormat";
static const char gCurrUnitPtnTag[]="CurrencyUnitPatterns";
CurrencyPluralInfo::CurrencyPluralInfo(UErrorCode& status)
-: fPluralCountToCurrencyUnitPattern(NULL),
- fPluralRules(NULL),
- fLocale(NULL) {
+: fPluralCountToCurrencyUnitPattern(nullptr),
+ fPluralRules(nullptr),
+ fLocale(nullptr),
+ fInternalStatus(U_ZERO_ERROR) {
initialize(Locale::getDefault(), status);
}
CurrencyPluralInfo::CurrencyPluralInfo(const Locale& locale, UErrorCode& status)
-: fPluralCountToCurrencyUnitPattern(NULL),
- fPluralRules(NULL),
- fLocale(NULL) {
+: fPluralCountToCurrencyUnitPattern(nullptr),
+ fPluralRules(nullptr),
+ fLocale(nullptr),
+ fInternalStatus(U_ZERO_ERROR) {
initialize(locale, status);
}
CurrencyPluralInfo::CurrencyPluralInfo(const CurrencyPluralInfo& info)
: UObject(info),
- fPluralCountToCurrencyUnitPattern(NULL),
- fPluralRules(NULL),
- fLocale(NULL) {
+ fPluralCountToCurrencyUnitPattern(nullptr),
+ fPluralRules(nullptr),
+ fLocale(nullptr),
+ fInternalStatus(U_ZERO_ERROR) {
*this = info;
}
-
CurrencyPluralInfo&
CurrencyPluralInfo::operator=(const CurrencyPluralInfo& info) {
if (this == &info) {
return *this;
}
+ fInternalStatus = info.fInternalStatus;
+ if (U_FAILURE(fInternalStatus)) {
+ // bail out early if the object we were copying from was already 'invalid'.
+ return *this;
+ }
+
deleteHash(fPluralCountToCurrencyUnitPattern);
- UErrorCode status = U_ZERO_ERROR;
- fPluralCountToCurrencyUnitPattern = initHash(status);
+ fPluralCountToCurrencyUnitPattern = initHash(fInternalStatus);
copyHash(info.fPluralCountToCurrencyUnitPattern,
- fPluralCountToCurrencyUnitPattern, status);
- if ( U_FAILURE(status) ) {
+ fPluralCountToCurrencyUnitPattern, fInternalStatus);
+ if ( U_FAILURE(fInternalStatus) ) {
return *this;
}
delete fPluralRules;
+ fPluralRules = nullptr;
delete fLocale;
- if (info.fPluralRules) {
+ fLocale = nullptr;
+
+ if (info.fPluralRules != nullptr) {
fPluralRules = info.fPluralRules->clone();
- } else {
- fPluralRules = NULL;
+ if (fPluralRules == nullptr) {
+ fInternalStatus = U_MEMORY_ALLOCATION_ERROR;
+ return *this;
+ }
}
- if (info.fLocale) {
+ if (info.fLocale != nullptr) {
fLocale = info.fLocale->clone();
- } else {
- fLocale = NULL;
+ if (fLocale == nullptr) {
+ // Note: If clone had an error parameter, then we could check/set that instead.
+ fInternalStatus = U_MEMORY_ALLOCATION_ERROR;
+ return *this;
+ }
+ // If the other locale wasn't bogus, but our clone'd locale is bogus, then OOM happened
+ // during the call to clone().
+ if (!info.fLocale->isBogus() && fLocale->isBogus()) {
+ fInternalStatus = U_MEMORY_ALLOCATION_ERROR;
+ return *this;
+ }
}
return *this;
}
-
CurrencyPluralInfo::~CurrencyPluralInfo() {
deleteHash(fPluralCountToCurrencyUnitPattern);
- fPluralCountToCurrencyUnitPattern = NULL;
+ fPluralCountToCurrencyUnitPattern = nullptr;
delete fPluralRules;
delete fLocale;
- fPluralRules = NULL;
- fLocale = NULL;
+ fPluralRules = nullptr;
+ fLocale = nullptr;
}
UBool
@@ -148,7 +166,14 @@ CurrencyPluralInfo::operator==(const CurrencyPluralInfo& info) const {
CurrencyPluralInfo*
CurrencyPluralInfo::clone() const {
- return new CurrencyPluralInfo(*this);
+ CurrencyPluralInfo* newObj = new CurrencyPluralInfo(*this);
+ // Since clone doesn't have a 'status' parameter, the best we can do is return nullptr
+ // if the new object was not full constructed properly (an error occurred).
+ if (newObj != nullptr && U_FAILURE(newObj->fInternalStatus)) {
+ delete newObj;
+ newObj = nullptr;
+ }
+ return newObj;
}
const PluralRules*
@@ -161,15 +186,15 @@ CurrencyPluralInfo::getCurrencyPluralPattern(const UnicodeString& pluralCount,
UnicodeString& result) const {
const UnicodeString* currencyPluralPattern =
(UnicodeString*)fPluralCountToCurrencyUnitPattern->get(pluralCount);
- if (currencyPluralPattern == NULL) {
+ if (currencyPluralPattern == nullptr) {
// fall back to "other"
if (pluralCount.compare(gPluralCountOther, 5)) {
currencyPluralPattern =
(UnicodeString*)fPluralCountToCurrencyUnitPattern->get(UnicodeString(TRUE, gPluralCountOther, 5));
}
- if (currencyPluralPattern == NULL) {
+ if (currencyPluralPattern == nullptr) {
// no currencyUnitPatterns defined,
- // fallback to predefined defult.
+ // fallback to predefined default.
// This should never happen when ICU resource files are
// available, since currencyUnitPattern of "other" is always
// defined in root.
@@ -190,14 +215,11 @@ void
CurrencyPluralInfo::setPluralRules(const UnicodeString& ruleDescription,
UErrorCode& status) {
if (U_SUCCESS(status)) {
- if (fPluralRules) {
- delete fPluralRules;
- }
+ delete fPluralRules;
fPluralRules = PluralRules::createRules(ruleDescription, status);
}
}
-
void
CurrencyPluralInfo::setCurrencyPluralPattern(const UnicodeString& pluralCount,
const UnicodeString& pattern,
@@ -206,63 +228,77 @@ CurrencyPluralInfo::setCurrencyPluralPattern(const UnicodeString& pluralCount,
UnicodeString* oldValue = static_cast<UnicodeString*>(
fPluralCountToCurrencyUnitPattern->get(pluralCount));
delete oldValue;
- fPluralCountToCurrencyUnitPattern->put(pluralCount, new UnicodeString(pattern), status);
+ LocalPointer<UnicodeString> p(new UnicodeString(pattern), status);
+ if (U_SUCCESS(status)) {
+ // the p object allocated above will be owned by fPluralCountToCurrencyUnitPattern
+ // after the call to put(), even if the method returns failure.
+ fPluralCountToCurrencyUnitPattern->put(pluralCount, p.orphan(), status);
+ }
}
}
-
void
CurrencyPluralInfo::setLocale(const Locale& loc, UErrorCode& status) {
initialize(loc, status);
}
-
void
CurrencyPluralInfo::initialize(const Locale& loc, UErrorCode& status) {
if (U_FAILURE(status)) {
return;
}
delete fLocale;
+ fLocale = nullptr;
+ delete fPluralRules;
+ fPluralRules = nullptr;
+
fLocale = loc.clone();
- if (fPluralRules) {
- delete fPluralRules;
+ if (fLocale == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ // If the locale passed in wasn't bogus, but our clone'd locale is bogus, then OOM happened
+ // during the call to loc.clone().
+ if (!loc.isBogus() && fLocale->isBogus()) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
}
fPluralRules = PluralRules::forLocale(loc, status);
setupCurrencyPluralPattern(loc, status);
}
-
void
CurrencyPluralInfo::setupCurrencyPluralPattern(const Locale& loc, UErrorCode& status) {
if (U_FAILURE(status)) {
return;
}
- if (fPluralCountToCurrencyUnitPattern) {
- deleteHash(fPluralCountToCurrencyUnitPattern);
- }
+ deleteHash(fPluralCountToCurrencyUnitPattern);
fPluralCountToCurrencyUnitPattern = initHash(status);
if (U_FAILURE(status)) {
return;
}
- NumberingSystem *ns = NumberingSystem::createInstance(loc,status);
+ LocalPointer<NumberingSystem> ns(NumberingSystem::createInstance(loc, status), status);
+ if (U_FAILURE(status)) {
+ return;
+ }
UErrorCode ec = U_ZERO_ERROR;
- UResourceBundle *rb = ures_open(NULL, loc.getName(), &ec);
- UResourceBundle *numElements = ures_getByKeyWithFallback(rb, gNumberElementsTag, NULL, &ec);
- rb = ures_getByKeyWithFallback(numElements, ns->getName(), rb, &ec);
- rb = ures_getByKeyWithFallback(rb, gPatternsTag, rb, &ec);
+ LocalUResourceBundlePointer rb(ures_open(nullptr, loc.getName(), &ec));
+ LocalUResourceBundlePointer numElements(ures_getByKeyWithFallback(rb.getAlias(), gNumberElementsTag, nullptr, &ec));
+ ures_getByKeyWithFallback(numElements.getAlias(), ns->getName(), rb.getAlias(), &ec);
+ ures_getByKeyWithFallback(rb.getAlias(), gPatternsTag, rb.getAlias(), &ec);
int32_t ptnLen;
- const UChar* numberStylePattern = ures_getStringByKeyWithFallback(rb, gDecimalFormatTag, &ptnLen, &ec);
+ const UChar* numberStylePattern = ures_getStringByKeyWithFallback(rb.getAlias(), gDecimalFormatTag, &ptnLen, &ec);
// Fall back to "latn" if num sys specific pattern isn't there.
- if ( ec == U_MISSING_RESOURCE_ERROR && uprv_strcmp(ns->getName(),gLatnTag)) {
+ if ( ec == U_MISSING_RESOURCE_ERROR && (uprv_strcmp(ns->getName(), gLatnTag) != 0)) {
ec = U_ZERO_ERROR;
- rb = ures_getByKeyWithFallback(numElements, gLatnTag, rb, &ec);
- rb = ures_getByKeyWithFallback(rb, gPatternsTag, rb, &ec);
- numberStylePattern = ures_getStringByKeyWithFallback(rb, gDecimalFormatTag, &ptnLen, &ec);
+ ures_getByKeyWithFallback(numElements.getAlias(), gLatnTag, rb.getAlias(), &ec);
+ ures_getByKeyWithFallback(rb.getAlias(), gPatternsTag, rb.getAlias(), &ec);
+ numberStylePattern = ures_getStringByKeyWithFallback(rb.getAlias(), gDecimalFormatTag, &ptnLen, &ec);
}
int32_t numberStylePatternLen = ptnLen;
- const UChar* negNumberStylePattern = NULL;
+ const UChar* negNumberStylePattern = nullptr;
int32_t negNumberStylePatternLen = 0;
// TODO: Java
// parse to check whether there is ";" separator in the numberStylePattern
@@ -279,127 +315,127 @@ CurrencyPluralInfo::setupCurrencyPluralPattern(const Locale& loc, UErrorCode& st
}
}
- ures_close(numElements);
- ures_close(rb);
- delete ns;
-
if (U_FAILURE(ec)) {
+ // If OOM occurred during the above code, then we want to report that back to the caller.
+ if (ec == U_MEMORY_ALLOCATION_ERROR) {
+ status = ec;
+ }
return;
}
- UResourceBundle *currRb = ures_open(U_ICUDATA_CURR, loc.getName(), &ec);
- UResourceBundle *currencyRes = ures_getByKeyWithFallback(currRb, gCurrUnitPtnTag, NULL, &ec);
+ LocalUResourceBundlePointer currRb(ures_open(U_ICUDATA_CURR, loc.getName(), &ec));
+ LocalUResourceBundlePointer currencyRes(ures_getByKeyWithFallback(currRb.getAlias(), gCurrUnitPtnTag, nullptr, &ec));
#ifdef CURRENCY_PLURAL_INFO_DEBUG
std::cout << "in set up\n";
#endif
- StringEnumeration* keywords = fPluralRules->getKeywords(ec);
+ LocalPointer<StringEnumeration> keywords(fPluralRules->getKeywords(ec), ec);
if (U_SUCCESS(ec)) {
const char* pluralCount;
- while ((pluralCount = keywords->next(NULL, ec)) != NULL) {
- if ( U_SUCCESS(ec) ) {
- int32_t ptnLen;
- UErrorCode err = U_ZERO_ERROR;
- const UChar* patternChars = ures_getStringByKeyWithFallback(
- currencyRes, pluralCount, &ptnLen, &err);
- if (U_SUCCESS(err) && ptnLen > 0) {
- UnicodeString* pattern = new UnicodeString(patternChars, ptnLen);
+ while (((pluralCount = keywords->next(nullptr, ec)) != nullptr) && U_SUCCESS(ec)) {
+ int32_t ptnLength;
+ UErrorCode err = U_ZERO_ERROR;
+ const UChar* patternChars = ures_getStringByKeyWithFallback(currencyRes.getAlias(), pluralCount, &ptnLength, &err);
+ if (err == U_MEMORY_ALLOCATION_ERROR || patternChars == nullptr) {
+ ec = err;
+ break;
+ }
+ if (U_SUCCESS(err) && ptnLength > 0) {
+ UnicodeString* pattern = new UnicodeString(patternChars, ptnLength);
+ if (pattern == nullptr) {
+ ec = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
#ifdef CURRENCY_PLURAL_INFO_DEBUG
- char result_1[1000];
- pattern->extract(0, pattern->length(), result_1, "UTF-8");
- std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n";
+ char result_1[1000];
+ pattern->extract(0, pattern->length(), result_1, "UTF-8");
+ std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n";
#endif
- pattern->findAndReplace(UnicodeString(TRUE, gPart0, 3),
- UnicodeString(numberStylePattern, numberStylePatternLen));
- pattern->findAndReplace(UnicodeString(TRUE, gPart1, 3), UnicodeString(TRUE, gTripleCurrencySign, 3));
-
- if (hasSeparator) {
- UnicodeString negPattern(patternChars, ptnLen);
- negPattern.findAndReplace(UnicodeString(TRUE, gPart0, 3),
- UnicodeString(negNumberStylePattern, negNumberStylePatternLen));
- negPattern.findAndReplace(UnicodeString(TRUE, gPart1, 3), UnicodeString(TRUE, gTripleCurrencySign, 3));
- pattern->append(gNumberPatternSeparator);
- pattern->append(negPattern);
- }
+ pattern->findAndReplace(UnicodeString(TRUE, gPart0, 3),
+ UnicodeString(numberStylePattern, numberStylePatternLen));
+ pattern->findAndReplace(UnicodeString(TRUE, gPart1, 3), UnicodeString(TRUE, gTripleCurrencySign, 3));
+
+ if (hasSeparator) {
+ UnicodeString negPattern(patternChars, ptnLength);
+ negPattern.findAndReplace(UnicodeString(TRUE, gPart0, 3),
+ UnicodeString(negNumberStylePattern, negNumberStylePatternLen));
+ negPattern.findAndReplace(UnicodeString(TRUE, gPart1, 3), UnicodeString(TRUE, gTripleCurrencySign, 3));
+ pattern->append(gNumberPatternSeparator);
+ pattern->append(negPattern);
+ }
#ifdef CURRENCY_PLURAL_INFO_DEBUG
- pattern->extract(0, pattern->length(), result_1, "UTF-8");
- std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n";
+ pattern->extract(0, pattern->length(), result_1, "UTF-8");
+ std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n";
#endif
-
- fPluralCountToCurrencyUnitPattern->put(UnicodeString(pluralCount, -1, US_INV), pattern, status);
- }
+ // the 'pattern' object allocated above will be owned by the fPluralCountToCurrencyUnitPattern after the call to
+ // put(), even if the method returns failure.
+ fPluralCountToCurrencyUnitPattern->put(UnicodeString(pluralCount, -1, US_INV), pattern, status);
}
}
}
- delete keywords;
- ures_close(currencyRes);
- ures_close(currRb);
+ // If OOM occurred during the above code, then we want to report that back to the caller.
+ if (ec == U_MEMORY_ALLOCATION_ERROR) {
+ status = ec;
+ }
}
-
-
void
-CurrencyPluralInfo::deleteHash(Hashtable* hTable)
-{
- if ( hTable == NULL ) {
+CurrencyPluralInfo::deleteHash(Hashtable* hTable) {
+ if ( hTable == nullptr ) {
return;
}
int32_t pos = UHASH_FIRST;
- const UHashElement* element = NULL;
- while ( (element = hTable->nextElement(pos)) != NULL ) {
+ const UHashElement* element = nullptr;
+ while ( (element = hTable->nextElement(pos)) != nullptr ) {
const UHashTok valueTok = element->value;
const UnicodeString* value = (UnicodeString*)valueTok.pointer;
delete value;
}
delete hTable;
- hTable = NULL;
+ hTable = nullptr;
}
-
Hashtable*
CurrencyPluralInfo::initHash(UErrorCode& status) {
- if ( U_FAILURE(status) ) {
- return NULL;
- }
- Hashtable* hTable;
- if ( (hTable = new Hashtable(TRUE, status)) == NULL ) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
+ if (U_FAILURE(status)) {
+ return nullptr;
}
- if ( U_FAILURE(status) ) {
- delete hTable;
- return NULL;
+ LocalPointer<Hashtable> hTable(new Hashtable(TRUE, status), status);
+ if (U_FAILURE(status)) {
+ return nullptr;
}
hTable->setValueComparator(ValueComparator);
- return hTable;
+ return hTable.orphan();
}
-
void
CurrencyPluralInfo::copyHash(const Hashtable* source,
Hashtable* target,
UErrorCode& status) {
- if ( U_FAILURE(status) ) {
+ if (U_FAILURE(status)) {
return;
}
int32_t pos = UHASH_FIRST;
- const UHashElement* element = NULL;
- if ( source ) {
- while ( (element = source->nextElement(pos)) != NULL ) {
+ const UHashElement* element = nullptr;
+ if (source) {
+ while ( (element = source->nextElement(pos)) != nullptr ) {
const UHashTok keyTok = element->key;
const UnicodeString* key = (UnicodeString*)keyTok.pointer;
const UHashTok valueTok = element->value;
const UnicodeString* value = (UnicodeString*)valueTok.pointer;
- UnicodeString* copy = new UnicodeString(*value);
- target->put(UnicodeString(*key), copy, status);
- if ( U_FAILURE(status) ) {
+ LocalPointer<UnicodeString> copy(new UnicodeString(*value), status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ // The HashTable owns the 'copy' object after the call to put().
+ target->put(UnicodeString(*key), copy.orphan(), status);
+ if (U_FAILURE(status)) {
return;
}
}
}
}
-
U_NAMESPACE_END
#endif
diff --git a/deps/icu-small/source/i18n/currunit.cpp b/deps/icu-small/source/i18n/currunit.cpp
index 6d8d1cd6c6..2ece508751 100644
--- a/deps/icu-small/source/i18n/currunit.cpp
+++ b/deps/icu-small/source/i18n/currunit.cpp
@@ -27,9 +27,14 @@ CurrencyUnit::CurrencyUnit(ConstChar16Ptr _isoCode, UErrorCode& ec) {
// The constructor always leaves the CurrencyUnit in a valid state (with a 3-character currency code).
// Note: in ICU4J Currency.getInstance(), we check string length for 3, but in ICU4C we allow a
// non-NUL-terminated string to be passed as an argument, so it is not possible to check length.
+ // However, we allow a NUL-terminated empty string, which should have the same behavior as nullptr.
+ // Consider NUL-terminated strings of length 1 or 2 as invalid.
const char16_t* isoCodeToUse;
- if (U_FAILURE(ec) || _isoCode == nullptr) {
+ if (U_FAILURE(ec) || _isoCode == nullptr || _isoCode[0] == 0) {
isoCodeToUse = kDefaultCurrency;
+ } else if (_isoCode[1] == 0 || _isoCode[2] == 0) {
+ isoCodeToUse = kDefaultCurrency;
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
} else if (!uprv_isInvariantUString(_isoCode, 3)) {
// TODO: Perform a more strict ASCII check like in ICU4J isAlpha3Code?
isoCodeToUse = kDefaultCurrency;
diff --git a/deps/icu-small/source/i18n/dcfmtsym.cpp b/deps/icu-small/source/i18n/dcfmtsym.cpp
index 5a432aec8e..04113785f2 100644
--- a/deps/icu-small/source/i18n/dcfmtsym.cpp
+++ b/deps/icu-small/source/i18n/dcfmtsym.cpp
@@ -436,7 +436,7 @@ DecimalFormatSymbols::initialize(const Locale& loc, UErrorCode& status,
sink.resolveMissingMonetarySeparators(fSymbols);
// Resolve codePointZero
- UChar32 tempCodePointZero;
+ UChar32 tempCodePointZero = -1;
for (int32_t i=0; i<=9; i++) {
const UnicodeString& stringDigit = getConstDigitSymbol(i);
if (stringDigit.countChar32() != 1) {
diff --git a/deps/icu-small/source/i18n/decimfmt.cpp b/deps/icu-small/source/i18n/decimfmt.cpp
index a2638bb742..edd8910d9d 100644
--- a/deps/icu-small/source/i18n/decimfmt.cpp
+++ b/deps/icu-small/source/i18n/decimfmt.cpp
@@ -1057,12 +1057,19 @@ UBool DecimalFormat::areSignificantDigitsUsed() const {
void DecimalFormat::setSignificantDigitsUsed(UBool useSignificantDigits) {
// These are the default values from the old implementation.
+ if (useSignificantDigits) {
+ if (fields->properties->minimumSignificantDigits != -1 ||
+ fields->properties->maximumSignificantDigits != -1) {
+ return;
+ }
+ } else {
+ if (fields->properties->minimumSignificantDigits == -1 &&
+ fields->properties->maximumSignificantDigits == -1) {
+ return;
+ }
+ }
int32_t minSig = useSignificantDigits ? 1 : -1;
int32_t maxSig = useSignificantDigits ? 6 : -1;
- if (fields->properties->minimumSignificantDigits == minSig &&
- fields->properties->maximumSignificantDigits == maxSig) {
- return;
- }
fields->properties->minimumSignificantDigits = minSig;
fields->properties->maximumSignificantDigits = maxSig;
touchNoError();
@@ -1175,7 +1182,12 @@ void DecimalFormat::setPropertiesFromPattern(const UnicodeString& pattern, int32
}
const numparse::impl::NumberParserImpl* DecimalFormat::getParser(UErrorCode& status) const {
- if (U_FAILURE(status)) { return nullptr; }
+ // TODO: Move this into umutex.h? (similar logic also in numrange_fluent.cpp)
+ // See ICU-20146
+
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
// First try to get the pre-computed parser
auto* ptr = fields->atomicParser.load();
@@ -1185,13 +1197,17 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getParser(UErrorCode& sta
// Try computing the parser on our own
auto* temp = NumberParserImpl::createParserFromProperties(*fields->properties, *fields->symbols, false, status);
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
if (temp == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
- // although we may still dereference, call sites should be guarded
+ return nullptr;
}
- // Note: ptr starts as nullptr; during compare_exchange, it is set to what is actually stored in the
- // atomic if another thread beat us to computing the parser object.
+ // Note: ptr starts as nullptr; during compare_exchange,
+ // it is set to what is actually stored in the atomic
+ // if another thread beat us to computing the parser object.
auto* nonConstThis = const_cast<DecimalFormat*>(this);
if (!nonConstThis->fields->atomicParser.compare_exchange_strong(ptr, temp)) {
// Another thread beat us to computing the parser
diff --git a/deps/icu-small/source/i18n/dtfmtsym.cpp b/deps/icu-small/source/i18n/dtfmtsym.cpp
index af421d41c7..c9dfa04583 100644
--- a/deps/icu-small/source/i18n/dtfmtsym.cpp
+++ b/deps/icu-small/source/i18n/dtfmtsym.cpp
@@ -1311,7 +1311,7 @@ DateFormatSymbols::initZoneStringsArray(void) {
UDate now = Calendar::getNow();
UnicodeString tzDispName;
- while ((tzid = tzids->snext(status))) {
+ while ((tzid = tzids->snext(status)) != 0) {
if (U_FAILURE(status)) {
break;
}
@@ -2224,8 +2224,8 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError
++typeMapPtr;
}
if (typeMapPtr->usageTypeName != NULL && compResult == 0) {
- fCapitalization[typeMapPtr->usageTypeEnumValue][0] = intVector[0];
- fCapitalization[typeMapPtr->usageTypeEnumValue][1] = intVector[1];
+ fCapitalization[typeMapPtr->usageTypeEnumValue][0] = static_cast<UBool>(intVector[0]);
+ fCapitalization[typeMapPtr->usageTypeEnumValue][1] = static_cast<UBool>(intVector[1]);
}
}
}
diff --git a/deps/icu-small/source/i18n/dtitvfmt.cpp b/deps/icu-small/source/i18n/dtitvfmt.cpp
index 743b534fc8..d952cbf509 100644
--- a/deps/icu-small/source/i18n/dtitvfmt.cpp
+++ b/deps/icu-small/source/i18n/dtitvfmt.cpp
@@ -877,8 +877,7 @@ DateIntervalFormat::getDateTimeSkeleton(const UnicodeString& skeleton,
if ( MCount < 3 ) {
normalizedDateSkeleton.append(CAP_M);
} else {
- int32_t i;
- for ( i = 0; i < MCount && i < MAX_M_COUNT; ++i ) {
+ for ( int32_t j = 0; j < MCount && j < MAX_M_COUNT; ++j) {
normalizedDateSkeleton.append(CAP_M);
}
}
@@ -887,8 +886,7 @@ DateIntervalFormat::getDateTimeSkeleton(const UnicodeString& skeleton,
if ( ECount <= 3 ) {
normalizedDateSkeleton.append(CAP_E);
} else {
- int32_t i;
- for ( i = 0; i < ECount && i < MAX_E_COUNT; ++i ) {
+ for ( int32_t j = 0; j < ECount && j < MAX_E_COUNT; ++j ) {
normalizedDateSkeleton.append(CAP_E);
}
}
diff --git a/deps/icu-small/source/i18n/dtitvinf.cpp b/deps/icu-small/source/i18n/dtitvinf.cpp
index c863a683a5..a289fc79c8 100644
--- a/deps/icu-small/source/i18n/dtitvinf.cpp
+++ b/deps/icu-small/source/i18n/dtitvinf.cpp
@@ -594,7 +594,7 @@ DateIntervalInfo::getBestSkeleton(const UnicodeString& skeleton,
const UHashElement* elem = NULL;
while ( (elem = fIntervalPatterns->nextElement(pos)) != NULL ) {
const UHashTok keyTok = elem->key;
- UnicodeString* skeleton = (UnicodeString*)keyTok.pointer;
+ UnicodeString* newSkeleton = (UnicodeString*)keyTok.pointer;
#ifdef DTITVINF_DEBUG
skeleton->extract(0, skeleton->length(), result, "UTF-8");
sprintf(mesg, "available skeletons: skeleton: %s; \n", result);
@@ -606,7 +606,7 @@ DateIntervalInfo::getBestSkeleton(const UnicodeString& skeleton,
for ( i = 0; i < fieldLength; ++i ) {
skeletonFieldWidth[i] = 0;
}
- parseSkeleton(*skeleton, skeletonFieldWidth);
+ parseSkeleton(*newSkeleton, skeletonFieldWidth);
// calculate distance
int32_t distance = 0;
int8_t fieldDifference = 1;
@@ -632,7 +632,7 @@ DateIntervalInfo::getBestSkeleton(const UnicodeString& skeleton,
}
}
if ( distance < bestDistance ) {
- bestSkeleton = skeleton;
+ bestSkeleton = newSkeleton;
bestDistance = distance;
bestMatchDistanceInfo = fieldDifference;
}
diff --git a/deps/icu-small/source/i18n/dtptngen.cpp b/deps/icu-small/source/i18n/dtptngen.cpp
index aefd70464e..b44daf37bf 100644
--- a/deps/icu-small/source/i18n/dtptngen.cpp
+++ b/deps/icu-small/source/i18n/dtptngen.cpp
@@ -18,6 +18,7 @@
#include "unicode/decimfmt.h"
#include "unicode/dtfmtsym.h"
#include "unicode/dtptngen.h"
+#include "unicode/localpointer.h"
#include "unicode/simpleformatter.h"
#include "unicode/smpdtfmt.h"
#include "unicode/udat.h"
@@ -88,17 +89,17 @@ static void ures_a_open(UResourceBundleAIterator *aiter, UResourceBundle *bund,
aiter->num = ures_getSize(aiter->bund);
aiter->cursor = 0;
#if !defined(U_SORT_ASCII_BUNDLE_ITERATOR)
- aiter->entries = NULL;
+ aiter->entries = nullptr;
#else
aiter->entries = (UResAEntry*)uprv_malloc(sizeof(UResAEntry)*aiter->num);
for(int i=0;i<aiter->num;i++) {
- aiter->entries[i].item = ures_getByIndex(aiter->bund, i, NULL, status);
+ aiter->entries[i].item = ures_getByIndex(aiter->bund, i, nullptr, status);
const char *akey = ures_getKey(aiter->entries[i].item);
int32_t len = uprv_strlen(akey)+1;
aiter->entries[i].key = (UChar*)uprv_malloc(len*sizeof(UChar));
u_charsToUChars(akey, aiter->entries[i].key, len);
}
- uprv_sortArray(aiter->entries, aiter->num, sizeof(UResAEntry), ures_a_codepointSort, NULL, TRUE, status);
+ uprv_sortArray(aiter->entries, aiter->num, sizeof(UResAEntry), ures_a_codepointSort, nullptr, TRUE, status);
#endif
}
@@ -115,7 +116,7 @@ static const UChar *ures_a_getNextString(UResourceBundleAIterator *aiter, int32_
#if !defined(U_SORT_ASCII_BUNDLE_ITERATOR)
return ures_getNextString(aiter->bund, len, key, err);
#else
- if(U_FAILURE(*err)) return NULL;
+ if(U_FAILURE(*err)) return nullptr;
UResourceBundle *item = aiter->entries[aiter->cursor].item;
const UChar* ret = ures_getString(item, len, err);
*key = ures_getKey(item);
@@ -302,49 +303,48 @@ DateTimePatternGenerator::createInstance(UErrorCode& status) {
DateTimePatternGenerator* U_EXPORT2
DateTimePatternGenerator::createInstance(const Locale& locale, UErrorCode& status) {
if (U_FAILURE(status)) {
- return NULL;
+ return nullptr;
}
LocalPointer<DateTimePatternGenerator> result(
new DateTimePatternGenerator(locale, status), status);
- return U_SUCCESS(status) ? result.orphan() : NULL;
+ return U_SUCCESS(status) ? result.orphan() : nullptr;
}
DateTimePatternGenerator* U_EXPORT2
DateTimePatternGenerator::createEmptyInstance(UErrorCode& status) {
- DateTimePatternGenerator *result = new DateTimePatternGenerator(status);
- if (result == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
if (U_FAILURE(status)) {
- delete result;
- result = NULL;
+ return nullptr;
}
- return result;
+ LocalPointer<DateTimePatternGenerator> result(
+ new DateTimePatternGenerator(status), status);
+ return U_SUCCESS(status) ? result.orphan() : nullptr;
}
DateTimePatternGenerator::DateTimePatternGenerator(UErrorCode &status) :
- skipMatcher(NULL),
- fAvailableFormatKeyHash(NULL)
+ skipMatcher(nullptr),
+ fAvailableFormatKeyHash(nullptr),
+ internalErrorCode(U_ZERO_ERROR)
{
fp = new FormatParser();
dtMatcher = new DateTimeMatcher();
distanceInfo = new DistanceInfo();
patternMap = new PatternMap();
- if (fp == NULL || dtMatcher == NULL || distanceInfo == NULL || patternMap == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
+ if (fp == nullptr || dtMatcher == nullptr || distanceInfo == nullptr || patternMap == nullptr) {
+ internalErrorCode = status = U_MEMORY_ALLOCATION_ERROR;
}
}
DateTimePatternGenerator::DateTimePatternGenerator(const Locale& locale, UErrorCode &status) :
- skipMatcher(NULL),
- fAvailableFormatKeyHash(NULL)
+ skipMatcher(nullptr),
+ fAvailableFormatKeyHash(nullptr),
+ internalErrorCode(U_ZERO_ERROR)
{
fp = new FormatParser();
dtMatcher = new DateTimeMatcher();
distanceInfo = new DistanceInfo();
patternMap = new PatternMap();
- if (fp == NULL || dtMatcher == NULL || distanceInfo == NULL || patternMap == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
+ if (fp == nullptr || dtMatcher == nullptr || distanceInfo == nullptr || patternMap == nullptr) {
+ internalErrorCode = status = U_MEMORY_ALLOCATION_ERROR;
}
else {
initData(locale, status);
@@ -353,13 +353,17 @@ DateTimePatternGenerator::DateTimePatternGenerator(const Locale& locale, UErrorC
DateTimePatternGenerator::DateTimePatternGenerator(const DateTimePatternGenerator& other) :
UObject(),
- skipMatcher(NULL),
- fAvailableFormatKeyHash(NULL)
+ skipMatcher(nullptr),
+ fAvailableFormatKeyHash(nullptr),
+ internalErrorCode(U_ZERO_ERROR)
{
fp = new FormatParser();
dtMatcher = new DateTimeMatcher();
distanceInfo = new DistanceInfo();
patternMap = new PatternMap();
+ if (fp == nullptr || dtMatcher == nullptr || distanceInfo == nullptr || patternMap == nullptr) {
+ internalErrorCode = U_MEMORY_ALLOCATION_ERROR;
+ }
*this=other;
}
@@ -369,6 +373,7 @@ DateTimePatternGenerator::operator=(const DateTimePatternGenerator& other) {
if (&other == this) {
return *this;
}
+ internalErrorCode = other.internalErrorCode;
pLocale = other.pLocale;
fDefaultHourFormatChar = other.fDefaultHourFormatChar;
*fp = *(other.fp);
@@ -380,11 +385,16 @@ DateTimePatternGenerator::operator=(const DateTimePatternGenerator& other) {
dateTimeFormat.getTerminatedBuffer();
decimal.getTerminatedBuffer();
delete skipMatcher;
- if ( other.skipMatcher == NULL ) {
- skipMatcher = NULL;
+ if ( other.skipMatcher == nullptr ) {
+ skipMatcher = nullptr;
}
else {
skipMatcher = new DateTimeMatcher(*other.skipMatcher);
+ if (skipMatcher == nullptr)
+ {
+ internalErrorCode = U_MEMORY_ALLOCATION_ERROR;
+ return *this;
+ }
}
for (int32_t i=0; i< UDATPG_FIELD_COUNT; ++i ) {
appendItemFormats[i] = other.appendItemFormats[i];
@@ -394,9 +404,8 @@ DateTimePatternGenerator::operator=(const DateTimePatternGenerator& other) {
fieldDisplayNames[i][j].getTerminatedBuffer(); // NUL-terminate for the C API.
}
}
- UErrorCode status = U_ZERO_ERROR;
- patternMap->copyFrom(*other.patternMap, status);
- copyHashtable(other.fAvailableFormatKeyHash, status);
+ patternMap->copyFrom(*other.patternMap, internalErrorCode);
+ copyHashtable(other.fAvailableFormatKeyHash, internalErrorCode);
return *this;
}
@@ -431,21 +440,21 @@ DateTimePatternGenerator::operator!=(const DateTimePatternGenerator& other) cons
}
DateTimePatternGenerator::~DateTimePatternGenerator() {
- if (fAvailableFormatKeyHash!=NULL) {
+ if (fAvailableFormatKeyHash!=nullptr) {
delete fAvailableFormatKeyHash;
}
- if (fp != NULL) delete fp;
- if (dtMatcher != NULL) delete dtMatcher;
- if (distanceInfo != NULL) delete distanceInfo;
- if (patternMap != NULL) delete patternMap;
- if (skipMatcher != NULL) delete skipMatcher;
+ if (fp != nullptr) delete fp;
+ if (dtMatcher != nullptr) delete dtMatcher;
+ if (distanceInfo != nullptr) delete distanceInfo;
+ if (patternMap != nullptr) delete patternMap;
+ if (skipMatcher != nullptr) delete skipMatcher;
}
namespace {
UInitOnce initOnce = U_INITONCE_INITIALIZER;
-UHashtable *localeToAllowedHourFormatsMap = NULL;
+UHashtable *localeToAllowedHourFormatsMap = nullptr;
// Value deleter for hashmap.
U_CFUNC void U_CALLCONV deleteAllowedHourFormats(void *ptr) {
@@ -474,8 +483,8 @@ void
DateTimePatternGenerator::initData(const Locale& locale, UErrorCode &status) {
//const char *baseLangName = locale.getBaseName(); // unused
- skipMatcher = NULL;
- fAvailableFormatKeyHash=NULL;
+ skipMatcher = nullptr;
+ fAvailableFormatKeyHash=nullptr;
addCanonicalItems(status);
addICUPatterns(locale, status);
addCLDRData(locale, status);
@@ -483,6 +492,8 @@ DateTimePatternGenerator::initData(const Locale& locale, UErrorCode &status) {
setDecimalSymbols(locale, status);
umtx_initOnce(initOnce, loadAllowedHourFormatsData, status);
getAllowedHourFormats(locale, status);
+ // If any of the above methods failed then the object is in an invalid state.
+ internalErrorCode = status;
} // DateTimePatternGenerator::initData
namespace {
@@ -505,7 +516,7 @@ struct AllowedHourFormatsSink : public ResourceSink {
LocalMemory<int32_t> list;
int32_t length;
if (value.getType() == URES_STRING) {
- if (list.allocateInsteadAndReset(2) == NULL) {
+ if (list.allocateInsteadAndReset(2) == nullptr) {
errorCode = U_MEMORY_ALLOCATION_ERROR;
return;
}
@@ -515,7 +526,7 @@ struct AllowedHourFormatsSink : public ResourceSink {
else {
ResourceArray allowedFormats = value.getArray(errorCode);
length = allowedFormats.getSize();
- if (list.allocateInsteadAndReset(length + 1) == NULL) {
+ if (list.allocateInsteadAndReset(length + 1) == nullptr) {
errorCode = U_MEMORY_ALLOCATION_ERROR;
return;
}
@@ -555,9 +566,14 @@ AllowedHourFormatsSink::~AllowedHourFormatsSink() {}
U_CFUNC void U_CALLCONV DateTimePatternGenerator::loadAllowedHourFormatsData(UErrorCode &status) {
if (U_FAILURE(status)) { return; }
localeToAllowedHourFormatsMap = uhash_open(
- uhash_hashChars, uhash_compareChars, NULL, &status);
+ uhash_hashChars, uhash_compareChars, nullptr, &status);
+ if (U_FAILURE(status)) { return; }
+
uhash_setValueDeleter(localeToAllowedHourFormatsMap, deleteAllowedHourFormats);
- LocalUResourceBundlePointer rb(ures_openDirect(NULL, "supplementalData", &status));
+ ucln_i18n_registerCleanup(UCLN_I18N_ALLOWED_HOUR_FORMATS, allowedHourFormatsCleanup);
+
+ LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "supplementalData", &status));
+ if (U_FAILURE(status)) { return; }
AllowedHourFormatsSink sink;
// TODO: Currently in the enumeration each table allocates a new array.
@@ -567,8 +583,6 @@ U_CFUNC void U_CALLCONV DateTimePatternGenerator::loadAllowedHourFormatsData(UEr
// vector (at index enum*2) for easy data sharing, copy sub-arrays into runtime
// object. Remember to clean up the vector, too.
ures_getAllItemsWithFallback(rb.getAlias(), "timeData", sink, status);
-
- ucln_i18n_registerCleanup(UCLN_I18N_ALLOWED_HOUR_FORMATS, allowedHourFormatsCleanup);
}
void DateTimePatternGenerator::getAllowedHourFormats(const Locale &locale, UErrorCode &status) {
@@ -589,17 +603,17 @@ void DateTimePatternGenerator::getAllowedHourFormats(const Locale &locale, UErro
const char *language = maxLocale.getLanguage();
CharString langCountry;
- langCountry.append(language, uprv_strlen(language), status);
+ langCountry.append(language, static_cast<int32_t>(uprv_strlen(language)), status);
langCountry.append('_', status);
- langCountry.append(country, uprv_strlen(country), status);
+ langCountry.append(country, static_cast<int32_t>(uprv_strlen(country)), status);
int32_t *allowedFormats;
allowedFormats = (int32_t *)uhash_get(localeToAllowedHourFormatsMap, langCountry.data());
- if (allowedFormats == NULL) {
+ if (allowedFormats == nullptr) {
allowedFormats = (int32_t *)uhash_get(localeToAllowedHourFormatsMap, const_cast<char *>(country));
}
- if (allowedFormats != NULL) { // Lookup is successful
+ if (allowedFormats != nullptr) { // Lookup is successful
for (int32_t i = 0; i < UPRV_LENGTHOF(fAllowedHourFormats); ++i) {
fAllowedHourFormats[i] = allowedFormats[i];
if (allowedFormats[i] == ALLOWED_HOUR_FORMAT_UNKNOWN) {
@@ -615,10 +629,10 @@ void DateTimePatternGenerator::getAllowedHourFormats(const Locale &locale, UErro
UnicodeString
DateTimePatternGenerator::getSkeleton(const UnicodeString& pattern, UErrorCode&
/*status*/) {
- FormatParser fp;
+ FormatParser fp2;
DateTimeMatcher matcher;
PtnSkeleton localSkeleton;
- matcher.set(pattern, &fp, localSkeleton);
+ matcher.set(pattern, &fp2, localSkeleton);
return localSkeleton.getSkeleton();
}
@@ -634,10 +648,10 @@ DateTimePatternGenerator::staticGetSkeleton(
UnicodeString
DateTimePatternGenerator::getBaseSkeleton(const UnicodeString& pattern, UErrorCode& /*status*/) {
- FormatParser fp;
+ FormatParser fp2;
DateTimeMatcher matcher;
PtnSkeleton localSkeleton;
- matcher.set(pattern, &fp, localSkeleton);
+ matcher.set(pattern, &fp2, localSkeleton);
return localSkeleton.getBaseSkeleton();
}
@@ -663,7 +677,7 @@ DateTimePatternGenerator::addICUPatterns(const Locale& locale, UErrorCode& statu
DateFormat::EStyle style = (DateFormat::EStyle)i;
df = DateFormat::createDateInstance(style, locale);
SimpleDateFormat* sdf;
- if (df != NULL && (sdf = dynamic_cast<SimpleDateFormat*>(df)) != NULL) {
+ if (df != nullptr && (sdf = dynamic_cast<SimpleDateFormat*>(df)) != nullptr) {
sdf->toPattern(dfPattern);
addPattern(dfPattern, FALSE, conflictingString, status);
}
@@ -672,7 +686,7 @@ DateTimePatternGenerator::addICUPatterns(const Locale& locale, UErrorCode& statu
if (U_FAILURE(status)) { return; }
df = DateFormat::createTimeInstance(style, locale);
- if (df != NULL && (sdf = dynamic_cast<SimpleDateFormat*>(df)) != NULL) {
+ if (df != nullptr && (sdf = dynamic_cast<SimpleDateFormat*>(df)) != nullptr) {
sdf->toPattern(dfPattern);
addPattern(dfPattern, FALSE, conflictingString, status);
@@ -747,13 +761,14 @@ DateTimePatternGenerator::getCalendarTypeToUse(const Locale& locale, CharString&
ures_getFunctionalEquivalent(
localeWithCalendarKey,
ULOC_LOCALE_IDENTIFIER_CAPACITY,
- NULL,
+ nullptr,
"calendar",
"calendar",
locale.getName(),
- NULL,
+ nullptr,
FALSE,
&err);
+ if (U_FAILURE(err)) { return; }
localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY-1] = 0; // ensure null termination
// now get the calendar key value from that locale
char calendarType[ULOC_KEYWORDS_CAPACITY];
@@ -763,7 +778,8 @@ DateTimePatternGenerator::getCalendarTypeToUse(const Locale& locale, CharString&
calendarType,
ULOC_KEYWORDS_CAPACITY,
&err);
- if (U_SUCCESS(err) && calendarTypeLen < ULOC_KEYWORDS_CAPACITY) {
+ if (U_FAILURE(err)) { return; }
+ if (calendarTypeLen < ULOC_KEYWORDS_CAPACITY) {
destination.clear().append(calendarType, -1, err);
if (U_FAILURE(err)) { return; }
}
@@ -774,7 +790,7 @@ DateTimePatternGenerator::getCalendarTypeToUse(const Locale& locale, CharString&
void
DateTimePatternGenerator::consumeShortTimePattern(const UnicodeString& shortTimePattern,
UErrorCode& status) {
-
+ if (U_FAILURE(status)) { return; }
// set fDefaultHourFormatChar to the hour format character from this pattern
int32_t tfIdx, tfLen = shortTimePattern.length();
UBool ignoreChars = FALSE;
@@ -782,7 +798,7 @@ DateTimePatternGenerator::consumeShortTimePattern(const UnicodeString& shortTime
UChar tfChar = shortTimePattern.charAt(tfIdx);
if ( tfChar == SINGLE_QUOTE ) {
ignoreChars = !ignoreChars; // toggle (handle quoted literals & '' for single quote)
- } else if ( !ignoreChars && u_strchr(hourFormatChars, tfChar) != NULL ) {
+ } else if ( !ignoreChars && u_strchr(hourFormatChars, tfChar) != nullptr ) {
fDefaultHourFormatChar = tfChar;
break;
}
@@ -872,9 +888,9 @@ struct DateTimePatternGenerator::AppendItemNamesSink : public ResourceSink {
valueStr.getTerminatedBuffer();
}
for (int32_t j = 1; j < UDATPG_WIDTH_COUNT; j++) {
- UnicodeString& valueStr = dtpg.getMutableFieldDisplayName((UDateTimePatternField)i, (UDateTimePGDisplayWidth)j);
- if (valueStr.isEmpty()) {
- valueStr = dtpg.getFieldDisplayName((UDateTimePatternField)i, (UDateTimePGDisplayWidth)(j-1));
+ UnicodeString& valueStr2 = dtpg.getMutableFieldDisplayName((UDateTimePatternField)i, (UDateTimePGDisplayWidth)j);
+ if (valueStr2.isEmpty()) {
+ valueStr2 = dtpg.getFieldDisplayName((UDateTimePatternField)i, (UDateTimePGDisplayWidth)(j-1));
}
}
}
@@ -921,7 +937,7 @@ DateTimePatternGenerator::addCLDRData(const Locale& locale, UErrorCode& errorCod
UnicodeString rbPattern, value, field;
CharString path;
- LocalUResourceBundlePointer rb(ures_open(NULL, locale.getName(), &errorCode));
+ LocalUResourceBundlePointer rb(ures_open(nullptr, locale.getName(), &errorCode));
if (U_FAILURE(errorCode)) { return; }
CharString calendarTypeToUse; // to be filled in with the type to use, if all goes well
@@ -966,12 +982,13 @@ DateTimePatternGenerator::addCLDRData(const Locale& locale, UErrorCode& errorCod
void
DateTimePatternGenerator::initHashtable(UErrorCode& err) {
- if (fAvailableFormatKeyHash!=NULL) {
+ if (U_FAILURE(err)) { return; }
+ if (fAvailableFormatKeyHash!=nullptr) {
return;
}
- if ((fAvailableFormatKeyHash = new Hashtable(FALSE, err))==NULL) {
- err=U_MEMORY_ALLOCATION_ERROR;
- return;
+ LocalPointer<Hashtable> hash(new Hashtable(FALSE, err), err);
+ if (U_SUCCESS(err)) {
+ fAvailableFormatKeyHash = hash.orphan();
}
}
@@ -1028,7 +1045,14 @@ DateTimePatternGenerator::getBestPattern(const UnicodeString& patternForm, UErro
UnicodeString
DateTimePatternGenerator::getBestPattern(const UnicodeString& patternForm, UDateTimePatternMatchOptions options, UErrorCode& status) {
- const UnicodeString *bestPattern=NULL;
+ if (U_FAILURE(status)) {
+ return UnicodeString();
+ }
+ if (U_FAILURE(internalErrorCode)) {
+ status = internalErrorCode;
+ return UnicodeString();
+ }
+ const UnicodeString *bestPattern = nullptr;
UnicodeString dtFormat;
UnicodeString resultPattern;
int32_t flags = kDTPGNoFlags;
@@ -1044,16 +1068,23 @@ DateTimePatternGenerator::getBestPattern(const UnicodeString& patternForm, UDate
resultPattern.remove();
dtMatcher->set(patternFormMapped, fp);
- const PtnSkeleton* specifiedSkeleton=NULL;
- bestPattern=getBestRaw(*dtMatcher, -1, distanceInfo, &specifiedSkeleton);
+ const PtnSkeleton* specifiedSkeleton = nullptr;
+ bestPattern=getBestRaw(*dtMatcher, -1, distanceInfo, status, &specifiedSkeleton);
+ if (U_FAILURE(status)) {
+ return UnicodeString();
+ }
+
if ( distanceInfo->missingFieldMask==0 && distanceInfo->extraFieldMask==0 ) {
resultPattern = adjustFieldTypes(*bestPattern, specifiedSkeleton, flags, options);
return resultPattern;
}
int32_t neededFields = dtMatcher->getFieldMask();
- UnicodeString datePattern=getBestAppending(neededFields & dateMask, flags, options);
- UnicodeString timePattern=getBestAppending(neededFields & timeMask, flags, options);
+ UnicodeString datePattern=getBestAppending(neededFields & dateMask, flags, status, options);
+ UnicodeString timePattern=getBestAppending(neededFields & timeMask, flags, status, options);
+ if (U_FAILURE(status)) {
+ return UnicodeString();
+ }
if (datePattern.length()==0) {
if (timePattern.length()==0) {
resultPattern.remove();
@@ -1074,7 +1105,7 @@ DateTimePatternGenerator::getBestPattern(const UnicodeString& patternForm, UDate
/*
* Map a skeleton that may have metacharacters jJC to one without, by replacing
- * the metacharacters with locale-appropriate fields of of h/H/k/K and of a/b/B
+ * the metacharacters with locale-appropriate fields of h/H/k/K and of a/b/B
* (depends on fDefaultHourFormatChar and fAllowedHourFormats being set, which in
* turn depends on initData having been run). This method also updates the flags
* as necessary. Returns the updated skeleton.
@@ -1159,9 +1190,16 @@ UnicodeString
DateTimePatternGenerator::replaceFieldTypes(const UnicodeString& pattern,
const UnicodeString& skeleton,
UDateTimePatternMatchOptions options,
- UErrorCode& /*status*/) {
+ UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return UnicodeString();
+ }
+ if (U_FAILURE(internalErrorCode)) {
+ status = internalErrorCode;
+ return UnicodeString();
+ }
dtMatcher->set(skeleton, fp);
- UnicodeString result = adjustFieldTypes(pattern, NULL, kDTPGNoFlags, options);
+ UnicodeString result = adjustFieldTypes(pattern, nullptr, kDTPGNoFlags, options);
return result;
}
@@ -1204,20 +1242,24 @@ DateTimePatternGenerator::getDateTimeFormat() const {
void
DateTimePatternGenerator::setDateTimeFromCalendar(const Locale& locale, UErrorCode& status) {
+ if (U_FAILURE(status)) { return; }
+
const UChar *resStr;
int32_t resStrLen = 0;
- Calendar* fCalendar = Calendar::createInstance(locale, status);
+ LocalPointer<Calendar> fCalendar(Calendar::createInstance(locale, status), status);
if (U_FAILURE(status)) { return; }
- LocalUResourceBundlePointer calData(ures_open(NULL, locale.getBaseName(), &status));
+ LocalUResourceBundlePointer calData(ures_open(nullptr, locale.getBaseName(), &status));
+ if (U_FAILURE(status)) { return; }
ures_getByKey(calData.getAlias(), DT_DateTimeCalendarTag, calData.getAlias(), &status);
+ if (U_FAILURE(status)) { return; }
LocalUResourceBundlePointer dateTimePatterns;
- if (fCalendar != NULL && fCalendar->getType() != NULL && *fCalendar->getType() != '\0'
+ if (fCalendar->getType() != nullptr && *fCalendar->getType() != '\0'
&& uprv_strcmp(fCalendar->getType(), DT_DateTimeGregorianTag) != 0) {
dateTimePatterns.adoptInstead(ures_getByKeyWithFallback(calData.getAlias(), fCalendar->getType(),
- NULL, &status));
+ nullptr, &status));
ures_getByKeyWithFallback(dateTimePatterns.getAlias(), DT_DateTimePatternsTag,
dateTimePatterns.getAlias(), &status);
}
@@ -1238,8 +1280,6 @@ DateTimePatternGenerator::setDateTimeFromCalendar(const Locale& locale, UErrorCo
}
resStr = ures_getStringByIndex(dateTimePatterns.getAlias(), (int32_t)DateFormat::kDateTime, &resStrLen, &status);
setDateTimeFormat(UnicodeString(TRUE, resStr, resStrLen));
-
- delete fCalendar;
}
void
@@ -1259,7 +1299,12 @@ DateTimePatternGenerator::addPattern(
UnicodeString &conflictingPattern,
UErrorCode& status)
{
- return addPatternWithSkeleton(pattern, NULL, override, conflictingPattern, status);
+ if (U_FAILURE(internalErrorCode)) {
+ status = internalErrorCode;
+ return UDATPG_NO_CONFLICT;
+ }
+
+ return addPatternWithSkeleton(pattern, nullptr, override, conflictingPattern, status);
}
// For DateTimePatternGenerator::addPatternWithSkeleton -
@@ -1280,13 +1325,17 @@ DateTimePatternGenerator::addPatternWithSkeleton(
UnicodeString& conflictingPattern,
UErrorCode& status)
{
+ if (U_FAILURE(internalErrorCode)) {
+ status = internalErrorCode;
+ return UDATPG_NO_CONFLICT;
+ }
UnicodeString basePattern;
PtnSkeleton skeleton;
UDateTimePatternConflict conflictingStatus = UDATPG_NO_CONFLICT;
DateTimeMatcher matcher;
- if ( skeletonToUse == NULL ) {
+ if ( skeletonToUse == nullptr ) {
matcher.set(pattern, fp, skeleton);
matcher.getBasePattern(basePattern);
} else {
@@ -1302,7 +1351,7 @@ DateTimePatternGenerator::addPatternWithSkeleton(
// availableFormats items from root, which should not override any previous entry with the same base.
UBool entryHadSpecifiedSkeleton;
const UnicodeString *duplicatePattern = patternMap->getPatternFromBasePattern(basePattern, entryHadSpecifiedSkeleton);
- if (duplicatePattern != NULL && (!entryHadSpecifiedSkeleton || (skeletonToUse != NULL && !override))) {
+ if (duplicatePattern != nullptr && (!entryHadSpecifiedSkeleton || (skeletonToUse != nullptr && !override))) {
conflictingStatus = UDATPG_BASE_CONFLICT;
conflictingPattern = *duplicatePattern;
if (!override) {
@@ -1313,16 +1362,16 @@ DateTimePatternGenerator::addPatternWithSkeleton(
// items from CLDR data. In that case, we don't want an item from a parent locale to replace an item with
// same skeleton from the specified locale, so skip the current item if skeletonWasSpecified is true for
// the previously-specified conflicting item.
- const PtnSkeleton* entrySpecifiedSkeleton = NULL;
+ const PtnSkeleton* entrySpecifiedSkeleton = nullptr;
duplicatePattern = patternMap->getPatternFromSkeleton(skeleton, &entrySpecifiedSkeleton);
- if (duplicatePattern != NULL ) {
+ if (duplicatePattern != nullptr ) {
conflictingStatus = UDATPG_CONFLICT;
conflictingPattern = *duplicatePattern;
- if (!override || (skeletonToUse != NULL && entrySpecifiedSkeleton != NULL)) {
+ if (!override || (skeletonToUse != nullptr && entrySpecifiedSkeleton != nullptr)) {
return conflictingStatus;
}
}
- patternMap->add(basePattern, skeleton, pattern, skeletonToUse != NULL, status);
+ patternMap->add(basePattern, skeleton, pattern, skeletonToUse != nullptr, status);
if(U_FAILURE(status)) {
return conflictingStatus;
}
@@ -1369,13 +1418,16 @@ const UnicodeString*
DateTimePatternGenerator::getBestRaw(DateTimeMatcher& source,
int32_t includeMask,
DistanceInfo* missingFields,
+ UErrorCode &status,
const PtnSkeleton** specifiedSkeletonPtr) {
int32_t bestDistance = 0x7fffffff;
DistanceInfo tempInfo;
- const UnicodeString *bestPattern=NULL;
- const PtnSkeleton* specifiedSkeleton=NULL;
+ const UnicodeString *bestPattern=nullptr;
+ const PtnSkeleton* specifiedSkeleton=nullptr;
+
+ PatternMapIterator it(status);
+ if (U_FAILURE(status)) { return nullptr; }
- PatternMapIterator it;
for (it.set(*patternMap); it.hasNext(); ) {
DateTimeMatcher trial = it.next();
if (trial.equals(skipMatcher)) {
@@ -1485,8 +1537,8 @@ DateTimePatternGenerator::adjustFieldTypes(const UnicodeString& pattern,
c = fDefaultHourFormatChar;
}
field.remove();
- for (int32_t i=adjFieldLen; i>0; --i) {
- field+=c;
+ for (int32_t j=adjFieldLen; j>0; --j) {
+ field += c;
}
}
newPattern+=field;
@@ -1496,14 +1548,21 @@ DateTimePatternGenerator::adjustFieldTypes(const UnicodeString& pattern,
}
UnicodeString
-DateTimePatternGenerator::getBestAppending(int32_t missingFields, int32_t flags, UDateTimePatternMatchOptions options) {
+DateTimePatternGenerator::getBestAppending(int32_t missingFields, int32_t flags, UErrorCode &status, UDateTimePatternMatchOptions options) {
+ if (U_FAILURE(status)) {
+ return UnicodeString();
+ }
UnicodeString resultPattern, tempPattern;
- UErrorCode err=U_ZERO_ERROR;
+ const UnicodeString* tempPatternPtr;
int32_t lastMissingFieldMask=0;
if (missingFields!=0) {
resultPattern=UnicodeString();
- const PtnSkeleton* specifiedSkeleton=NULL;
- tempPattern = *getBestRaw(*dtMatcher, missingFields, distanceInfo, &specifiedSkeleton);
+ const PtnSkeleton* specifiedSkeleton=nullptr;
+ tempPatternPtr = getBestRaw(*dtMatcher, missingFields, distanceInfo, status, &specifiedSkeleton);
+ if (U_FAILURE(status)) {
+ return UnicodeString();
+ }
+ tempPattern = *tempPatternPtr;
resultPattern = adjustFieldTypes(tempPattern, specifiedSkeleton, flags, options);
if ( distanceInfo->missingFieldMask==0 ) {
return resultPattern;
@@ -1519,19 +1578,26 @@ DateTimePatternGenerator::getBestAppending(int32_t missingFields, int32_t flags,
continue;
}
int32_t startingMask = distanceInfo->missingFieldMask;
- tempPattern = *getBestRaw(*dtMatcher, distanceInfo->missingFieldMask, distanceInfo, &specifiedSkeleton);
+ tempPatternPtr = getBestRaw(*dtMatcher, distanceInfo->missingFieldMask, distanceInfo, status, &specifiedSkeleton);
+ if (U_FAILURE(status)) {
+ return UnicodeString();
+ }
+ tempPattern = *tempPatternPtr;
tempPattern = adjustFieldTypes(tempPattern, specifiedSkeleton, flags, options);
int32_t foundMask=startingMask& ~distanceInfo->missingFieldMask;
int32_t topField=getTopBitNumber(foundMask);
- UnicodeString appendName;
- getAppendName((UDateTimePatternField)topField, appendName);
- const UnicodeString *values[3] = {
- &resultPattern,
- &tempPattern,
- &appendName
- };
- SimpleFormatter(appendItemFormats[topField], 2, 3, err).
- formatAndReplace(values, 3, resultPattern, NULL, 0, err);
+
+ if (appendItemFormats[topField].length() != 0) {
+ UnicodeString appendName;
+ getAppendName((UDateTimePatternField)topField, appendName);
+ const UnicodeString *values[3] = {
+ &resultPattern,
+ &tempPattern,
+ &appendName
+ };
+ SimpleFormatter(appendItemFormats[topField], 2, 3, status).
+ formatAndReplace(values, 3, resultPattern, nullptr, 0, status);
+ }
lastMissingFieldMask = distanceInfo->missingFieldMask;
}
}
@@ -1539,7 +1605,7 @@ DateTimePatternGenerator::getBestAppending(int32_t missingFields, int32_t flags,
}
int32_t
-DateTimePatternGenerator::getTopBitNumber(int32_t foundMask) {
+DateTimePatternGenerator::getTopBitNumber(int32_t foundMask) const {
if ( foundMask==0 ) {
return 0;
}
@@ -1568,22 +1634,21 @@ DateTimePatternGenerator::isAvailableFormatSet(const UnicodeString &key) const {
void
DateTimePatternGenerator::copyHashtable(Hashtable *other, UErrorCode &status) {
-
- if (other == NULL) {
+ if (other == nullptr || U_FAILURE(status)) {
return;
}
- if (fAvailableFormatKeyHash != NULL) {
+ if (fAvailableFormatKeyHash != nullptr) {
delete fAvailableFormatKeyHash;
- fAvailableFormatKeyHash = NULL;
+ fAvailableFormatKeyHash = nullptr;
}
initHashtable(status);
if(U_FAILURE(status)){
return;
}
int32_t pos = UHASH_FIRST;
- const UHashElement* elem = NULL;
+ const UHashElement* elem = nullptr;
// walk through the hash table and create a deep clone
- while((elem = other->nextElement(pos))!= NULL){
+ while((elem = other->nextElement(pos))!= nullptr){
const UHashTok otherKeyTok = elem->key;
UnicodeString* otherKey = (UnicodeString*)otherKeyTok.pointer;
fAvailableFormatKeyHash->puti(*otherKey, 1, status);
@@ -1595,8 +1660,17 @@ DateTimePatternGenerator::copyHashtable(Hashtable *other, UErrorCode &status) {
StringEnumeration*
DateTimePatternGenerator::getSkeletons(UErrorCode& status) const {
- StringEnumeration* skeletonEnumerator = new DTSkeletonEnumeration(*patternMap, DT_SKELETON, status);
- return skeletonEnumerator;
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+ if (U_FAILURE(internalErrorCode)) {
+ status = internalErrorCode;
+ return nullptr;
+ }
+ LocalPointer<StringEnumeration> skeletonEnumerator(
+ new DTSkeletonEnumeration(*patternMap, DT_SKELETON, status), status);
+
+ return U_SUCCESS(status) ? skeletonEnumerator.orphan() : nullptr;
}
const UnicodeString&
@@ -1607,47 +1681,70 @@ DateTimePatternGenerator::getPatternForSkeleton(const UnicodeString& skeleton) c
return emptyString;
}
curElem = patternMap->getHeader(skeleton.charAt(0));
- while ( curElem != NULL ) {
+ while ( curElem != nullptr ) {
if ( curElem->skeleton->getSkeleton()==skeleton ) {
return curElem->pattern;
}
- curElem=curElem->next;
+ curElem = curElem->next.getAlias();
}
return emptyString;
}
StringEnumeration*
DateTimePatternGenerator::getBaseSkeletons(UErrorCode& status) const {
- StringEnumeration* baseSkeletonEnumerator = new DTSkeletonEnumeration(*patternMap, DT_BASESKELETON, status);
- return baseSkeletonEnumerator;
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+ if (U_FAILURE(internalErrorCode)) {
+ status = internalErrorCode;
+ return nullptr;
+ }
+ LocalPointer<StringEnumeration> baseSkeletonEnumerator(
+ new DTSkeletonEnumeration(*patternMap, DT_BASESKELETON, status), status);
+
+ return U_SUCCESS(status) ? baseSkeletonEnumerator.orphan() : nullptr;
}
StringEnumeration*
DateTimePatternGenerator::getRedundants(UErrorCode& status) {
- StringEnumeration* output = new DTRedundantEnumeration();
+ if (U_FAILURE(status)) { return nullptr; }
+ if (U_FAILURE(internalErrorCode)) {
+ status = internalErrorCode;
+ return nullptr;
+ }
+ LocalPointer<StringEnumeration> output(new DTRedundantEnumeration(), status);
+ if (U_FAILURE(status)) { return nullptr; }
const UnicodeString *pattern;
- PatternMapIterator it;
+ PatternMapIterator it(status);
+ if (U_FAILURE(status)) { return nullptr; }
+
for (it.set(*patternMap); it.hasNext(); ) {
DateTimeMatcher current = it.next();
pattern = patternMap->getPatternFromSkeleton(*(it.getSkeleton()));
if ( isCanonicalItem(*pattern) ) {
continue;
}
- if ( skipMatcher == NULL ) {
+ if ( skipMatcher == nullptr ) {
skipMatcher = new DateTimeMatcher(current);
+ if (skipMatcher == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
}
else {
*skipMatcher = current;
}
UnicodeString trial = getBestPattern(current.getPattern(), status);
+ if (U_FAILURE(status)) { return nullptr; }
if (trial == *pattern) {
- ((DTRedundantEnumeration *)output)->add(*pattern, status);
+ ((DTRedundantEnumeration *)output.getAlias())->add(*pattern, status);
+ if (U_FAILURE(status)) { return nullptr; }
}
if (current.equals(skipMatcher)) {
continue;
}
}
- return output;
+ return output.orphan();
}
UBool
@@ -1671,45 +1768,54 @@ DateTimePatternGenerator::clone() const {
PatternMap::PatternMap() {
for (int32_t i=0; i < MAX_PATTERN_ENTRIES; ++i ) {
- boot[i]=NULL;
+ boot[i] = nullptr;
}
isDupAllowed = TRUE;
}
void
PatternMap::copyFrom(const PatternMap& other, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
this->isDupAllowed = other.isDupAllowed;
- for (int32_t bootIndex=0; bootIndex<MAX_PATTERN_ENTRIES; ++bootIndex ) {
- PtnElem *curElem, *otherElem, *prevElem=NULL;
+ for (int32_t bootIndex = 0; bootIndex < MAX_PATTERN_ENTRIES; ++bootIndex) {
+ PtnElem *curElem, *otherElem, *prevElem=nullptr;
otherElem = other.boot[bootIndex];
- while (otherElem!=NULL) {
- if ((curElem = new PtnElem(otherElem->basePattern, otherElem->pattern))==NULL) {
- // out of memory
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
+ while (otherElem != nullptr) {
+ LocalPointer<PtnElem> newElem(new PtnElem(otherElem->basePattern, otherElem->pattern), status);
+ if (U_FAILURE(status)) {
+ return; // out of memory
}
- if ( this->boot[bootIndex]== NULL ) {
- this->boot[bootIndex] = curElem;
+ newElem->skeleton.adoptInsteadAndCheckErrorCode(new PtnSkeleton(*(otherElem->skeleton)), status);
+ if (U_FAILURE(status)) {
+ return; // out of memory
}
- if ((curElem->skeleton=new PtnSkeleton(*(otherElem->skeleton))) == NULL ) {
- // out of memory
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- curElem->skeletonWasSpecified = otherElem->skeletonWasSpecified;
- if (prevElem!=NULL) {
- prevElem->next=curElem;
+ newElem->skeletonWasSpecified = otherElem->skeletonWasSpecified;
+
+ // Release ownership from the LocalPointer of the PtnElem object.
+ // The PtnElem will now be owned by either the boot (for the first entry in the linked-list)
+ // or owned by the previous PtnElem object in the linked-list.
+ curElem = newElem.orphan();
+
+ if (this->boot[bootIndex] == nullptr) {
+ this->boot[bootIndex] = curElem;
+ } else {
+ if (prevElem != nullptr) {
+ prevElem->next.adoptInstead(curElem);
+ } else {
+ U_ASSERT(false);
+ }
}
- curElem->next=NULL;
prevElem = curElem;
- otherElem = otherElem->next;
+ otherElem = otherElem->next.getAlias();
}
}
}
PtnElem*
-PatternMap::getHeader(UChar baseChar) {
+PatternMap::getHeader(UChar baseChar) const {
PtnElem* curElem;
if ( (baseChar >= CAP_A) && (baseChar <= CAP_Z) ) {
@@ -1720,7 +1826,7 @@ PatternMap::getHeader(UChar baseChar) {
curElem = boot[26+baseChar-LOW_A];
}
else {
- return NULL;
+ return nullptr;
}
}
return curElem;
@@ -1728,9 +1834,9 @@ PatternMap::getHeader(UChar baseChar) {
PatternMap::~PatternMap() {
for (int32_t i=0; i < MAX_PATTERN_ENTRIES; ++i ) {
- if (boot[i]!=NULL ) {
+ if (boot[i] != nullptr ) {
delete boot[i];
- boot[i]=NULL;
+ boot[i] = nullptr;
}
}
} // PatternMap destructor
@@ -1759,39 +1865,45 @@ PatternMap::add(const UnicodeString& basePattern,
}
}
- if (baseElem == NULL) {
- if ((curElem = new PtnElem(basePattern, value)) == NULL ) {
- // out of memory
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
+ if (baseElem == nullptr) {
+ LocalPointer<PtnElem> newElem(new PtnElem(basePattern, value), status);
+ if (U_FAILURE(status)) {
+ return; // out of memory
}
+ newElem->skeleton.adoptInsteadAndCheckErrorCode(new PtnSkeleton(skeleton), status);
+ if (U_FAILURE(status)) {
+ return; // out of memory
+ }
+ newElem->skeletonWasSpecified = skeletonWasSpecified;
if (baseChar >= LOW_A) {
- boot[26 + (baseChar-LOW_A)] = curElem;
+ boot[26 + (baseChar - LOW_A)] = newElem.orphan(); // the boot array now owns the PtnElem.
}
else {
- boot[baseChar-CAP_A] = curElem;
+ boot[baseChar - CAP_A] = newElem.orphan(); // the boot array now owns the PtnElem.
}
- curElem->skeleton = new PtnSkeleton(skeleton);
- curElem->skeletonWasSpecified = skeletonWasSpecified;
}
- if ( baseElem != NULL ) {
+ if ( baseElem != nullptr ) {
curElem = getDuplicateElem(basePattern, skeleton, baseElem);
- if (curElem == NULL) {
+ if (curElem == nullptr) {
// add new element to the list.
curElem = baseElem;
- while( curElem -> next != NULL )
+ while( curElem -> next != nullptr )
{
- curElem = curElem->next;
+ curElem = curElem->next.getAlias();
}
- if ((curElem->next = new PtnElem(basePattern, value)) == NULL ) {
- // out of memory
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
+
+ LocalPointer<PtnElem> newElem(new PtnElem(basePattern, value), status);
+ if (U_FAILURE(status)) {
+ return; // out of memory
}
- curElem=curElem->next;
- curElem->skeleton = new PtnSkeleton(skeleton);
- curElem->skeletonWasSpecified = skeletonWasSpecified;
+ newElem->skeleton.adoptInsteadAndCheckErrorCode(new PtnSkeleton(skeleton), status);
+ if (U_FAILURE(status)) {
+ return; // out of memory
+ }
+ newElem->skeletonWasSpecified = skeletonWasSpecified;
+ curElem->next.adoptInstead(newElem.orphan());
+ curElem = curElem->next.getAlias();
}
else {
// Pattern exists in the list already.
@@ -1809,11 +1921,11 @@ PatternMap::add(const UnicodeString& basePattern,
// Find the pattern from the given basePattern string.
const UnicodeString *
-PatternMap::getPatternFromBasePattern(UnicodeString& basePattern, UBool& skeletonWasSpecified) { // key to search for
+PatternMap::getPatternFromBasePattern(const UnicodeString& basePattern, UBool& skeletonWasSpecified) const { // key to search for
PtnElem *curElem;
- if ((curElem=getHeader(basePattern.charAt(0)))==NULL) {
- return NULL; // no match
+ if ((curElem=getHeader(basePattern.charAt(0)))==nullptr) {
+ return nullptr; // no match
}
do {
@@ -1821,10 +1933,10 @@ PatternMap::getPatternFromBasePattern(UnicodeString& basePattern, UBool& skeleto
skeletonWasSpecified = curElem->skeletonWasSpecified;
return &(curElem->pattern);
}
- curElem=curElem->next;
- }while (curElem != NULL);
+ curElem = curElem->next.getAlias();
+ } while (curElem != nullptr);
- return NULL;
+ return nullptr;
} // PatternMap::getFromBasePattern
@@ -1835,69 +1947,69 @@ PatternMap::getPatternFromBasePattern(UnicodeString& basePattern, UBool& skeleto
// optimum distance value in getBestRaw. When this is called from public getRedundants (specifiedSkeletonPtr is NULL),
// for now it will continue to compare based on baseOriginal so as not to change the behavior unnecessarily.
const UnicodeString *
-PatternMap::getPatternFromSkeleton(PtnSkeleton& skeleton, const PtnSkeleton** specifiedSkeletonPtr) { // key to search for
+PatternMap::getPatternFromSkeleton(const PtnSkeleton& skeleton, const PtnSkeleton** specifiedSkeletonPtr) const { // key to search for
PtnElem *curElem;
if (specifiedSkeletonPtr) {
- *specifiedSkeletonPtr = NULL;
+ *specifiedSkeletonPtr = nullptr;
}
// find boot entry
UChar baseChar = skeleton.getFirstChar();
- if ((curElem=getHeader(baseChar))==NULL) {
- return NULL; // no match
+ if ((curElem=getHeader(baseChar))==nullptr) {
+ return nullptr; // no match
}
do {
UBool equal;
- if (specifiedSkeletonPtr != NULL) { // called from DateTimePatternGenerator::getBestRaw or addPattern, use original
+ if (specifiedSkeletonPtr != nullptr) { // called from DateTimePatternGenerator::getBestRaw or addPattern, use original
equal = curElem->skeleton->original == skeleton.original;
} else { // called from DateTimePatternGenerator::getRedundants, use baseOriginal
equal = curElem->skeleton->baseOriginal == skeleton.baseOriginal;
}
if (equal) {
if (specifiedSkeletonPtr && curElem->skeletonWasSpecified) {
- *specifiedSkeletonPtr = curElem->skeleton;
+ *specifiedSkeletonPtr = curElem->skeleton.getAlias();
}
return &(curElem->pattern);
}
- curElem=curElem->next;
- }while (curElem != NULL);
+ curElem = curElem->next.getAlias();
+ } while (curElem != nullptr);
- return NULL;
+ return nullptr;
}
UBool
-PatternMap::equals(const PatternMap& other) {
+PatternMap::equals(const PatternMap& other) const {
if ( this==&other ) {
return TRUE;
}
- for (int32_t bootIndex=0; bootIndex<MAX_PATTERN_ENTRIES; ++bootIndex ) {
- if ( boot[bootIndex]==other.boot[bootIndex] ) {
+ for (int32_t bootIndex = 0; bootIndex < MAX_PATTERN_ENTRIES; ++bootIndex) {
+ if (boot[bootIndex] == other.boot[bootIndex]) {
continue;
}
- if ( (boot[bootIndex]==NULL)||(other.boot[bootIndex]==NULL) ) {
+ if ((boot[bootIndex] == nullptr) || (other.boot[bootIndex] == nullptr)) {
return FALSE;
}
PtnElem *otherElem = other.boot[bootIndex];
PtnElem *myElem = boot[bootIndex];
- while ((otherElem!=NULL) || (myElem!=NULL)) {
+ while ((otherElem != nullptr) || (myElem != nullptr)) {
if ( myElem == otherElem ) {
break;
}
- if ((otherElem==NULL) || (myElem==NULL)) {
+ if ((otherElem == nullptr) || (myElem == nullptr)) {
return FALSE;
}
if ( (myElem->basePattern != otherElem->basePattern) ||
(myElem->pattern != otherElem->pattern) ) {
return FALSE;
}
- if ((myElem->skeleton!=otherElem->skeleton)&&
+ if ((myElem->skeleton.getAlias() != otherElem->skeleton.getAlias()) &&
!myElem->skeleton->equals(*(otherElem->skeleton))) {
return FALSE;
}
- myElem = myElem->next;
- otherElem=otherElem->next;
+ myElem = myElem->next.getAlias();
+ otherElem = otherElem->next.getAlias();
}
}
return TRUE;
@@ -1909,21 +2021,21 @@ PtnElem*
PatternMap::getDuplicateElem(
const UnicodeString &basePattern,
const PtnSkeleton &skeleton,
- PtnElem *baseElem) {
+ PtnElem *baseElem) {
PtnElem *curElem;
- if ( baseElem == (PtnElem *)NULL ) {
- return (PtnElem*)NULL;
+ if ( baseElem == nullptr ) {
+ return nullptr;
}
else {
curElem = baseElem;
}
do {
if ( basePattern.compare(curElem->basePattern)==0 ) {
- UBool isEqual=TRUE;
- for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
+ UBool isEqual = TRUE;
+ for (int32_t i = 0; i < UDATPG_FIELD_COUNT; ++i) {
if (curElem->skeleton->type[i] != skeleton.type[i] ) {
- isEqual=FALSE;
+ isEqual = FALSE;
break;
}
}
@@ -1931,11 +2043,11 @@ PatternMap::getDuplicateElem(
return curElem;
}
}
- curElem = curElem->next;
- } while( curElem != (PtnElem *)NULL );
+ curElem = curElem->next.getAlias();
+ } while( curElem != nullptr );
// end of the list
- return (PtnElem*)NULL;
+ return nullptr;
} // PatternMap::getDuplicateElem
@@ -1976,7 +2088,7 @@ DateTimeMatcher::set(const UnicodeString& pattern, FormatParser* fp, PtnSkeleton
continue;
}
int32_t canonicalIndex = fp->getCanonicalIndex(value);
- if (canonicalIndex < 0 ) {
+ if (canonicalIndex < 0) {
continue;
}
const dtTypeElem *row = &dtTypes[canonicalIndex];
@@ -1986,8 +2098,9 @@ DateTimeMatcher::set(const UnicodeString& pattern, FormatParser* fp, PtnSkeleton
int32_t repeatCount = row->minLen;
skeletonResult.baseOriginal.populate(field, repeatChar, repeatCount);
int16_t subField = row->type;
- if ( row->type > 0) {
- subField += value.length();
+ if (row->type > 0) {
+ U_ASSERT(value.length() < INT16_MAX);
+ subField += static_cast<int16_t>(value.length());
}
skeletonResult.type[field] = subField;
}
@@ -2031,8 +2144,8 @@ DateTimeMatcher::getPattern() {
}
int32_t
-DateTimeMatcher::getDistance(const DateTimeMatcher& other, int32_t includeMask, DistanceInfo& distanceInfo) {
- int32_t result=0;
+DateTimeMatcher::getDistance(const DateTimeMatcher& other, int32_t includeMask, DistanceInfo& distanceInfo) const {
+ int32_t result = 0;
distanceInfo.clear();
for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) {
int32_t myType = (includeMask&(1<<i))==0 ? 0 : skeleton.type[i];
@@ -2071,13 +2184,13 @@ DateTimeMatcher::copyFrom() {
UBool
DateTimeMatcher::equals(const DateTimeMatcher* other) const {
- if (other==NULL) { return FALSE; }
+ if (other==nullptr) { return FALSE; }
return skeleton.original == other->skeleton.original;
}
int32_t
-DateTimeMatcher::getFieldMask() {
- int32_t result=0;
+DateTimeMatcher::getFieldMask() const {
+ int32_t result = 0;
for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
if (skeleton.type[i]!=0) {
@@ -2094,7 +2207,7 @@ DateTimeMatcher::getSkeletonPtr() {
FormatParser::FormatParser () {
status = START;
- itemNumber=0;
+ itemNumber = 0;
}
@@ -2106,7 +2219,7 @@ FormatParser::~FormatParser () {
// Note: the startPos may
FormatParser::TokenStatus
FormatParser::setTokens(const UnicodeString& pattern, int32_t startPos, int32_t *len) {
- int32_t curLoc = startPos;
+ int32_t curLoc = startPos;
if ( curLoc >= pattern.length()) {
return DONE;
}
@@ -2132,10 +2245,10 @@ FormatParser::setTokens(const UnicodeString& pattern, int32_t startPos, int32_t
void
FormatParser::set(const UnicodeString& pattern) {
- int32_t startPos=0;
- TokenStatus result=START;
- int32_t len=0;
- itemNumber =0;
+ int32_t startPos = 0;
+ TokenStatus result = START;
+ int32_t len = 0;
+ itemNumber = 0;
do {
result = setTokens( pattern, startPos, &len );
@@ -2186,14 +2299,14 @@ FormatParser::getCanonicalIndex(const UnicodeString& s, UBool strict) {
UBool
FormatParser::isQuoteLiteral(const UnicodeString& s) {
- return (UBool)(s.charAt(0)==SINGLE_QUOTE);
+ return (UBool)(s.charAt(0) == SINGLE_QUOTE);
}
-// This function aussumes the current itemIndex points to the quote literal.
+// This function assumes the current itemIndex points to the quote literal.
// Please call isQuoteLiteral prior to this function.
void
FormatParser::getQuoteLiteral(UnicodeString& quote, int32_t *itemIndex) {
- int32_t i=*itemIndex;
+ int32_t i = *itemIndex;
quote.remove();
if (items[i].charAt(0)==SINGLE_QUOTE) {
@@ -2222,7 +2335,7 @@ FormatParser::getQuoteLiteral(UnicodeString& quote, int32_t *itemIndex) {
}
UBool
-FormatParser::isPatternSeparator(UnicodeString& field) {
+FormatParser::isPatternSeparator(const UnicodeString& field) const {
for (int32_t i=0; i<field.length(); ++i ) {
UChar c= field.charAt(i);
if ( (c==SINGLE_QUOTE) || (c==BACKSLASH) || (c==SPACE) || (c==COLON) ||
@@ -2239,21 +2352,19 @@ FormatParser::isPatternSeparator(UnicodeString& field) {
DistanceInfo::~DistanceInfo() {}
void
-DistanceInfo::setTo(DistanceInfo &other) {
+DistanceInfo::setTo(const DistanceInfo& other) {
missingFieldMask = other.missingFieldMask;
extraFieldMask= other.extraFieldMask;
}
-PatternMapIterator::PatternMapIterator() {
- bootIndex = 0;
- nodePtr = NULL;
- patternMap=NULL;
- matcher= new DateTimeMatcher();
+PatternMapIterator::PatternMapIterator(UErrorCode& status) :
+ bootIndex(0), nodePtr(nullptr), matcher(nullptr), patternMap(nullptr)
+{
+ if (U_FAILURE(status)) { return; }
+ matcher.adoptInsteadAndCheckErrorCode(new DateTimeMatcher(), status);
}
-
PatternMapIterator::~PatternMapIterator() {
- delete matcher;
}
void
@@ -2262,36 +2373,36 @@ PatternMapIterator::set(PatternMap& newPatternMap) {
}
PtnSkeleton*
-PatternMapIterator::getSkeleton() {
- if ( nodePtr == NULL ) {
- return NULL;
+PatternMapIterator::getSkeleton() const {
+ if ( nodePtr == nullptr ) {
+ return nullptr;
}
else {
- return nodePtr->skeleton;
+ return nodePtr->skeleton.getAlias();
}
}
UBool
-PatternMapIterator::hasNext() {
- int32_t headIndex=bootIndex;
- PtnElem *curPtr=nodePtr;
+PatternMapIterator::hasNext() const {
+ int32_t headIndex = bootIndex;
+ PtnElem *curPtr = nodePtr;
- if (patternMap==NULL) {
+ if (patternMap==nullptr) {
return FALSE;
}
while ( headIndex < MAX_PATTERN_ENTRIES ) {
- if ( curPtr != NULL ) {
- if ( curPtr->next != NULL ) {
+ if ( curPtr != nullptr ) {
+ if ( curPtr->next != nullptr ) {
return TRUE;
}
else {
headIndex++;
- curPtr=NULL;
+ curPtr=nullptr;
continue;
}
}
else {
- if ( patternMap->boot[headIndex] != NULL ) {
+ if ( patternMap->boot[headIndex] != nullptr ) {
return TRUE;
}
else {
@@ -2299,7 +2410,6 @@ PatternMapIterator::hasNext() {
continue;
}
}
-
}
return FALSE;
}
@@ -2307,19 +2417,19 @@ PatternMapIterator::hasNext() {
DateTimeMatcher&
PatternMapIterator::next() {
while ( bootIndex < MAX_PATTERN_ENTRIES ) {
- if ( nodePtr != NULL ) {
- if ( nodePtr->next != NULL ) {
- nodePtr = nodePtr->next;
+ if ( nodePtr != nullptr ) {
+ if ( nodePtr->next != nullptr ) {
+ nodePtr = nodePtr->next.getAlias();
break;
}
else {
bootIndex++;
- nodePtr=NULL;
+ nodePtr=nullptr;
continue;
}
}
else {
- if ( patternMap->boot[bootIndex] != NULL ) {
+ if ( patternMap->boot[bootIndex] != nullptr ) {
nodePtr = patternMap->boot[bootIndex];
break;
}
@@ -2329,7 +2439,7 @@ PatternMapIterator::next() {
}
}
}
- if (nodePtr!=NULL) {
+ if (nodePtr!=nullptr) {
matcher->copyFrom(*nodePtr->skeleton);
}
else {
@@ -2468,36 +2578,28 @@ PtnSkeleton::~PtnSkeleton() {
}
PtnElem::PtnElem(const UnicodeString &basePat, const UnicodeString &pat) :
-basePattern(basePat),
-skeleton(NULL),
-pattern(pat),
-next(NULL)
+ basePattern(basePat), skeleton(nullptr), pattern(pat), next(nullptr)
{
}
PtnElem::~PtnElem() {
-
- if (next!=NULL) {
- delete next;
- }
- delete skeleton;
}
-DTSkeletonEnumeration::DTSkeletonEnumeration(PatternMap &patternMap, dtStrEnum type, UErrorCode& status) {
+DTSkeletonEnumeration::DTSkeletonEnumeration(PatternMap& patternMap, dtStrEnum type, UErrorCode& status) : fSkeletons(nullptr) {
PtnElem *curElem;
PtnSkeleton *curSkeleton;
UnicodeString s;
int32_t bootIndex;
pos=0;
- fSkeletons = new UVector(status);
+ fSkeletons.adoptInsteadAndCheckErrorCode(new UVector(status), status);
if (U_FAILURE(status)) {
- delete fSkeletons;
return;
}
+
for (bootIndex=0; bootIndex<MAX_PATTERN_ENTRIES; ++bootIndex ) {
curElem = patternMap.boot[bootIndex];
- while (curElem!=NULL) {
+ while (curElem!=nullptr) {
switch(type) {
case DT_BASESKELETON:
s=curElem->basePattern;
@@ -2506,32 +2608,36 @@ DTSkeletonEnumeration::DTSkeletonEnumeration(PatternMap &patternMap, dtStrEnum t
s=curElem->pattern;
break;
case DT_SKELETON:
- curSkeleton=curElem->skeleton;
+ curSkeleton=curElem->skeleton.getAlias();
s=curSkeleton->getSkeleton();
break;
}
if ( !isCanonicalItem(s) ) {
- fSkeletons->addElement(new UnicodeString(s), status);
+ LocalPointer<UnicodeString> newElem(new UnicodeString(s), status);
if (U_FAILURE(status)) {
- delete fSkeletons;
- fSkeletons = NULL;
return;
}
+ fSkeletons->addElement(newElem.getAlias(), status);
+ if (U_FAILURE(status)) {
+ fSkeletons.adoptInstead(nullptr);
+ return;
+ }
+ newElem.orphan(); // fSkeletons vector now owns the UnicodeString.
}
- curElem = curElem->next;
+ curElem = curElem->next.getAlias();
}
}
- if ((bootIndex==MAX_PATTERN_ENTRIES) && (curElem!=NULL) ) {
+ if ((bootIndex==MAX_PATTERN_ENTRIES) && (curElem!=nullptr) ) {
status = U_BUFFER_OVERFLOW_ERROR;
}
}
const UnicodeString*
DTSkeletonEnumeration::snext(UErrorCode& status) {
- if (U_SUCCESS(status) && pos < fSkeletons->size()) {
+ if (U_SUCCESS(status) && fSkeletons.isValid() && pos < fSkeletons->size()) {
return (const UnicodeString*)fSkeletons->elementAt(pos++);
}
- return NULL;
+ return nullptr;
}
void
@@ -2541,7 +2647,7 @@ DTSkeletonEnumeration::reset(UErrorCode& /*status*/) {
int32_t
DTSkeletonEnumeration::count(UErrorCode& /*status*/) const {
- return (fSkeletons==NULL) ? 0 : fSkeletons->size();
+ return (fSkeletons.isNull()) ? 0 : fSkeletons->size();
}
UBool
@@ -2559,44 +2665,45 @@ DTSkeletonEnumeration::isCanonicalItem(const UnicodeString& item) {
DTSkeletonEnumeration::~DTSkeletonEnumeration() {
UnicodeString *s;
- for (int32_t i=0; i<fSkeletons->size(); ++i) {
- if ((s=(UnicodeString *)fSkeletons->elementAt(i))!=NULL) {
- delete s;
+ if (fSkeletons.isValid()) {
+ for (int32_t i = 0; i < fSkeletons->size(); ++i) {
+ if ((s = (UnicodeString *)fSkeletons->elementAt(i)) != nullptr) {
+ delete s;
+ }
}
}
- delete fSkeletons;
}
-DTRedundantEnumeration::DTRedundantEnumeration() {
- pos=0;
- fPatterns = NULL;
+DTRedundantEnumeration::DTRedundantEnumeration() : pos(0), fPatterns(nullptr) {
}
void
DTRedundantEnumeration::add(const UnicodeString& pattern, UErrorCode& status) {
- if (U_FAILURE(status)) return;
- if (fPatterns == NULL) {
- fPatterns = new UVector(status);
+ if (U_FAILURE(status)) { return; }
+ if (fPatterns.isNull()) {
+ fPatterns.adoptInsteadAndCheckErrorCode(new UVector(status), status);
if (U_FAILURE(status)) {
- delete fPatterns;
- fPatterns = NULL;
return;
}
}
- fPatterns->addElement(new UnicodeString(pattern), status);
+ LocalPointer<UnicodeString> newElem(new UnicodeString(pattern), status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fPatterns->addElement(newElem.getAlias(), status);
if (U_FAILURE(status)) {
- delete fPatterns;
- fPatterns = NULL;
+ fPatterns.adoptInstead(nullptr);
return;
}
+ newElem.orphan(); // fPatterns now owns the string.
}
const UnicodeString*
DTRedundantEnumeration::snext(UErrorCode& status) {
- if (U_SUCCESS(status) && pos < fPatterns->size()) {
+ if (U_SUCCESS(status) && fPatterns.isValid() && pos < fPatterns->size()) {
return (const UnicodeString*)fPatterns->elementAt(pos++);
}
- return NULL;
+ return nullptr;
}
void
@@ -2606,11 +2713,11 @@ DTRedundantEnumeration::reset(UErrorCode& /*status*/) {
int32_t
DTRedundantEnumeration::count(UErrorCode& /*status*/) const {
- return (fPatterns==NULL) ? 0 : fPatterns->size();
+ return (fPatterns.isNull()) ? 0 : fPatterns->size();
}
UBool
-DTRedundantEnumeration::isCanonicalItem(const UnicodeString& item) {
+DTRedundantEnumeration::isCanonicalItem(const UnicodeString& item) const {
if ( item.length() != 1 ) {
return FALSE;
}
@@ -2624,12 +2731,13 @@ DTRedundantEnumeration::isCanonicalItem(const UnicodeString& item) {
DTRedundantEnumeration::~DTRedundantEnumeration() {
UnicodeString *s;
- for (int32_t i=0; i<fPatterns->size(); ++i) {
- if ((s=(UnicodeString *)fPatterns->elementAt(i))!=NULL) {
- delete s;
+ if (fPatterns.isValid()) {
+ for (int32_t i = 0; i < fPatterns->size(); ++i) {
+ if ((s = (UnicodeString *)fPatterns->elementAt(i)) != nullptr) {
+ delete s;
+ }
}
}
- delete fPatterns;
}
U_NAMESPACE_END
diff --git a/deps/icu-small/source/i18n/dtptngen_impl.h b/deps/icu-small/source/i18n/dtptngen_impl.h
index 2ea31a75c4..95219f0ba2 100644
--- a/deps/icu-small/source/i18n/dtptngen_impl.h
+++ b/deps/icu-small/source/i18n/dtptngen_impl.h
@@ -116,7 +116,7 @@ typedef struct dtTypeElem {
int16_t type;
int16_t minLen;
int16_t weight;
-}dtTypeElem;
+} dtTypeElem;
// A compact storage mechanism for skeleton field strings. Several dozen of these will be created
// for a typical DateTimePatternGenerator instance.
@@ -172,30 +172,28 @@ public:
virtual ~PtnSkeleton();
};
-
class PtnElem : public UMemory {
public:
UnicodeString basePattern;
- PtnSkeleton *skeleton;
+ LocalPointer<PtnSkeleton> skeleton;
UnicodeString pattern;
UBool skeletonWasSpecified; // if specified in availableFormats, not derived
- PtnElem *next;
+ LocalPointer<PtnElem> next;
PtnElem(const UnicodeString &basePattern, const UnicodeString &pattern);
virtual ~PtnElem();
-
};
class FormatParser : public UMemory {
public:
UnicodeString items[MAX_DT_TOKEN];
- int32_t itemNumber;
+ int32_t itemNumber;
FormatParser();
virtual ~FormatParser();
void set(const UnicodeString& patternString);
void getQuoteLiteral(UnicodeString& quote, int32_t *itemIndex);
- UBool isPatternSeparator(UnicodeString& field);
+ UBool isPatternSeparator(const UnicodeString& field) const;
static UBool isQuoteLiteral(const UnicodeString& s);
static int32_t getCanonicalIndex(const UnicodeString& s) { return getCanonicalIndex(s, TRUE); }
static int32_t getCanonicalIndex(const UnicodeString& s, UBool strict);
@@ -206,7 +204,7 @@ private:
ADD_TOKEN,
SYNTAX_ERROR,
DONE
- } ToeknStatus;
+ } TokenStatus;
TokenStatus status;
virtual TokenStatus setTokens(const UnicodeString& pattern, int32_t startPos, int32_t *len);
@@ -220,7 +218,7 @@ public:
DistanceInfo() {}
virtual ~DistanceInfo();
void clear() { missingFieldMask = extraFieldMask = 0; }
- void setTo(DistanceInfo& other);
+ void setTo(const DistanceInfo& other);
void addMissing(int32_t field) { missingFieldMask |= (1<<field); }
void addExtra(int32_t field) { extraFieldMask |= (1<<field); }
};
@@ -237,11 +235,11 @@ public:
void copyFrom();
PtnSkeleton* getSkeletonPtr();
UBool equals(const DateTimeMatcher* other) const;
- int32_t getDistance(const DateTimeMatcher& other, int32_t includeMask, DistanceInfo& distanceInfo);
+ int32_t getDistance(const DateTimeMatcher& other, int32_t includeMask, DistanceInfo& distanceInfo) const;
DateTimeMatcher();
DateTimeMatcher(const DateTimeMatcher& other);
virtual ~DateTimeMatcher();
- int32_t getFieldMask();
+ int32_t getFieldMask() const;
};
class PatternMap : public UMemory {
@@ -250,34 +248,34 @@ public:
PatternMap();
virtual ~PatternMap();
void add(const UnicodeString& basePattern, const PtnSkeleton& skeleton, const UnicodeString& value, UBool skeletonWasSpecified, UErrorCode& status);
- const UnicodeString* getPatternFromBasePattern(UnicodeString& basePattern, UBool& skeletonWasSpecified);
- const UnicodeString* getPatternFromSkeleton(PtnSkeleton& skeleton, const PtnSkeleton** specifiedSkeletonPtr = 0);
+ const UnicodeString* getPatternFromBasePattern(const UnicodeString& basePattern, UBool& skeletonWasSpecified) const;
+ const UnicodeString* getPatternFromSkeleton(const PtnSkeleton& skeleton, const PtnSkeleton** specifiedSkeletonPtr = 0) const;
void copyFrom(const PatternMap& other, UErrorCode& status);
- PtnElem* getHeader(UChar baseChar);
- UBool equals(const PatternMap& other);
+ PtnElem* getHeader(UChar baseChar) const;
+ UBool equals(const PatternMap& other) const;
private:
UBool isDupAllowed;
- PtnElem* getDuplicateElem(const UnicodeString &basePattern, const PtnSkeleton& skeleton, PtnElem *baseElem);
+ PtnElem* getDuplicateElem(const UnicodeString& basePattern, const PtnSkeleton& skeleton, PtnElem *baseElem);
}; // end PatternMap
class PatternMapIterator : public UMemory {
public:
- PatternMapIterator();
+ PatternMapIterator(UErrorCode &status);
virtual ~PatternMapIterator();
void set(PatternMap& patternMap);
- PtnSkeleton* getSkeleton();
- UBool hasNext();
+ PtnSkeleton* getSkeleton() const;
+ UBool hasNext() const;
DateTimeMatcher& next();
private:
int32_t bootIndex;
PtnElem *nodePtr;
- DateTimeMatcher *matcher;
+ LocalPointer<DateTimeMatcher> matcher;
PatternMap *patternMap;
};
class DTSkeletonEnumeration : public StringEnumeration {
public:
- DTSkeletonEnumeration(PatternMap &patternMap, dtStrEnum type, UErrorCode& status);
+ DTSkeletonEnumeration(PatternMap& patternMap, dtStrEnum type, UErrorCode& status);
virtual ~DTSkeletonEnumeration();
static UClassID U_EXPORT2 getStaticClassID(void);
virtual UClassID getDynamicClassID(void) const;
@@ -287,7 +285,7 @@ public:
private:
int32_t pos;
UBool isCanonicalItem(const UnicodeString& item);
- UVector *fSkeletons;
+ LocalPointer<UVector> fSkeletons;
};
class DTRedundantEnumeration : public StringEnumeration {
@@ -302,8 +300,8 @@ public:
void add(const UnicodeString &pattern, UErrorCode& status);
private:
int32_t pos;
- UBool isCanonicalItem(const UnicodeString& item);
- UVector *fPatterns;
+ UBool isCanonicalItem(const UnicodeString& item) const;
+ LocalPointer<UVector> fPatterns;
};
U_NAMESPACE_END
diff --git a/deps/icu-small/source/i18n/erarules.cpp b/deps/icu-small/source/i18n/erarules.cpp
new file mode 100644
index 0000000000..669f844230
--- /dev/null
+++ b/deps/icu-small/source/i18n/erarules.cpp
@@ -0,0 +1,307 @@
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include <stdlib.h>
+#include "unicode/ucal.h"
+#include "unicode/ures.h"
+#include "unicode/ustring.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "erarules.h"
+#include "gregoimp.h"
+#include "uassert.h"
+
+U_NAMESPACE_BEGIN
+
+static const int32_t MAX_ENCODED_START_YEAR = 32767;
+static const int32_t MIN_ENCODED_START_YEAR = -32768;
+static const int32_t MIN_ENCODED_START = -2147483391; // encodeDate(MIN_ENCODED_START_YEAR, 1, 1, ...);
+
+static const int32_t YEAR_MASK = 0xFFFF0000;
+static const int32_t MONTH_MASK = 0x0000FF00;
+static const int32_t DAY_MASK = 0x000000FF;
+
+static const int32_t MAX_INT32 = 0x7FFFFFFF;
+static const int32_t MIN_INT32 = 0xFFFFFFFF;
+
+static const UChar VAL_FALSE[] = {0x66, 0x61, 0x6c, 0x73, 0x65}; // "false"
+static const UChar VAL_FALSE_LEN = 5;
+
+static UBool isSet(int startDate) {
+ return startDate != 0;
+}
+
+static UBool isValidRuleStartDate(int32_t year, int32_t month, int32_t day) {
+ return year >= MIN_ENCODED_START_YEAR && year <= MAX_ENCODED_START_YEAR
+ && month >= 1 && month <= 12 && day >=1 && day <= 31;
+}
+
+/**
+ * Encode year/month/date to a single integer.
+ * year is high 16 bits (-32768 to 32767), month is
+ * next 8 bits and day of month is last 8 bits.
+ *
+ * @param year year
+ * @param month month (1-base)
+ * @param day day of month
+ * @return an encoded date.
+ */
+static int32_t encodeDate(int32_t year, int32_t month, int32_t day) {
+ return year << 16 | month << 8 | day;
+}
+
+static void decodeDate(int32_t encodedDate, int32_t (&fields)[3]) {
+ if (encodedDate == MIN_ENCODED_START) {
+ fields[0] = MIN_INT32;
+ fields[1] = 1;
+ fields[2] = 1;
+ } else {
+ fields[0] = (encodedDate & YEAR_MASK) >> 16;
+ fields[1] = (encodedDate & MONTH_MASK) >> 8;
+ fields[2] = encodedDate & DAY_MASK;
+ }
+}
+
+/**
+ * Compare an encoded date with another date specified by year/month/day.
+ * @param encoded An encoded date
+ * @param year Year of another date
+ * @param month Month of another date
+ * @param day Day of another date
+ * @return -1 when encoded date is earlier, 0 when two dates are same,
+ * and 1 when encoded date is later.
+ */
+static int32_t compareEncodedDateWithYMD(int encoded, int year, int month, int day) {
+ if (year < MIN_ENCODED_START_YEAR) {
+ if (encoded == MIN_ENCODED_START) {
+ if (year > MIN_INT32 || month > 1 || day > 1) {
+ return -1;
+ }
+ return 0;
+ } else {
+ return 1;
+ }
+ } else if (year > MAX_ENCODED_START_YEAR) {
+ return -1;
+ } else {
+ int tmp = encodeDate(year, month, day);
+ if (encoded < tmp) {
+ return -1;
+ } else if (encoded == tmp) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+}
+
+EraRules::EraRules(LocalMemory<int32_t>& eraStartDates, int32_t numEras)
+ : numEras(numEras) {
+ startDates.moveFrom(eraStartDates);
+ initCurrentEra();
+}
+
+EraRules::~EraRules() {
+}
+
+EraRules* EraRules::createInstance(const char *calType, UBool includeTentativeEra, UErrorCode& status) {
+ if(U_FAILURE(status)) {
+ return nullptr;
+ }
+ LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "supplementalData", &status));
+ ures_getByKey(rb.getAlias(), "calendarData", rb.getAlias(), &status);
+ ures_getByKey(rb.getAlias(), calType, rb.getAlias(), &status);
+ ures_getByKey(rb.getAlias(), "eras", rb.getAlias(), &status);
+
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+
+ int32_t numEras = ures_getSize(rb.getAlias());
+ int32_t firstTentativeIdx = MAX_INT32;
+
+ LocalMemory<int32_t> startDates(static_cast<int32_t *>(uprv_malloc(numEras * sizeof(int32_t))));
+ if (startDates.isNull()) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+ uprv_memset(startDates.getAlias(), 0 , numEras * sizeof(int32_t));
+
+ while (ures_hasNext(rb.getAlias())) {
+ LocalUResourceBundlePointer eraRuleRes(ures_getNextResource(rb.getAlias(), nullptr, &status));
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+ const char *eraIdxStr = ures_getKey(eraRuleRes.getAlias());
+ char *endp;
+ int32_t eraIdx = (int32_t)strtol(eraIdxStr, &endp, 10);
+ if ((size_t)(endp - eraIdxStr) != uprv_strlen(eraIdxStr)) {
+ status = U_INVALID_FORMAT_ERROR;
+ return nullptr;
+ }
+ if (eraIdx < 0 || eraIdx >= numEras) {
+ status = U_INVALID_FORMAT_ERROR;
+ return nullptr;
+ }
+ if (isSet(startDates[eraIdx])) {
+ // start date of the index was already set
+ status = U_INVALID_FORMAT_ERROR;
+ return nullptr;
+ }
+
+ UBool hasName = TRUE;
+ UBool hasEnd = TRUE;
+ int32_t len;
+ while (ures_hasNext(eraRuleRes.getAlias())) {
+ LocalUResourceBundlePointer res(ures_getNextResource(eraRuleRes.getAlias(), nullptr, &status));
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+ const char *key = ures_getKey(res.getAlias());
+ if (uprv_strcmp(key, "start") == 0) {
+ const int32_t *fields = ures_getIntVector(res.getAlias(), &len, &status);
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+ if (len != 3 || !isValidRuleStartDate(fields[0], fields[1], fields[2])) {
+ status = U_INVALID_FORMAT_ERROR;
+ return nullptr;
+ }
+ startDates[eraIdx] = encodeDate(fields[0], fields[1], fields[2]);
+ } else if (uprv_strcmp(key, "named") == 0) {
+ const UChar *val = ures_getString(res.getAlias(), &len, &status);
+ if (u_strncmp(val, VAL_FALSE, VAL_FALSE_LEN) == 0) {
+ hasName = FALSE;
+ }
+ } else if (uprv_strcmp(key, "end") == 0) {
+ hasEnd = TRUE;
+ }
+ }
+
+ if (isSet(startDates[eraIdx])) {
+ if (hasEnd) {
+ // This implementation assumes either start or end is available, not both.
+ // For now, just ignore the end rule.
+ }
+ } else {
+ if (hasEnd) {
+ if (eraIdx != 0) {
+ // This implementation does not support end only rule for eras other than
+ // the first one.
+ status = U_INVALID_FORMAT_ERROR;
+ return nullptr;
+ }
+ U_ASSERT(eraIdx == 0);
+ startDates[eraIdx] = MIN_ENCODED_START;
+ } else {
+ status = U_INVALID_FORMAT_ERROR;
+ return nullptr;
+ }
+ }
+
+ if (hasName) {
+ if (eraIdx >= firstTentativeIdx) {
+ status = U_INVALID_FORMAT_ERROR;
+ return nullptr;
+ }
+ } else {
+ if (eraIdx < firstTentativeIdx) {
+ firstTentativeIdx = eraIdx;
+ }
+ }
+ }
+
+ EraRules *result;
+ if (firstTentativeIdx < MAX_INT32 && !includeTentativeEra) {
+ result = new EraRules(startDates, firstTentativeIdx);
+ } else {
+ result = new EraRules(startDates, numEras);
+ }
+
+ if (result == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return result;
+}
+
+void EraRules::getStartDate(int32_t eraIdx, int32_t (&fields)[3], UErrorCode& status) const {
+ if(U_FAILURE(status)) {
+ return;
+ }
+ if (eraIdx < 0 || eraIdx >= numEras) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ decodeDate(startDates[eraIdx], fields);
+}
+
+int32_t EraRules::getStartYear(int32_t eraIdx, UErrorCode& status) const {
+ int year = MAX_INT32; // bogus value
+ if(U_FAILURE(status)) {
+ return year;
+ }
+ if (eraIdx < 0 || eraIdx >= numEras) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return year;
+ }
+ int fields[3];
+ decodeDate(startDates[eraIdx], fields);
+ year = fields[0];
+
+ return year;
+}
+
+int32_t EraRules::getEraIndex(int32_t year, int32_t month, int32_t day, UErrorCode& status) const {
+ if(U_FAILURE(status)) {
+ return -1;
+ }
+
+ if (month < 1 || month > 12 || day < 1 || day > 31) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return -1;
+ }
+ int32_t high = numEras; // last index + 1
+ int32_t low;
+
+ // Short circuit for recent years. Most modern computations will
+ // occur in the last few eras.
+ if (compareEncodedDateWithYMD(startDates[getCurrentEraIndex()], year, month, day) <= 0) {
+ low = getCurrentEraIndex();
+ } else {
+ low = 0;
+ }
+
+ // Do binary search
+ while (low < high - 1) {
+ int i = (low + high) / 2;
+ if (compareEncodedDateWithYMD(startDates[i], year, month, day) <= 0) {
+ low = i;
+ } else {
+ high = i;
+ }
+ }
+ return low;
+}
+
+void EraRules::initCurrentEra() {
+ UDate now = ucal_getNow();
+ int year, month0, dom, dow, doy, mid;
+ Grego::timeToFields(now, year, month0, dom, dow, doy, mid);
+ int currentEncodedDate = encodeDate(year, month0 + 1 /* changes to 1-base */, dom);
+ int eraIdx = numEras - 1;
+ while (eraIdx > 0) {
+ if (currentEncodedDate >= startDates[eraIdx]) {
+ break;
+ }
+ eraIdx--;
+ }
+ // Note: current era could be before the first era.
+ // In this case, this implementation returns the first era index (0).
+ currentEra = eraIdx;}
+
+U_NAMESPACE_END
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/deps/icu-small/source/i18n/erarules.h b/deps/icu-small/source/i18n/erarules.h
new file mode 100644
index 0000000000..4ed8640832
--- /dev/null
+++ b/deps/icu-small/source/i18n/erarules.h
@@ -0,0 +1,92 @@
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#ifndef ERARULES_H_
+#define ERARULES_H_
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/localpointer.h"
+#include "unicode/uobject.h"
+#include "cmemory.h"
+
+U_NAMESPACE_BEGIN
+
+// Export an explicit template instantiation of LocalMemory used as a data member of EraRules.
+// When building DLLs for Windows this is required even though no direct access leaks out of the i18n library.
+// See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples.
+#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
+// Ignore warning 4661 as LocalPointerBase does not use operator== or operator!=
+#pragma warning(suppress: 4661)
+template class U_I18N_API LocalPointerBase<int32_t>;
+template class U_I18N_API LocalMemory<int32_t>;
+#endif
+
+class U_I18N_API EraRules : public UMemory {
+public:
+ ~EraRules();
+
+ static EraRules* createInstance(const char *calType, UBool includeTentativeEra, UErrorCode& status);
+
+ /**
+ * Gets number of effective eras
+ * @return number of effective eras
+ */
+ inline int32_t getNumberOfEras() const {
+ return numEras;
+ }
+
+ /**
+ * Gets start date of an era
+ * @param eraIdx Era index
+ * @param fields Receives date fields. The result includes values of year, month,
+ * day of month in this order. When an era has no start date, the result
+ * will be January 1st in year whose value is minimum integer.
+ * @param status Receives status.
+ */
+ void getStartDate(int32_t eraIdx, int32_t (&fields)[3], UErrorCode& status) const;
+
+ /**
+ * Gets start year of an era
+ * @param eraIdx Era index
+ * @param status Receives status.
+ * @return The first year of an era. When a era has no start date, minimum int32
+ * value is returned.
+ */
+ int32_t getStartYear(int32_t eraIdx, UErrorCode& status) const;
+
+ /**
+ * Returns era index for the specified year/month/day.
+ * @param year Year
+ * @param month Month (1-base)
+ * @param day Day of month
+ * @param status Receives status
+ * @return era index (or 0, when the specified date is before the first era)
+ */
+ int32_t getEraIndex(int32_t year, int32_t month, int32_t day, UErrorCode& status) const;
+
+ /**
+ * Gets the current era index. This is calculated only once for an instance of
+ * EraRules.
+ *
+ * @return era index of current era (or 0, when current date is before the first era)
+ */
+ inline int32_t getCurrentEraIndex() const {
+ return currentEra;
+ }
+
+private:
+ EraRules(LocalMemory<int32_t>& eraStartDates, int32_t numEra);
+
+ void initCurrentEra();
+
+ LocalMemory<int32_t> startDates;
+ int32_t numEras;
+ int32_t currentEra;
+};
+
+U_NAMESPACE_END
+#endif /* #if !UCONFIG_NO_FORMATTING */
+#endif /* ERARULES_H_ */
diff --git a/deps/icu-small/source/i18n/fphdlimp.h b/deps/icu-small/source/i18n/fphdlimp.h
index 2e9d5622b1..a6827e01e9 100644
--- a/deps/icu-small/source/i18n/fphdlimp.h
+++ b/deps/icu-small/source/i18n/fphdlimp.h
@@ -10,9 +10,10 @@
#ifndef FPHDLIMP_H
#define FPHDLIMP_H
+#include "unicode/utypes.h"
+
#if !UCONFIG_NO_FORMATTING
-#include "unicode/utypes.h"
#include "unicode/fieldpos.h"
#include "unicode/fpositer.h"
diff --git a/deps/icu-small/source/i18n/gregocal.cpp b/deps/icu-small/source/i18n/gregocal.cpp
index 49c4226049..4db66758df 100644
--- a/deps/icu-small/source/i18n/gregocal.cpp
+++ b/deps/icu-small/source/i18n/gregocal.cpp
@@ -541,8 +541,8 @@ int32_t GregorianCalendar::handleComputeMonthStart(int32_t eyear, int32_t month,
}
UBool isLeap = eyear%4 == 0;
- int32_t y = eyear-1;
- int32_t julianDay = 365*y + ClockMath::floorDivide(y, 4) + (kJan1_1JulianDay - 3);
+ int64_t y = (int64_t)eyear-1;
+ int64_t julianDay = 365*y + ClockMath::floorDivide(y, (int64_t)4) + (kJan1_1JulianDay - 3);
nonConstThis->fIsGregorian = (eyear >= fGregorianCutoverYear);
#if defined (U_DEBUG_CAL)
@@ -572,7 +572,7 @@ int32_t GregorianCalendar::handleComputeMonthStart(int32_t eyear, int32_t month,
julianDay += isLeap?kLeapNumDays[month]:kNumDays[month];
}
- return julianDay;
+ return static_cast<int32_t>(julianDay);
}
int32_t GregorianCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month) const
diff --git a/deps/icu-small/source/i18n/gregoimp.h b/deps/icu-small/source/i18n/gregoimp.h
index 55922a6b40..eb3844f852 100644
--- a/deps/icu-small/source/i18n/gregoimp.h
+++ b/deps/icu-small/source/i18n/gregoimp.h
@@ -299,8 +299,8 @@ inline int32_t Grego::millisToJulianDay(double millis) {
}
inline int32_t Grego::gregorianShift(int32_t eyear) {
- int32_t y = eyear-1;
- int32_t gregShift = ClockMath::floorDivide(y, 400) - ClockMath::floorDivide(y, 100) + 2;
+ int64_t y = (int64_t)eyear-1;
+ int32_t gregShift = static_cast<int32_t>(ClockMath::floorDivide(y, (int64_t)400) - ClockMath::floorDivide(y, (int64_t)100) + 2);
return gregShift;
}
diff --git a/deps/icu-small/source/i18n/indiancal.cpp b/deps/icu-small/source/i18n/indiancal.cpp
index a2a7f2dcdd..667b6f2d7a 100644
--- a/deps/icu-small/source/i18n/indiancal.cpp
+++ b/deps/icu-small/source/i18n/indiancal.cpp
@@ -347,12 +347,15 @@ IndianCalendar::inDaylightTime(UErrorCode& status) const
return (UBool)(U_SUCCESS(status) ? (internalGet(UCAL_DST_OFFSET) != 0) : FALSE);
}
-// default century
-const UDate IndianCalendar::fgSystemDefaultCentury = DBL_MIN;
-const int32_t IndianCalendar::fgSystemDefaultCenturyYear = -1;
-UDate IndianCalendar::fgSystemDefaultCenturyStart = DBL_MIN;
-int32_t IndianCalendar::fgSystemDefaultCenturyStartYear = -1;
+/**
+ * The system maintains a static default century start date and Year. They are
+ * initialized the first time they are used. Once the system default century date
+ * and year are set, they do not change.
+ */
+static UDate gSystemDefaultCenturyStart = DBL_MIN;
+static int32_t gSystemDefaultCenturyStartYear = -1;
+static icu::UInitOnce gSystemDefaultCenturyInit = U_INITONCE_INITIALIZER;
UBool IndianCalendar::haveDefaultCentury() const
@@ -360,87 +363,45 @@ UBool IndianCalendar::haveDefaultCentury() const
return TRUE;
}
-UDate IndianCalendar::defaultCenturyStart() const
+static void U_CALLCONV
+initializeSystemDefaultCentury()
{
- return internalGetDefaultCenturyStart();
-}
+ // initialize systemDefaultCentury and systemDefaultCenturyYear based
+ // on the current time. They'll be set to 80 years before
+ // the current time.
+ UErrorCode status = U_ZERO_ERROR;
-int32_t IndianCalendar::defaultCenturyStartYear() const
-{
- return internalGetDefaultCenturyStartYear();
-}
+ IndianCalendar calendar ( Locale ( "@calendar=Indian" ), status);
+ if ( U_SUCCESS ( status ) ) {
+ calendar.setTime ( Calendar::getNow(), status );
+ calendar.add ( UCAL_YEAR, -80, status );
-UDate
-IndianCalendar::internalGetDefaultCenturyStart() const
-{
- // lazy-evaluate systemDefaultCenturyStart
- UBool needsUpdate;
- {
- Mutex m;
- needsUpdate = (fgSystemDefaultCenturyStart == fgSystemDefaultCentury);
- }
+ UDate newStart = calendar.getTime ( status );
+ int32_t newYear = calendar.get ( UCAL_YEAR, status );
- if (needsUpdate) {
- initializeSystemDefaultCentury();
+ gSystemDefaultCenturyStart = newStart;
+ gSystemDefaultCenturyStartYear = newYear;
}
+ // We have no recourse upon failure.
+}
- // use defaultCenturyStart unless it's the flag value;
- // then use systemDefaultCenturyStart
- return fgSystemDefaultCenturyStart;
+UDate
+IndianCalendar::defaultCenturyStart() const
+{
+ // lazy-evaluate systemDefaultCenturyStart
+ umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
+ return gSystemDefaultCenturyStart;
}
int32_t
-IndianCalendar::internalGetDefaultCenturyStartYear() const
+IndianCalendar::defaultCenturyStartYear() const
{
// lazy-evaluate systemDefaultCenturyStartYear
- UBool needsUpdate;
- {
- Mutex m;
-
- needsUpdate = (fgSystemDefaultCenturyStart == fgSystemDefaultCentury);
- }
-
- if (needsUpdate) {
- initializeSystemDefaultCentury();
- }
-
- // use defaultCenturyStart unless it's the flag value;
- // then use systemDefaultCenturyStartYear
-
- return fgSystemDefaultCenturyStartYear;
+ umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
+ return gSystemDefaultCenturyStartYear;
}
-void
-IndianCalendar::initializeSystemDefaultCentury()
-{
- // initialize systemDefaultCentury and systemDefaultCenturyYear based
- // on the current time. They'll be set to 80 years before
- // the current time.
- // No point in locking as it should be idempotent.
- if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury) {
- UErrorCode status = U_ZERO_ERROR;
-
- IndianCalendar calendar(Locale("@calendar=Indian"),status);
- if (U_SUCCESS(status)) {
- calendar.setTime(Calendar::getNow(), status);
- calendar.add(UCAL_YEAR, -80, status);
-
- UDate newStart = calendar.getTime(status);
- int32_t newYear = calendar.get(UCAL_YEAR, status);
-
- {
- Mutex m;
-
- fgSystemDefaultCenturyStart = newStart;
- fgSystemDefaultCenturyStartYear = newYear;
- }
- }
-
- // We have no recourse upon failure unless we want to propagate the failure
- // out.
- }
-}
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IndianCalendar)
diff --git a/deps/icu-small/source/i18n/indiancal.h b/deps/icu-small/source/i18n/indiancal.h
index d40af5ad45..ffd4ae8b8a 100644
--- a/deps/icu-small/source/i18n/indiancal.h
+++ b/deps/icu-small/source/i18n/indiancal.h
@@ -68,7 +68,7 @@ U_NAMESPACE_BEGIN
*/
-class IndianCalendar : public Calendar {
+class U_I18N_API IndianCalendar : public Calendar {
public:
/**
* Useful constants for IndianCalendar.
@@ -274,10 +274,10 @@ public:
* @return The class ID for all objects of this class.
* @internal
*/
- U_I18N_API static UClassID U_EXPORT2 getStaticClassID(void);
+ static UClassID U_EXPORT2 getStaticClassID(void);
/**
- * return the calendar type, "buddhist".
+ * return the calendar type, "indian".
*
* @return calendar type
* @internal
@@ -320,49 +320,6 @@ protected:
* @internal
*/
virtual int32_t defaultCenturyStartYear() const;
-
- private: // default century stuff.
- /**
- * The system maintains a static default century start date. This is initialized
- * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to
- * indicate an uninitialized state. Once the system default century date and year
- * are set, they do not change.
- */
- static UDate fgSystemDefaultCenturyStart;
-
- /**
- * See documentation for systemDefaultCenturyStart.
- */
- static int32_t fgSystemDefaultCenturyStartYear;
-
- /**
- * Default value that indicates the defaultCenturyStartYear is unitialized
- */
- static const int32_t fgSystemDefaultCenturyYear;
-
- /**
- * start of default century, as a date
- */
- static const UDate fgSystemDefaultCentury;
-
- /**
- * Returns the beginning date of the 100-year window that dates
- * with 2-digit years are considered to fall within.
- */
- UDate internalGetDefaultCenturyStart(void) const;
-
- /**
- * Returns the first year of the 100-year window that dates with
- * 2-digit years are considered to fall within.
- */
- int32_t internalGetDefaultCenturyStartYear(void) const;
-
- /**
- * Initializes the 100-year window that dates with 2-digit years
- * are considered to fall within so that its start date is 80 years
- * before the current time.
- */
- static void initializeSystemDefaultCentury(void);
};
U_NAMESPACE_END
diff --git a/deps/icu-small/source/i18n/japancal.cpp b/deps/icu-small/source/i18n/japancal.cpp
index a2738e86a9..056781617d 100644
--- a/deps/icu-small/source/i18n/japancal.cpp
+++ b/deps/icu-small/source/i18n/japancal.cpp
@@ -16,286 +16,88 @@
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
-
+#if U_PLATFORM_HAS_WINUWP_API == 0
+#include <stdlib.h> // getenv() is not available in UWP env
+#endif
#include "cmemory.h"
+#include "erarules.h"
#include "japancal.h"
#include "unicode/gregocal.h"
#include "umutex.h"
#include "uassert.h"
-
-//#define U_DEBUG_JCAL
-
-#ifdef U_DEBUG_JCAL
-#include <stdio.h>
-#endif
+#include "ucln_in.h"
+#include "cstring.h"
+
+static icu::EraRules * gJapaneseEraRules = nullptr;
+static icu::UInitOnce gJapaneseEraRulesInitOnce = U_INITONCE_INITIALIZER;
+static int32_t gCurrentEra = 0;
+
+U_CDECL_BEGIN
+static UBool japanese_calendar_cleanup(void) {
+ if (gJapaneseEraRules) {
+ delete gJapaneseEraRules;
+ gJapaneseEraRules = nullptr;
+ }
+ gCurrentEra = 0;
+ gJapaneseEraRulesInitOnce.reset();
+ return TRUE;
+}
+U_CDECL_END
U_NAMESPACE_BEGIN
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(JapaneseCalendar)
-// Gregorian date of each emperor's ascension
-// Years are AD, months are 1-based.
-static const struct {
- int16_t year;
- int8_t month;
- int8_t day;
-} kEraInfo[] = {
- // Year Month Day
- { 645, 6, 19 }, // Taika 0
- { 650, 2, 15 }, // Hakuchi 1
- { 672, 1, 1 }, // Hakuho 2
- { 686, 7, 20 }, // Shucho 3
- { 701, 3, 21 }, // Taiho 4
- { 704, 5, 10 }, // Keiun 5
- { 708, 1, 11 }, // Wado 6
- { 715, 9, 2 }, // Reiki 7
- { 717, 11, 17 }, // Yoro 8
- { 724, 2, 4 }, // Jinki 9
- { 729, 8, 5 }, // Tempyo 10
- { 749, 4, 14 }, // Tempyo-kampo 11
- { 749, 7, 2 }, // Tempyo-shoho 12
- { 757, 8, 18 }, // Tempyo-hoji 13
- { 765, 1, 7 }, // Tempho-jingo 14
- { 767, 8, 16 }, // Jingo-keiun 15
- { 770, 10, 1 }, // Hoki 16
- { 781, 1, 1 }, // Ten-o 17
- { 782, 8, 19 }, // Enryaku 18
- { 806, 5, 18 }, // Daido 19
- { 810, 9, 19 }, // Konin 20
- { 824, 1, 5 }, // Tencho
- { 834, 1, 3 }, // Showa
- { 848, 6, 13 }, // Kajo
- { 851, 4, 28 }, // Ninju
- { 854, 11, 30 }, // Saiko
- { 857, 2, 21 }, // Tennan
- { 859, 4, 15 }, // Jogan
- { 877, 4, 16 }, // Genkei
- { 885, 2, 21 }, // Ninna
- { 889, 4, 27 }, // Kampyo 30
- { 898, 4, 26 }, // Shotai
- { 901, 7, 15 }, // Engi
- { 923, 4, 11 }, // Encho
- { 931, 4, 26 }, // Shohei
- { 938, 5, 22 }, // Tengyo
- { 947, 4, 22 }, // Tenryaku
- { 957, 10, 27 }, // Tentoku
- { 961, 2, 16 }, // Owa
- { 964, 7, 10 }, // Koho
- { 968, 8, 13 }, // Anna 40
- { 970, 3, 25 }, // Tenroku
- { 973, 12, 20 }, // Ten-en
- { 976, 7, 13 }, // Jogen
- { 978, 11, 29 }, // Tengen
- { 983, 4, 15 }, // Eikan
- { 985, 4, 27 }, // Kanna
- { 987, 4, 5 }, // Ei-en
- { 989, 8, 8 }, // Eiso
- { 990, 11, 7 }, // Shoryaku
- { 995, 2, 22 }, // Chotoku 50
- { 999, 1, 13 }, // Choho
- { 1004, 7, 20 }, // Kanko
- { 1012, 12, 25 }, // Chowa
- { 1017, 4, 23 }, // Kannin
- { 1021, 2, 2 }, // Jian
- { 1024, 7, 13 }, // Manju
- { 1028, 7, 25 }, // Chogen
- { 1037, 4, 21 }, // Choryaku
- { 1040, 11, 10 }, // Chokyu
- { 1044, 11, 24 }, // Kantoku 60
- { 1046, 4, 14 }, // Eisho
- { 1053, 1, 11 }, // Tengi
- { 1058, 8, 29 }, // Kohei
- { 1065, 8, 2 }, // Jiryaku
- { 1069, 4, 13 }, // Enkyu
- { 1074, 8, 23 }, // Shoho
- { 1077, 11, 17 }, // Shoryaku
- { 1081, 2, 10 }, // Eiho
- { 1084, 2, 7 }, // Otoku
- { 1087, 4, 7 }, // Kanji 70
- { 1094, 12, 15 }, // Kaho
- { 1096, 12, 17 }, // Eicho
- { 1097, 11, 21 }, // Shotoku
- { 1099, 8, 28 }, // Kowa
- { 1104, 2, 10 }, // Choji
- { 1106, 4, 9 }, // Kasho
- { 1108, 8, 3 }, // Tennin
- { 1110, 7, 13 }, // Ten-ei
- { 1113, 7, 13 }, // Eikyu
- { 1118, 4, 3 }, // Gen-ei 80
- { 1120, 4, 10 }, // Hoan
- { 1124, 4, 3 }, // Tenji
- { 1126, 1, 22 }, // Daiji
- { 1131, 1, 29 }, // Tensho
- { 1132, 8, 11 }, // Chosho
- { 1135, 4, 27 }, // Hoen
- { 1141, 7, 10 }, // Eiji
- { 1142, 4, 28 }, // Koji
- { 1144, 2, 23 }, // Tenyo
- { 1145, 7, 22 }, // Kyuan 90
- { 1151, 1, 26 }, // Ninpei
- { 1154, 10, 28 }, // Kyuju
- { 1156, 4, 27 }, // Hogen
- { 1159, 4, 20 }, // Heiji
- { 1160, 1, 10 }, // Eiryaku
- { 1161, 9, 4 }, // Oho
- { 1163, 3, 29 }, // Chokan
- { 1165, 6, 5 }, // Eiman
- { 1166, 8, 27 }, // Nin-an
- { 1169, 4, 8 }, // Kao 100
- { 1171, 4, 21 }, // Shoan
- { 1175, 7, 28 }, // Angen
- { 1177, 8, 4 }, // Jisho
- { 1181, 7, 14 }, // Yowa
- { 1182, 5, 27 }, // Juei
- { 1184, 4, 16 }, // Genryuku
- { 1185, 8, 14 }, // Bunji
- { 1190, 4, 11 }, // Kenkyu
- { 1199, 4, 27 }, // Shoji
- { 1201, 2, 13 }, // Kennin 110
- { 1204, 2, 20 }, // Genkyu
- { 1206, 4, 27 }, // Ken-ei
- { 1207, 10, 25 }, // Shogen
- { 1211, 3, 9 }, // Kenryaku
- { 1213, 12, 6 }, // Kenpo
- { 1219, 4, 12 }, // Shokyu
- { 1222, 4, 13 }, // Joo
- { 1224, 11, 20 }, // Gennin
- { 1225, 4, 20 }, // Karoku
- { 1227, 12, 10 }, // Antei 120
- { 1229, 3, 5 }, // Kanki
- { 1232, 4, 2 }, // Joei
- { 1233, 4, 15 }, // Tempuku
- { 1234, 11, 5 }, // Bunryaku
- { 1235, 9, 19 }, // Katei
- { 1238, 11, 23 }, // Ryakunin
- { 1239, 2, 7 }, // En-o
- { 1240, 7, 16 }, // Ninji
- { 1243, 2, 26 }, // Kangen
- { 1247, 2, 28 }, // Hoji 130
- { 1249, 3, 18 }, // Kencho
- { 1256, 10, 5 }, // Kogen
- { 1257, 3, 14 }, // Shoka
- { 1259, 3, 26 }, // Shogen
- { 1260, 4, 13 }, // Bun-o
- { 1261, 2, 20 }, // Kocho
- { 1264, 2, 28 }, // Bun-ei
- { 1275, 4, 25 }, // Kenji
- { 1278, 2, 29 }, // Koan
- { 1288, 4, 28 }, // Shoo 140
- { 1293, 8, 55 }, // Einin
- { 1299, 4, 25 }, // Shoan
- { 1302, 11, 21 }, // Kengen
- { 1303, 8, 5 }, // Kagen
- { 1306, 12, 14 }, // Tokuji
- { 1308, 10, 9 }, // Enkei
- { 1311, 4, 28 }, // Ocho
- { 1312, 3, 20 }, // Showa
- { 1317, 2, 3 }, // Bunpo
- { 1319, 4, 28 }, // Geno 150
- { 1321, 2, 23 }, // Genkyo
- { 1324, 12, 9 }, // Shochu
- { 1326, 4, 26 }, // Kareki
- { 1329, 8, 29 }, // Gentoku
- { 1331, 8, 9 }, // Genko
- { 1334, 1, 29 }, // Kemmu
- { 1336, 2, 29 }, // Engen
- { 1340, 4, 28 }, // Kokoku
- { 1346, 12, 8 }, // Shohei
- { 1370, 7, 24 }, // Kentoku 160
- { 1372, 4, 1 }, // Bunch\u0169
- { 1375, 5, 27 }, // Tenju
- { 1379, 3, 22 }, // Koryaku
- { 1381, 2, 10 }, // Kowa
- { 1384, 4, 28 }, // Gench\u0169
- { 1384, 2, 27 }, // Meitoku
- { 1387, 8, 23 }, // Kakei
- { 1389, 2, 9 }, // Koo
- { 1390, 3, 26 }, // Meitoku
- { 1394, 7, 5 }, // Oei 170
- { 1428, 4, 27 }, // Shocho
- { 1429, 9, 5 }, // Eikyo
- { 1441, 2, 17 }, // Kakitsu
- { 1444, 2, 5 }, // Bun-an
- { 1449, 7, 28 }, // Hotoku
- { 1452, 7, 25 }, // Kyotoku
- { 1455, 7, 25 }, // Kosho
- { 1457, 9, 28 }, // Choroku
- { 1460, 12, 21 }, // Kansho
- { 1466, 2, 28 }, // Bunsho 180
- { 1467, 3, 3 }, // Onin
- { 1469, 4, 28 }, // Bunmei
- { 1487, 7, 29 }, // Chokyo
- { 1489, 8, 21 }, // Entoku
- { 1492, 7, 19 }, // Meio
- { 1501, 2, 29 }, // Bunki
- { 1504, 2, 30 }, // Eisho
- { 1521, 8, 23 }, // Taiei
- { 1528, 8, 20 }, // Kyoroku
- { 1532, 7, 29 }, // Tenmon 190
- { 1555, 10, 23 }, // Koji
- { 1558, 2, 28 }, // Eiroku
- { 1570, 4, 23 }, // Genki
- { 1573, 7, 28 }, // Tensho
- { 1592, 12, 8 }, // Bunroku
- { 1596, 10, 27 }, // Keicho
- { 1615, 7, 13 }, // Genwa
- { 1624, 2, 30 }, // Kan-ei
- { 1644, 12, 16 }, // Shoho
- { 1648, 2, 15 }, // Keian 200
- { 1652, 9, 18 }, // Shoo
- { 1655, 4, 13 }, // Meiryaku
- { 1658, 7, 23 }, // Manji
- { 1661, 4, 25 }, // Kanbun
- { 1673, 9, 21 }, // Enpo
- { 1681, 9, 29 }, // Tenwa
- { 1684, 2, 21 }, // Jokyo
- { 1688, 9, 30 }, // Genroku
- { 1704, 3, 13 }, // Hoei
- { 1711, 4, 25 }, // Shotoku 210
- { 1716, 6, 22 }, // Kyoho
- { 1736, 4, 28 }, // Genbun
- { 1741, 2, 27 }, // Kanpo
- { 1744, 2, 21 }, // Enkyo
- { 1748, 7, 12 }, // Kan-en
- { 1751, 10, 27 }, // Horyaku
- { 1764, 6, 2 }, // Meiwa
- { 1772, 11, 16 }, // An-ei
- { 1781, 4, 2 }, // Tenmei
- { 1789, 1, 25 }, // Kansei 220
- { 1801, 2, 5 }, // Kyowa
- { 1804, 2, 11 }, // Bunka
- { 1818, 4, 22 }, // Bunsei
- { 1830, 12, 10 }, // Tenpo
- { 1844, 12, 2 }, // Koka
- { 1848, 2, 28 }, // Kaei
- { 1854, 11, 27 }, // Ansei
- { 1860, 3, 18 }, // Man-en
- { 1861, 2, 19 }, // Bunkyu
- { 1864, 2, 20 }, // Genji 230
- { 1865, 4, 7 }, // Keio 231
- { 1868, 9, 8 }, // Meiji 232
- { 1912, 7, 30 }, // Taisho 233
- { 1926, 12, 25 }, // Showa 234
- { 1989, 1, 8 } // Heisei 235
-};
-
-#define kEraCount UPRV_LENGTHOF(kEraInfo)
-
-/**
- * The current era, for reference.
- */
-static const int32_t kCurrentEra = (kEraCount-1); // int32_t to match the calendar field type
-
static const int32_t kGregorianEpoch = 1970; // used as the default value of EXTENDED_YEAR
+static const char* TENTATIVE_ERA_VAR_NAME = "ICU_ENABLE_TENTATIVE_ERA";
+
+// Initialize global Japanese era data
+static void U_CALLCONV initializeEras(UErrorCode &status) {
+ // Although start date of next Japanese era is planned ahead, a name of
+ // new era might not be available. This implementation allows tester to
+ // check a new era without era names by settings below (in priority order).
+ // By default, such tentative era is disabled.
+
+ // 1. Environment variable ICU_ENABLE_TENTATIVE_ERA=true or false
+
+ UBool includeTentativeEra = FALSE;
+
+#if U_PLATFORM_HAS_WINUWP_API == 1
+ // UWP doesn't allow access to getenv(), but we can call GetEnvironmentVariableW to do the same thing.
+ UChar varName[26] = {};
+ u_charsToUChars(TENTATIVE_ERA_VAR_NAME, varName, static_cast<int32_t>(uprv_strlen(TENTATIVE_ERA_VAR_NAME)));
+ WCHAR varValue[5] = {};
+ DWORD ret = GetEnvironmentVariableW(reinterpret_cast<WCHAR*>(varName), varValue, UPRV_LENGTHOF(varValue));
+ if ((ret == 4) && (_wcsicmp(varValue, L"true") == 0)) {
+ includeTentativeEra = TRUE;
+ }
+#else
+ char *envVarVal = getenv(TENTATIVE_ERA_VAR_NAME);
+ if (envVarVal != NULL && uprv_stricmp(envVarVal, "true") == 0) {
+ includeTentativeEra = TRUE;
+ }
+#endif
+ gJapaneseEraRules = EraRules::createInstance("japanese", includeTentativeEra, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ gCurrentEra = gJapaneseEraRules->getCurrentEraIndex();
+}
+
+static void init(UErrorCode &status) {
+ umtx_initOnce(gJapaneseEraRulesInitOnce, &initializeEras, status);
+ ucln_i18n_registerCleanup(UCLN_I18N_JAPANESE_CALENDAR, japanese_calendar_cleanup);
+}
/* Some platforms don't like to export constants, like old Palm OS and some z/OS configurations. */
uint32_t JapaneseCalendar::getCurrentEra() {
- return kCurrentEra;
+ return gCurrentEra;
}
JapaneseCalendar::JapaneseCalendar(const Locale& aLocale, UErrorCode& success)
: GregorianCalendar(aLocale, success)
{
+ init(success);
setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
}
@@ -306,6 +108,9 @@ JapaneseCalendar::~JapaneseCalendar()
JapaneseCalendar::JapaneseCalendar(const JapaneseCalendar& source)
: GregorianCalendar(source)
{
+ UErrorCode status = U_ZERO_ERROR;
+ init(status);
+ U_ASSERT(U_SUCCESS(status));
}
JapaneseCalendar& JapaneseCalendar::operator= ( const JapaneseCalendar& right)
@@ -332,10 +137,14 @@ int32_t JapaneseCalendar::getDefaultMonthInYear(int32_t eyear)
int32_t month = 0;
// Find out if we are at the edge of an era
-
- if(eyear == kEraInfo[era].year) {
+ int32_t eraStart[3] = { 0,0,0 };
+ UErrorCode status = U_ZERO_ERROR;
+ gJapaneseEraRules->getStartDate(era, eraStart, status);
+ U_ASSERT(U_SUCCESS(status));
+ if(eyear == eraStart[0]) {
// Yes, we're in the first year of this era.
- return kEraInfo[era].month-1;
+ return eraStart[1] // month
+ -1; // return 0-based month
}
return month;
@@ -346,9 +155,13 @@ int32_t JapaneseCalendar::getDefaultDayInMonth(int32_t eyear, int32_t month)
int32_t era = internalGetEra();
int32_t day = 1;
- if(eyear == kEraInfo[era].year) {
- if(month == (kEraInfo[era].month-1)) {
- return kEraInfo[era].day;
+ int32_t eraStart[3] = { 0,0,0 };
+ UErrorCode status = U_ZERO_ERROR;
+ gJapaneseEraRules->getStartDate(era, eraStart, status);
+ U_ASSERT(U_SUCCESS(status));
+ if(eyear == eraStart[0]) {
+ if(month == eraStart[1] - 1) {
+ return eraStart[2];
}
}
@@ -358,7 +171,7 @@ int32_t JapaneseCalendar::getDefaultDayInMonth(int32_t eyear, int32_t month)
int32_t JapaneseCalendar::internalGetEra() const
{
- return internalGet(UCAL_ERA, kCurrentEra);
+ return internalGet(UCAL_ERA, gCurrentEra);
}
int32_t JapaneseCalendar::handleGetExtendedYear()
@@ -369,12 +182,18 @@ int32_t JapaneseCalendar::handleGetExtendedYear()
if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR &&
newerField(UCAL_EXTENDED_YEAR, UCAL_ERA) == UCAL_EXTENDED_YEAR) {
- year = internalGet(UCAL_EXTENDED_YEAR, kGregorianEpoch);
- } else {
- // Subtract one because year starts at 1
- year = internalGet(UCAL_YEAR) + kEraInfo[internalGetEra()].year - 1;
- }
- return year;
+ year = internalGet(UCAL_EXTENDED_YEAR, kGregorianEpoch);
+ } else {
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t eraStartYear = gJapaneseEraRules->getStartYear(internalGet(UCAL_ERA, gCurrentEra), status);
+ U_ASSERT(U_SUCCESS(status));
+
+ // extended year is a gregorian year, where 1 = 1AD, 0 = 1BC, -1 = 2BC, etc
+ year = internalGet(UCAL_YEAR, 1) // pin to minimum of year 1 (first year)
+ + eraStartYear // add gregorian starting year
+ - 1; // Subtract one because year starts at 1
+ }
+ return year;
}
@@ -383,79 +202,10 @@ void JapaneseCalendar::handleComputeFields(int32_t julianDay, UErrorCode& status
//Calendar::timeToFields(theTime, quick, status);
GregorianCalendar::handleComputeFields(julianDay, status);
int32_t year = internalGet(UCAL_EXTENDED_YEAR); // Gregorian year
+ int32_t eraIdx = gJapaneseEraRules->getEraIndex(year, internalGet(UCAL_MONTH) + 1, internalGet(UCAL_DAY_OF_MONTH), status);
- int32_t low = 0;
-
- // Short circuit for recent years. Most modern computations will
- // occur in the current era and won't require the binary search.
- // Note that if the year is == the current era year, then we use
- // the binary search to handle the month/dom comparison.
-#ifdef U_DEBUG_JCAL
- fprintf(stderr, "== %d \n", year);
-#endif
-
- if (year > kEraInfo[kCurrentEra].year) {
- low = kCurrentEra;
-#ifdef U_DEBUG_JCAL
- fprintf(stderr, " low=%d (special)\n", low);
-#endif
- } else {
- // Binary search
- int32_t high = kEraCount;
-
-#ifdef U_DEBUG_JCAL
- fprintf(stderr, " high=%d\n", high);
-#endif
- while (low < high - 1) {
- int32_t i = (low + high) / 2;
- int32_t diff = year - kEraInfo[i].year;
-
-#ifdef U_DEBUG_JCAL
- fprintf(stderr, " d=%d low=%d, high=%d. Considering %d:M%d D%d Y%d. { we are ?:M%d D%d Y%d }\n",
- diff,low, high, i, kEraInfo[i].month-1, kEraInfo[i].day, kEraInfo[i].year, internalGet(UCAL_MONTH), internalGet(UCAL_DATE),year);
-#endif
-
- // If years are the same, then compare the months, and if those
- // are the same, compare days of month. In the ERAS array
- // months are 1-based for easier maintenance.
- if (diff == 0) {
- diff = internalGet(UCAL_MONTH) - (kEraInfo[i].month - 1);
-#ifdef U_DEBUG_JCAL
- fprintf(stderr, "diff now %d (M) = %d - %d - 1\n", diff, internalGet(UCAL_MONTH), kEraInfo[i].month);
-#endif
- if (diff == 0) {
- diff = internalGet(UCAL_DATE) - kEraInfo[i].day;
-#ifdef U_DEBUG_JCAL
- fprintf(stderr, "diff now %d (D)\n", diff);
-#endif
- }
- }
- if (diff >= 0) {
- low = i;
- } else {
- high = i;
- }
-#ifdef U_DEBUG_JCAL
- fprintf(stderr, ". low=%d, high=%d, i=%d, diff=%d.. %d\n", low, high, i, diff, year);
-#endif
-
- }
- }
-
-#ifdef U_DEBUG_JCAL
- fprintf(stderr, " low[era]=%d,.. %d\n", low, year);
-#endif
- // Now we've found the last era that starts before this date, so
- // adjust the year to count from the start of that era. Note that
- // all dates before the first era will fall into the first era by
- // the algorithm.
-
- internalSet(UCAL_ERA, low);
- internalSet(UCAL_YEAR, year - kEraInfo[low].year + 1);
-#ifdef U_DEBUG_JCAL
- fprintf(stderr, " Set ERA=%d, year=%d\n", low, year-kEraInfo[low].year+1);
-#endif
-
+ internalSet(UCAL_ERA, eraIdx);
+ internalSet(UCAL_YEAR, year - gJapaneseEraRules->getStartYear(eraIdx, status) + 1);
}
/*
@@ -483,7 +233,7 @@ int32_t JapaneseCalendar::handleGetLimit(UCalendarDateFields field, ELimitType l
if (limitType == UCAL_LIMIT_MINIMUM || limitType == UCAL_LIMIT_GREATEST_MINIMUM) {
return 0;
}
- return kCurrentEra;
+ return gCurrentEra;
case UCAL_YEAR:
{
switch (limitType) {
@@ -494,7 +244,12 @@ int32_t JapaneseCalendar::handleGetLimit(UCalendarDateFields field, ELimitType l
return 1;
case UCAL_LIMIT_COUNT: //added to avoid warning
case UCAL_LIMIT_MAXIMUM:
- return GregorianCalendar::handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM) - kEraInfo[kCurrentEra].year;
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t eraStartYear = gJapaneseEraRules->getStartYear(gCurrentEra, status);
+ U_ASSERT(U_SUCCESS(status));
+ return GregorianCalendar::handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM) - eraStartYear;
+ }
default:
return 1; // Error condition, invalid limitType
}
@@ -510,15 +265,18 @@ int32_t JapaneseCalendar::getActualMaximum(UCalendarDateFields field, UErrorCode
if (U_FAILURE(status)) {
return 0; // error case... any value
}
- if (era == kCurrentEra) {
+ if (era == gCurrentEra) {
// TODO: Investigate what value should be used here - revisit after 4.0.
return handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM);
} else {
- int32_t nextEraYear = kEraInfo[era + 1].year;
- int32_t nextEraMonth = kEraInfo[era + 1].month;
- int32_t nextEraDate = kEraInfo[era + 1].day;
-
- int32_t maxYear = nextEraYear - kEraInfo[era].year + 1; // 1-base
+ int32_t nextEraStart[3] = { 0,0,0 };
+ gJapaneseEraRules->getStartDate(era + 1, nextEraStart, status);
+ int32_t nextEraYear = nextEraStart[0];
+ int32_t nextEraMonth = nextEraStart[1]; // 1-base
+ int32_t nextEraDate = nextEraStart[2];
+
+ int32_t eraStartYear = gJapaneseEraRules->getStartYear(era, status);
+ int32_t maxYear = nextEraYear - eraStartYear + 1; // 1-base
if (nextEraMonth == 1 && nextEraDate == 1) {
// Subtract 1, because the next era starts at Jan 1
maxYear--;
diff --git a/deps/icu-small/source/i18n/japancal.h b/deps/icu-small/source/i18n/japancal.h
index 356351d28d..67d2d70315 100644
--- a/deps/icu-small/source/i18n/japancal.h
+++ b/deps/icu-small/source/i18n/japancal.h
@@ -49,10 +49,18 @@ U_NAMESPACE_BEGIN
* July 30, 1912 (Taisho), December 25, 1926 (Showa), and January 7, 1989 (Heisei). Constants
* for these eras, suitable for use in the <code>UCAL_ERA</code> field, are provided
* in this class. Note that the <em>number</em> used for each era is more or
- * less arbitrary. Currently, the era starting in 1053 AD is era #0; however this
- * may change in the future as we add more historical data. Use the predefined
- * constants rather than using actual, absolute numbers.
+ * less arbitrary. Currently, the era starting in 645 AD is era #0; however this
+ * may change in the future. Use the predefined constants rather than using actual,
+ * absolute numbers.
* <p>
+ * Since ICU4C 63, start date of each era is imported from CLDR. CLDR era data
+ * may contain tentative era in near future with placeholder names. By default,
+ * such era data is not enabled. ICU4C users who want to test the behavior of
+ * the future era can enable this one of following settings (in the priority
+ * order):
+ * <ol>
+ * <li>Environment variable <code>ICU_ENABLE_TENTATIVE_ERA=true</code>.</li>
+ * </nl>
* @internal
*/
class JapaneseCalendar : public GregorianCalendar {
diff --git a/deps/icu-small/source/i18n/listformatter.cpp b/deps/icu-small/source/i18n/listformatter.cpp
new file mode 100644
index 0000000000..d919534852
--- /dev/null
+++ b/deps/icu-small/source/i18n/listformatter.cpp
@@ -0,0 +1,525 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/*
+*******************************************************************************
+*
+* Copyright (C) 2013-2016, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+*******************************************************************************
+* file name: listformatter.cpp
+* encoding: UTF-8
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2012aug27
+* created by: Umesh P. Nair
+*/
+
+#include "cmemory.h"
+#include "unicode/fpositer.h" // FieldPositionIterator
+#include "unicode/listformatter.h"
+#include "unicode/simpleformatter.h"
+#include "unicode/ulistformatter.h"
+#include "fphdlimp.h"
+#include "mutex.h"
+#include "hash.h"
+#include "cstring.h"
+#include "uarrsort.h"
+#include "ulocimp.h"
+#include "charstr.h"
+#include "ucln_in.h"
+#include "uresimp.h"
+#include "resource.h"
+
+U_NAMESPACE_BEGIN
+
+struct ListFormatInternal : public UMemory {
+ SimpleFormatter twoPattern;
+ SimpleFormatter startPattern;
+ SimpleFormatter middlePattern;
+ SimpleFormatter endPattern;
+
+ListFormatInternal(
+ const UnicodeString& two,
+ const UnicodeString& start,
+ const UnicodeString& middle,
+ const UnicodeString& end,
+ UErrorCode &errorCode) :
+ twoPattern(two, 2, 2, errorCode),
+ startPattern(start, 2, 2, errorCode),
+ middlePattern(middle, 2, 2, errorCode),
+ endPattern(end, 2, 2, errorCode) {}
+
+ListFormatInternal(const ListFormatData &data, UErrorCode &errorCode) :
+ twoPattern(data.twoPattern, errorCode),
+ startPattern(data.startPattern, errorCode),
+ middlePattern(data.middlePattern, errorCode),
+ endPattern(data.endPattern, errorCode) { }
+
+ListFormatInternal(const ListFormatInternal &other) :
+ twoPattern(other.twoPattern),
+ startPattern(other.startPattern),
+ middlePattern(other.middlePattern),
+ endPattern(other.endPattern) { }
+};
+
+
+
+static Hashtable* listPatternHash = nullptr;
+static UMutex listFormatterMutex = U_MUTEX_INITIALIZER;
+static const char STANDARD_STYLE[] = "standard";
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV uprv_listformatter_cleanup() {
+ delete listPatternHash;
+ listPatternHash = nullptr;
+ return TRUE;
+}
+
+static void U_CALLCONV
+uprv_deleteListFormatInternal(void *obj) {
+ delete static_cast<ListFormatInternal *>(obj);
+}
+
+U_CDECL_END
+
+ListFormatter::ListFormatter(const ListFormatter& other) :
+ owned(other.owned), data(other.data) {
+ if (other.owned != nullptr) {
+ owned = new ListFormatInternal(*other.owned);
+ data = owned;
+ }
+}
+
+ListFormatter& ListFormatter::operator=(const ListFormatter& other) {
+ if (this == &other) {
+ return *this;
+ }
+ delete owned;
+ if (other.owned) {
+ owned = new ListFormatInternal(*other.owned);
+ data = owned;
+ } else {
+ owned = nullptr;
+ data = other.data;
+ }
+ return *this;
+}
+
+void ListFormatter::initializeHash(UErrorCode& errorCode) {
+ if (U_FAILURE(errorCode)) {
+ return;
+ }
+
+ listPatternHash = new Hashtable();
+ if (listPatternHash == nullptr) {
+ errorCode = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ listPatternHash->setValueDeleter(uprv_deleteListFormatInternal);
+ ucln_i18n_registerCleanup(UCLN_I18N_LIST_FORMATTER, uprv_listformatter_cleanup);
+
+}
+
+const ListFormatInternal* ListFormatter::getListFormatInternal(
+ const Locale& locale, const char *style, UErrorCode& errorCode) {
+ if (U_FAILURE(errorCode)) {
+ return nullptr;
+ }
+ CharString keyBuffer(locale.getName(), errorCode);
+ keyBuffer.append(':', errorCode).append(style, errorCode);
+ UnicodeString key(keyBuffer.data(), -1, US_INV);
+ ListFormatInternal* result = nullptr;
+ {
+ Mutex m(&listFormatterMutex);
+ if (listPatternHash == nullptr) {
+ initializeHash(errorCode);
+ if (U_FAILURE(errorCode)) {
+ return nullptr;
+ }
+ }
+ result = static_cast<ListFormatInternal*>(listPatternHash->get(key));
+ }
+ if (result != nullptr) {
+ return result;
+ }
+ result = loadListFormatInternal(locale, style, errorCode);
+ if (U_FAILURE(errorCode)) {
+ return nullptr;
+ }
+
+ {
+ Mutex m(&listFormatterMutex);
+ ListFormatInternal* temp = static_cast<ListFormatInternal*>(listPatternHash->get(key));
+ if (temp != nullptr) {
+ delete result;
+ result = temp;
+ } else {
+ listPatternHash->put(key, result, errorCode);
+ if (U_FAILURE(errorCode)) {
+ return nullptr;
+ }
+ }
+ }
+ return result;
+}
+
+static const UChar solidus = 0x2F;
+static const UChar aliasPrefix[] = { 0x6C,0x69,0x73,0x74,0x50,0x61,0x74,0x74,0x65,0x72,0x6E,0x2F }; // "listPattern/"
+enum {
+ kAliasPrefixLen = UPRV_LENGTHOF(aliasPrefix),
+ kStyleLenMax = 24 // longest currently is 14
+};
+
+struct ListFormatter::ListPatternsSink : public ResourceSink {
+ UnicodeString two, start, middle, end;
+#if ((U_PLATFORM == U_PF_AIX) || (U_PLATFORM == U_PF_OS390)) && (U_CPLUSPLUS_VERSION < 11)
+ char aliasedStyle[kStyleLenMax+1];
+ ListPatternsSink() {
+ uprv_memset(aliasedStyle, 0, kStyleLenMax+1);
+ }
+#else
+ char aliasedStyle[kStyleLenMax+1] = {0};
+
+ ListPatternsSink() {}
+#endif
+ virtual ~ListPatternsSink();
+
+ void setAliasedStyle(UnicodeString alias) {
+ int32_t startIndex = alias.indexOf(aliasPrefix, kAliasPrefixLen, 0);
+ if (startIndex < 0) {
+ return;
+ }
+ startIndex += kAliasPrefixLen;
+ int32_t endIndex = alias.indexOf(solidus, startIndex);
+ if (endIndex < 0) {
+ endIndex = alias.length();
+ }
+ alias.extract(startIndex, endIndex-startIndex, aliasedStyle, kStyleLenMax+1, US_INV);
+ aliasedStyle[kStyleLenMax] = 0;
+ }
+
+ void handleValueForPattern(ResourceValue &value, UnicodeString &pattern, UErrorCode &errorCode) {
+ if (pattern.isEmpty()) {
+ if (value.getType() == URES_ALIAS) {
+ if (aliasedStyle[0] == 0) {
+ setAliasedStyle(value.getAliasUnicodeString(errorCode));
+ }
+ } else {
+ pattern = value.getUnicodeString(errorCode);
+ }
+ }
+ }
+
+ virtual void put(const char *key, ResourceValue &value, UBool /*noFallback*/,
+ UErrorCode &errorCode) {
+ aliasedStyle[0] = 0;
+ if (value.getType() == URES_ALIAS) {
+ setAliasedStyle(value.getAliasUnicodeString(errorCode));
+ return;
+ }
+ ResourceTable listPatterns = value.getTable(errorCode);
+ for (int i = 0; U_SUCCESS(errorCode) && listPatterns.getKeyAndValue(i, key, value); ++i) {
+ if (uprv_strcmp(key, "2") == 0) {
+ handleValueForPattern(value, two, errorCode);
+ } else if (uprv_strcmp(key, "end") == 0) {
+ handleValueForPattern(value, end, errorCode);
+ } else if (uprv_strcmp(key, "middle") == 0) {
+ handleValueForPattern(value, middle, errorCode);
+ } else if (uprv_strcmp(key, "start") == 0) {
+ handleValueForPattern(value, start, errorCode);
+ }
+ }
+ }
+};
+
+// Virtual destructors must be defined out of line.
+ListFormatter::ListPatternsSink::~ListPatternsSink() {}
+
+ListFormatInternal* ListFormatter::loadListFormatInternal(
+ const Locale& locale, const char * style, UErrorCode& errorCode) {
+ UResourceBundle* rb = ures_open(nullptr, locale.getName(), &errorCode);
+ rb = ures_getByKeyWithFallback(rb, "listPattern", rb, &errorCode);
+ if (U_FAILURE(errorCode)) {
+ ures_close(rb);
+ return nullptr;
+ }
+ ListFormatter::ListPatternsSink sink;
+ char currentStyle[kStyleLenMax+1];
+ uprv_strncpy(currentStyle, style, kStyleLenMax);
+ currentStyle[kStyleLenMax] = 0;
+
+ for (;;) {
+ ures_getAllItemsWithFallback(rb, currentStyle, sink, errorCode);
+ if (U_FAILURE(errorCode) || sink.aliasedStyle[0] == 0 || uprv_strcmp(currentStyle, sink.aliasedStyle) == 0) {
+ break;
+ }
+ uprv_strcpy(currentStyle, sink.aliasedStyle);
+ }
+ ures_close(rb);
+ if (U_FAILURE(errorCode)) {
+ return nullptr;
+ }
+ if (sink.two.isEmpty() || sink.start.isEmpty() || sink.middle.isEmpty() || sink.end.isEmpty()) {
+ errorCode = U_MISSING_RESOURCE_ERROR;
+ return nullptr;
+ }
+ ListFormatInternal* result = new ListFormatInternal(sink.two, sink.start, sink.middle, sink.end, errorCode);
+ if (result == nullptr) {
+ errorCode = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+ if (U_FAILURE(errorCode)) {
+ delete result;
+ return nullptr;
+ }
+ return result;
+}
+
+ListFormatter* ListFormatter::createInstance(UErrorCode& errorCode) {
+ Locale locale; // The default locale.
+ return createInstance(locale, errorCode);
+}
+
+ListFormatter* ListFormatter::createInstance(const Locale& locale, UErrorCode& errorCode) {
+ return createInstance(locale, STANDARD_STYLE, errorCode);
+}
+
+ListFormatter* ListFormatter::createInstance(const Locale& locale, const char *style, UErrorCode& errorCode) {
+ const ListFormatInternal* listFormatInternal = getListFormatInternal(locale, style, errorCode);
+ if (U_FAILURE(errorCode)) {
+ return nullptr;
+ }
+ ListFormatter* p = new ListFormatter(listFormatInternal);
+ if (p == nullptr) {
+ errorCode = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+ return p;
+}
+
+ListFormatter::ListFormatter(const ListFormatData& listFormatData, UErrorCode &errorCode) {
+ owned = new ListFormatInternal(listFormatData, errorCode);
+ data = owned;
+}
+
+ListFormatter::ListFormatter(const ListFormatInternal* listFormatterInternal) : owned(nullptr), data(listFormatterInternal) {
+}
+
+ListFormatter::~ListFormatter() {
+ delete owned;
+}
+
+/**
+ * Joins first and second using the pattern pat.
+ * 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. On exit, result is the join of first and second
+ * according to pat. Any previous value of result gets replaced.
+ */
+static void joinStringsAndReplace(
+ const SimpleFormatter& pat,
+ const UnicodeString& first,
+ const UnicodeString& second,
+ UnicodeString &result,
+ UBool recordOffset,
+ int32_t &offset,
+ int32_t *offsetFirst,
+ int32_t *offsetSecond,
+ UErrorCode& errorCode) {
+ if (U_FAILURE(errorCode)) {
+ return;
+ }
+ const UnicodeString *params[2] = {&first, &second};
+ int32_t offsets[2];
+ pat.formatAndReplace(
+ params,
+ UPRV_LENGTHOF(params),
+ result,
+ offsets,
+ UPRV_LENGTHOF(offsets),
+ errorCode);
+ if (U_FAILURE(errorCode)) {
+ return;
+ }
+ if (offsets[0] == -1 || offsets[1] == -1) {
+ errorCode = U_INVALID_FORMAT_ERROR;
+ return;
+ }
+ if (recordOffset) {
+ offset = offsets[1];
+ } else if (offset >= 0) {
+ offset += offsets[0];
+ }
+ if (offsetFirst != nullptr) *offsetFirst = offsets[0];
+ if (offsetSecond != nullptr) *offsetSecond = offsets[1];
+}
+
+UnicodeString& ListFormatter::format(
+ const UnicodeString items[],
+ int32_t nItems,
+ UnicodeString& appendTo,
+ UErrorCode& errorCode) const {
+ int32_t offset;
+ return format(items, nItems, appendTo, -1, offset, errorCode);
+}
+
+#if !UCONFIG_NO_FORMATTING
+UnicodeString& ListFormatter::format(
+ const UnicodeString items[],
+ int32_t nItems,
+ UnicodeString & appendTo,
+ FieldPositionIterator* posIter,
+ UErrorCode& errorCode) const {
+ int32_t offset;
+ FieldPositionIteratorHandler handler(posIter, errorCode);
+ return format_(items, nItems, appendTo, -1, offset, &handler, errorCode);
+};
+#endif
+
+UnicodeString& ListFormatter::format(
+ const UnicodeString items[],
+ int32_t nItems,
+ UnicodeString& appendTo,
+ int32_t index,
+ int32_t &offset,
+ UErrorCode& errorCode) const {
+ return format_(items, nItems, appendTo, index, offset, nullptr, errorCode);
+}
+
+UnicodeString& ListFormatter::format_(
+ const UnicodeString items[],
+ int32_t nItems,
+ UnicodeString& appendTo,
+ int32_t index,
+ int32_t &offset,
+ FieldPositionHandler* handler,
+ UErrorCode& errorCode) const {
+#if !UCONFIG_NO_FORMATTING
+ offset = -1;
+ if (U_FAILURE(errorCode)) {
+ return appendTo;
+ }
+ if (data == nullptr) {
+ errorCode = U_INVALID_STATE_ERROR;
+ return appendTo;
+ }
+
+ if (nItems <= 0) {
+ return appendTo;
+ }
+ if (nItems == 1) {
+ if (index == 0) {
+ offset = appendTo.length();
+ }
+ if (handler != nullptr) {
+ handler->addAttribute(ULISTFMT_ELEMENT_FIELD,
+ appendTo.length(),
+ appendTo.length() + items[0].length());
+ }
+ appendTo.append(items[0]);
+ return appendTo;
+ }
+ UnicodeString result(items[0]);
+ if (index == 0) {
+ offset = 0;
+ }
+ int32_t offsetFirst;
+ int32_t offsetSecond;
+ int32_t prefixLength = 0;
+ // for n items, there are 2 * (n + 1) boundary including 0 and the upper
+ // edge.
+ MaybeStackArray<int32_t, 10> offsets((handler != nullptr) ? 2 * (nItems + 1): 0);
+ joinStringsAndReplace(
+ nItems == 2 ? data->twoPattern : data->startPattern,
+ result,
+ items[1],
+ result,
+ index == 1,
+ offset,
+ &offsetFirst,
+ &offsetSecond,
+ errorCode);
+ if (handler != nullptr) {
+ offsets[0] = 0;
+ prefixLength += offsetFirst;
+ offsets[1] = offsetSecond - prefixLength;
+ }
+ if (nItems > 2) {
+ for (int32_t i = 2; i < nItems - 1; ++i) {
+ joinStringsAndReplace(
+ data->middlePattern,
+ result,
+ items[i],
+ result,
+ index == i,
+ offset,
+ &offsetFirst,
+ &offsetSecond,
+ errorCode);
+ if (handler != nullptr) {
+ prefixLength += offsetFirst;
+ offsets[i] = offsetSecond - prefixLength;
+ }
+ }
+ joinStringsAndReplace(
+ data->endPattern,
+ result,
+ items[nItems - 1],
+ result,
+ index == nItems - 1,
+ offset,
+ &offsetFirst,
+ &offsetSecond,
+ errorCode);
+ if (handler != nullptr) {
+ prefixLength += offsetFirst;
+ offsets[nItems - 1] = offsetSecond - prefixLength;
+ }
+ }
+ if (handler != nullptr) {
+ // If there are already some data in appendTo, we need to adjust the index
+ // by shifting that lenght while insert into handler.
+ int32_t shift = appendTo.length() + prefixLength;
+ // Output the ULISTFMT_ELEMENT_FIELD in the order of the input elements
+ for (int32_t i = 0; i < nItems; ++i) {
+ offsets[i + nItems] = offsets[i] + items[i].length() + shift;
+ offsets[i] += shift;
+ handler->addAttribute(
+ ULISTFMT_ELEMENT_FIELD, // id
+ offsets[i], // index
+ offsets[i + nItems]); // limit
+ }
+ // The locale pattern may reorder the items (such as in ur-IN locale),
+ // so we cannot assume the array is in accendning order.
+ // To handle the edging case, just insert the two ends into the array
+ // and sort. Then we output ULISTFMT_LITERAL_FIELD if the indecies
+ // between the even and odd position are not the same in the sorted array.
+ offsets[2 * nItems] = shift - prefixLength;
+ offsets[2 * nItems + 1] = result.length() + shift - prefixLength;
+ uprv_sortArray(offsets.getAlias(), 2 * (nItems + 1), sizeof(int32_t),
+ uprv_int32Comparator, nullptr,
+ false, &errorCode);
+ for (int32_t i = 0; i <= nItems; ++i) {
+ if (offsets[i * 2] != offsets[i * 2 + 1]) {
+ handler->addAttribute(
+ ULISTFMT_LITERAL_FIELD, // id
+ offsets[i * 2], // index
+ offsets[i * 2 + 1]); // limit
+ }
+ }
+ }
+ if (U_SUCCESS(errorCode)) {
+ if (offset >= 0) {
+ offset += appendTo.length();
+ }
+ appendTo += result;
+ }
+#endif
+ return appendTo;
+}
+
+U_NAMESPACE_END
diff --git a/deps/icu-small/source/i18n/measfmt.cpp b/deps/icu-small/source/i18n/measfmt.cpp
index 996a20c2e0..03974ff4b7 100644
--- a/deps/icu-small/source/i18n/measfmt.cpp
+++ b/deps/icu-small/source/i18n/measfmt.cpp
@@ -47,7 +47,7 @@ U_NAMESPACE_BEGIN
static constexpr int32_t PER_UNIT_INDEX = StandardPlural::COUNT;
static constexpr int32_t PATTERN_COUNT = PER_UNIT_INDEX + 1;
-static constexpr int32_t MEAS_UNIT_COUNT = 138; // see assertion in MeasureFormatCacheData constructor
+static constexpr int32_t MEAS_UNIT_COUNT = 142; // see assertion in MeasureFormatCacheData constructor
static constexpr int32_t WIDTH_INDEX_COUNT = UMEASFMT_WIDTH_NARROW + 1;
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MeasureFormat)
@@ -618,7 +618,7 @@ MeasureFormat::MeasureFormat(
: cache(NULL),
numberFormat(NULL),
pluralRules(NULL),
- width(w),
+ fWidth(w),
listFormatter(NULL) {
initMeasureFormat(locale, w, NULL, status);
}
@@ -631,7 +631,7 @@ MeasureFormat::MeasureFormat(
: cache(NULL),
numberFormat(NULL),
pluralRules(NULL),
- width(w),
+ fWidth(w),
listFormatter(NULL) {
initMeasureFormat(locale, w, nfToAdopt, status);
}
@@ -641,7 +641,7 @@ MeasureFormat::MeasureFormat(const MeasureFormat &other) :
cache(other.cache),
numberFormat(other.numberFormat),
pluralRules(other.pluralRules),
- width(other.width),
+ fWidth(other.fWidth),
listFormatter(NULL) {
cache->addRef();
numberFormat->addRef();
@@ -659,7 +659,7 @@ MeasureFormat &MeasureFormat::operator=(const MeasureFormat &other) {
SharedObject::copyPtr(other.cache, cache);
SharedObject::copyPtr(other.numberFormat, numberFormat);
SharedObject::copyPtr(other.pluralRules, pluralRules);
- width = other.width;
+ fWidth = other.fWidth;
delete listFormatter;
if (other.listFormatter != NULL) {
listFormatter = new ListFormatter(*other.listFormatter);
@@ -673,7 +673,7 @@ MeasureFormat::MeasureFormat() :
cache(NULL),
numberFormat(NULL),
pluralRules(NULL),
- width(UMEASFMT_WIDTH_SHORT),
+ fWidth(UMEASFMT_WIDTH_SHORT),
listFormatter(NULL) {
}
@@ -703,7 +703,7 @@ UBool MeasureFormat::operator==(const Format &other) const {
// don't have to check it here.
// differing widths aren't equivalent
- if (width != rhs.width) {
+ if (fWidth != rhs.fWidth) {
return FALSE;
}
// Width the same check locales.
@@ -805,7 +805,7 @@ UnicodeString &MeasureFormat::formatMeasures(
if (measureCount == 1) {
return formatMeasure(measures[0], **numberFormat, appendTo, pos, status);
}
- if (width == UMEASFMT_WIDTH_NUMERIC) {
+ if (fWidth == UMEASFMT_WIDTH_NUMERIC) {
Formattable hms[3];
int32_t bitMap = toHMS(measures, measureCount, hms, status);
if (bitMap > 0) {
@@ -839,7 +839,7 @@ UnicodeString &MeasureFormat::formatMeasures(
}
UnicodeString MeasureFormat::getUnitDisplayName(const MeasureUnit& unit, UErrorCode& /*status*/) const {
- UMeasureFormatWidth width = getRegularWidth(this->width);
+ UMeasureFormatWidth width = getRegularWidth(fWidth);
const UChar* const* styleToDnam = cache->dnams[unit.getIndex()];
const UChar* dnam = styleToDnam[width];
if (dnam == NULL) {
@@ -895,11 +895,11 @@ void MeasureFormat::initMeasureFormat(
return;
}
}
- width = w;
+ fWidth = w;
delete listFormatter;
listFormatter = ListFormatter::createInstance(
locale,
- listStyles[getRegularWidth(width)],
+ listStyles[getRegularWidth(fWidth)],
status);
}
@@ -922,7 +922,7 @@ UBool MeasureFormat::setMeasureFormatLocale(const Locale &locale, UErrorCode &st
if (U_FAILURE(status) || locale == getLocale(status)) {
return FALSE;
}
- initMeasureFormat(locale, width, NULL, status);
+ initMeasureFormat(locale, fWidth, NULL, status);
return U_SUCCESS(status);
}
@@ -956,7 +956,7 @@ UnicodeString &MeasureFormat::formatMeasure(
if (isCurrency(amtUnit)) {
UChar isoCode[4];
u_charsToUChars(amtUnit.getSubtype(), isoCode, 4);
- return cache->getCurrencyFormat(width)->format(
+ return cache->getCurrencyFormat(fWidth)->format(
new CurrencyAmount(amtNumber, isoCode, status),
appendTo,
pos,
@@ -965,7 +965,7 @@ UnicodeString &MeasureFormat::formatMeasure(
UnicodeString formattedNumber;
StandardPlural::Form pluralForm = QuantityFormatter::selectPlural(
amtNumber, nf, **pluralRules, formattedNumber, pos, status);
- const SimpleFormatter *formatter = getPluralFormatter(amtUnit, width, pluralForm, status);
+ const SimpleFormatter *formatter = getPluralFormatter(amtUnit, fWidth, pluralForm, status);
return QuantityFormatter::format(*formatter, formattedNumber, appendTo, pos, status);
}
@@ -1016,7 +1016,6 @@ UnicodeString &MeasureFormat::formatNumeric(
return appendTo;
break;
}
- return appendTo;
}
static void appendRange(
@@ -1173,7 +1172,7 @@ int32_t MeasureFormat::withPerUnitAndAppend(
if (U_FAILURE(status)) {
return offset;
}
- const SimpleFormatter *perUnitFormatter = getFormatterOrNull(perUnit, width, PER_UNIT_INDEX);
+ const SimpleFormatter *perUnitFormatter = getFormatterOrNull(perUnit, fWidth, PER_UNIT_INDEX);
if (perUnitFormatter != NULL) {
const UnicodeString *params[] = {&formatted};
perUnitFormatter->formatAndAppend(
@@ -1185,9 +1184,9 @@ int32_t MeasureFormat::withPerUnitAndAppend(
status);
return offset;
}
- const SimpleFormatter *perFormatter = getPerFormatter(width, status);
+ const SimpleFormatter *perFormatter = getPerFormatter(fWidth, status);
const SimpleFormatter *pattern =
- getPluralFormatter(perUnit, width, StandardPlural::ONE, status);
+ getPluralFormatter(perUnit, fWidth, StandardPlural::ONE, status);
if (U_FAILURE(status)) {
return offset;
}
diff --git a/deps/icu-small/source/i18n/measunit.cpp b/deps/icu-small/source/i18n/measunit.cpp
index dc156aa720..f6059f8c6d 100644
--- a/deps/icu-small/source/i18n/measunit.cpp
+++ b/deps/icu-small/source/i18n/measunit.cpp
@@ -39,23 +39,23 @@ static const int32_t gOffsets[] = {
2,
7,
16,
- 20,
- 24,
- 321,
- 331,
- 342,
- 346,
- 352,
- 356,
- 376,
- 377,
- 388,
- 391,
- 397,
+ 22,
+ 26,
+ 325,
+ 336,
+ 347,
+ 351,
+ 357,
+ 361,
+ 381,
+ 382,
+ 393,
+ 396,
402,
- 406,
- 410,
- 435
+ 408,
+ 412,
+ 416,
+ 441
};
static const int32_t gIndexes[] = {
@@ -63,23 +63,23 @@ static const int32_t gIndexes[] = {
2,
7,
16,
- 20,
- 24,
- 24,
- 34,
- 45,
- 49,
- 55,
- 59,
- 79,
- 80,
- 91,
+ 22,
+ 26,
+ 26,
+ 37,
+ 48,
+ 52,
+ 58,
+ 62,
+ 82,
+ 83,
94,
- 100,
- 105,
+ 97,
+ 103,
109,
113,
- 138
+ 117,
+ 142
};
// Must be sorted alphabetically.
@@ -128,6 +128,8 @@ static const char * const gSubTypes[] = {
"milligram-per-deciliter",
"millimole-per-liter",
"part-per-million",
+ "percent",
+ "permille",
"liter-per-100kilometers",
"liter-per-kilometer",
"mile-per-gallon",
@@ -388,9 +390,11 @@ static const char * const gSubTypes[] = {
"UYN",
"UYP",
"UYU",
+ "UYW",
"UZS",
"VEB",
"VEF",
+ "VES",
"VNC",
"VND",
"VUV",
@@ -437,6 +441,7 @@ static const char * const gSubTypes[] = {
"kilobyte",
"megabit",
"megabyte",
+ "petabyte",
"terabit",
"terabyte",
"century",
@@ -505,6 +510,7 @@ static const char * const gSubTypes[] = {
"megawatt",
"milliwatt",
"watt",
+ "atmosphere",
"hectopascal",
"inch-hg",
"millibar",
@@ -547,14 +553,14 @@ static const char * const gSubTypes[] = {
// Must be sorted by first value and then second value.
static int32_t unitPerUnitToSingleUnit[][4] = {
- {363, 333, 17, 0},
- {365, 339, 17, 2},
- {367, 333, 17, 3},
- {367, 424, 4, 2},
- {367, 425, 4, 3},
- {382, 422, 3, 1},
- {385, 11, 16, 4},
- {427, 363, 4, 1}
+ {368, 338, 17, 0},
+ {370, 344, 17, 2},
+ {372, 338, 17, 3},
+ {372, 430, 4, 2},
+ {372, 431, 4, 3},
+ {387, 428, 3, 1},
+ {390, 11, 16, 5},
+ {433, 368, 4, 1}
};
// Shortcuts to the base unit in order to make the default constructor fast
@@ -641,6 +647,14 @@ MeasureUnit *MeasureUnit::createPartPerMillion(UErrorCode &status) {
return MeasureUnit::create(3, 3, status);
}
+MeasureUnit *MeasureUnit::createPercent(UErrorCode &status) {
+ return MeasureUnit::create(3, 4, status);
+}
+
+MeasureUnit *MeasureUnit::createPermille(UErrorCode &status) {
+ return MeasureUnit::create(3, 5, status);
+}
+
MeasureUnit *MeasureUnit::createLiterPer100Kilometers(UErrorCode &status) {
return MeasureUnit::create(4, 0, status);
}
@@ -689,14 +703,18 @@ MeasureUnit *MeasureUnit::createMegabyte(UErrorCode &status) {
return MeasureUnit::create(6, 7, status);
}
-MeasureUnit *MeasureUnit::createTerabit(UErrorCode &status) {
+MeasureUnit *MeasureUnit::createPetabyte(UErrorCode &status) {
return MeasureUnit::create(6, 8, status);
}
-MeasureUnit *MeasureUnit::createTerabyte(UErrorCode &status) {
+MeasureUnit *MeasureUnit::createTerabit(UErrorCode &status) {
return MeasureUnit::create(6, 9, status);
}
+MeasureUnit *MeasureUnit::createTerabyte(UErrorCode &status) {
+ return MeasureUnit::create(6, 10, status);
+}
+
MeasureUnit *MeasureUnit::createCentury(UErrorCode &status) {
return MeasureUnit::create(7, 0, status);
}
@@ -949,26 +967,30 @@ MeasureUnit *MeasureUnit::createWatt(UErrorCode &status) {
return MeasureUnit::create(15, 5, status);
}
-MeasureUnit *MeasureUnit::createHectopascal(UErrorCode &status) {
+MeasureUnit *MeasureUnit::createAtmosphere(UErrorCode &status) {
return MeasureUnit::create(16, 0, status);
}
-MeasureUnit *MeasureUnit::createInchHg(UErrorCode &status) {
+MeasureUnit *MeasureUnit::createHectopascal(UErrorCode &status) {
return MeasureUnit::create(16, 1, status);
}
-MeasureUnit *MeasureUnit::createMillibar(UErrorCode &status) {
+MeasureUnit *MeasureUnit::createInchHg(UErrorCode &status) {
return MeasureUnit::create(16, 2, status);
}
-MeasureUnit *MeasureUnit::createMillimeterOfMercury(UErrorCode &status) {
+MeasureUnit *MeasureUnit::createMillibar(UErrorCode &status) {
return MeasureUnit::create(16, 3, status);
}
-MeasureUnit *MeasureUnit::createPoundPerSquareInch(UErrorCode &status) {
+MeasureUnit *MeasureUnit::createMillimeterOfMercury(UErrorCode &status) {
return MeasureUnit::create(16, 4, status);
}
+MeasureUnit *MeasureUnit::createPoundPerSquareInch(UErrorCode &status) {
+ return MeasureUnit::create(16, 5, status);
+}
+
MeasureUnit *MeasureUnit::createKilometerPerHour(UErrorCode &status) {
return MeasureUnit::create(17, 0, status);
}
diff --git a/deps/icu-small/source/i18n/msgfmt.cpp b/deps/icu-small/source/i18n/msgfmt.cpp
index 8b3807e671..8ff86a2cac 100644
--- a/deps/icu-small/source/i18n/msgfmt.cpp
+++ b/deps/icu-small/source/i18n/msgfmt.cpp
@@ -1078,7 +1078,7 @@ void MessageFormat::format(int32_t msgStart, const void *plNumber,
// that formats the number without subtracting the offset.
appendTo.formatAndAppend(pluralNumber.formatter, *arg, success);
}
- } else if ((formatter = getCachedFormatter(i -2))) {
+ } else if ((formatter = getCachedFormatter(i -2)) != 0) {
// Handles all ArgType.SIMPLE, and formatters from setFormat() and its siblings.
if (dynamic_cast<const ChoiceFormat*>(formatter) ||
dynamic_cast<const PluralFormat*>(formatter) ||
diff --git a/deps/icu-small/source/i18n/nfrule.cpp b/deps/icu-small/source/i18n/nfrule.cpp
index 9f5deb3168..b5e7892d5e 100644
--- a/deps/icu-small/source/i18n/nfrule.cpp
+++ b/deps/icu-small/source/i18n/nfrule.cpp
@@ -39,14 +39,14 @@ NFRule::NFRule(const RuleBasedNumberFormat* _rbnf, const UnicodeString &_ruleTex
, radix(10)
, exponent(0)
, decimalPoint(0)
- , ruleText(_ruleText)
+ , fRuleText(_ruleText)
, sub1(NULL)
, sub2(NULL)
, formatter(_rbnf)
, rulePatternFormat(NULL)
{
- if (!ruleText.isEmpty()) {
- parseRuleDescriptor(ruleText, status);
+ if (!fRuleText.isEmpty()) {
+ parseRuleDescriptor(fRuleText, status);
}
}
@@ -122,7 +122,7 @@ NFRule::makeRules(UnicodeString& description,
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
- description = rule1->ruleText;
+ description = rule1->fRuleText;
// check the description to see whether there's text enclosed
// in brackets
@@ -314,7 +314,7 @@ NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status)
if (c == gSlash) {
val = 0;
++p;
- int64_t ll_10 = 10;
+ ll_10 = 10;
while (p < descriptorLength) {
c = descriptor.charAt(p);
if (c >= gZero && c <= gNine) {
@@ -418,7 +418,7 @@ NFRule::extractSubstitutions(const NFRuleSet* ruleSet,
if (U_FAILURE(status)) {
return;
}
- this->ruleText = ruleText;
+ fRuleText = ruleText;
sub1 = extractSubstitution(ruleSet, predecessor, status);
if (sub1 == NULL) {
// Small optimization. There is no need to create a redundant NullSubstitution.
@@ -427,15 +427,15 @@ NFRule::extractSubstitutions(const NFRuleSet* ruleSet,
else {
sub2 = extractSubstitution(ruleSet, predecessor, status);
}
- int32_t pluralRuleStart = this->ruleText.indexOf(gDollarOpenParenthesis, -1, 0);
- int32_t pluralRuleEnd = (pluralRuleStart >= 0 ? this->ruleText.indexOf(gClosedParenthesisDollar, -1, pluralRuleStart) : -1);
+ int32_t pluralRuleStart = fRuleText.indexOf(gDollarOpenParenthesis, -1, 0);
+ int32_t pluralRuleEnd = (pluralRuleStart >= 0 ? fRuleText.indexOf(gClosedParenthesisDollar, -1, pluralRuleStart) : -1);
if (pluralRuleEnd >= 0) {
- int32_t endType = this->ruleText.indexOf(gComma, pluralRuleStart);
+ int32_t endType = fRuleText.indexOf(gComma, pluralRuleStart);
if (endType < 0) {
status = U_PARSE_ERROR;
return;
}
- UnicodeString type(this->ruleText.tempSubString(pluralRuleStart + 2, endType - pluralRuleStart - 2));
+ UnicodeString type(fRuleText.tempSubString(pluralRuleStart + 2, endType - pluralRuleStart - 2));
UPluralType pluralType;
if (type.startsWith(UNICODE_STRING_SIMPLE("cardinal"))) {
pluralType = UPLURAL_TYPE_CARDINAL;
@@ -448,7 +448,7 @@ NFRule::extractSubstitutions(const NFRuleSet* ruleSet,
return;
}
rulePatternFormat = formatter->createPluralFormat(pluralType,
- this->ruleText.tempSubString(endType + 1, pluralRuleEnd - endType - 1), status);
+ fRuleText.tempSubString(endType + 1, pluralRuleEnd - endType - 1), status);
}
}
@@ -484,16 +484,16 @@ NFRule::extractSubstitution(const NFRuleSet* ruleSet,
// special-case the ">>>" token, since searching for the > at the
// end will actually find the > in the middle
- if (ruleText.indexOf(gGreaterGreaterGreater, 3, 0) == subStart) {
+ if (fRuleText.indexOf(gGreaterGreaterGreater, 3, 0) == subStart) {
subEnd = subStart + 2;
// otherwise the substitution token ends with the same character
// it began with
} else {
- UChar c = ruleText.charAt(subStart);
- subEnd = ruleText.indexOf(c, subStart + 1);
+ UChar c = fRuleText.charAt(subStart);
+ subEnd = fRuleText.indexOf(c, subStart + 1);
// special case for '<%foo<<'
- if (c == gLessThan && subEnd != -1 && subEnd < ruleText.length() - 1 && ruleText.charAt(subEnd+1) == c) {
+ if (c == gLessThan && subEnd != -1 && subEnd < fRuleText.length() - 1 && fRuleText.charAt(subEnd+1) == c) {
// ordinals use "=#,##0==%abbrev=" as their rule. Notice that the '==' in the middle
// occurs because of the juxtaposition of two different rules. The check for '<' is a hack
// to get around this. Having the duplicate at the front would cause problems with
@@ -513,12 +513,12 @@ NFRule::extractSubstitution(const NFRuleSet* ruleSet,
// some text bounded by substitution token characters). Use
// makeSubstitution() to create the right kind of substitution
UnicodeString subToken;
- subToken.setTo(ruleText, subStart, subEnd + 1 - subStart);
+ subToken.setTo(fRuleText, subStart, subEnd + 1 - subStart);
result = NFSubstitution::makeSubstitution(subStart, this, predecessor, ruleSet,
this->formatter, subToken, status);
// remove the substitution from the rule text
- ruleText.removeBetween(subStart, subEnd+1);
+ fRuleText.removeBetween(subStart, subEnd+1);
return result;
}
@@ -601,7 +601,7 @@ NFRule::indexOfAnyRulePrefix() const
{
int result = -1;
for (int i = 0; RULE_PREFIXES[i]; i++) {
- int32_t pos = ruleText.indexOf(*RULE_PREFIXES[i]);
+ int32_t pos = fRuleText.indexOf(*RULE_PREFIXES[i]);
if (pos != -1 && (result == -1 || pos < result)) {
result = pos;
}
@@ -637,7 +637,7 @@ NFRule::operator==(const NFRule& rhs) const
return baseValue == rhs.baseValue
&& radix == rhs.radix
&& exponent == rhs.exponent
- && ruleText == rhs.ruleText
+ && fRuleText == rhs.fRuleText
&& util_equalSubstitutions(sub1, rhs.sub1)
&& util_equalSubstitutions(sub2, rhs.sub2);
}
@@ -690,14 +690,14 @@ NFRule::_appendRuleText(UnicodeString& result) const
// if the rule text begins with a space, write an apostrophe
// (whitespace after the rule descriptor is ignored; the
// apostrophe is used to make the whitespace significant)
- if (ruleText.charAt(0) == gSpace && (sub1 == NULL || sub1->getPos() != 0)) {
+ if (fRuleText.charAt(0) == gSpace && (sub1 == NULL || sub1->getPos() != 0)) {
result.append(gTick);
}
// now, write the rule's rule text, inserting appropriate
// substitution tokens in the appropriate places
UnicodeString ruleTextCopy;
- ruleTextCopy.setTo(ruleText);
+ ruleTextCopy.setTo(fRuleText);
UnicodeString temp;
if (sub2 != NULL) {
@@ -743,24 +743,24 @@ NFRule::doFormat(int64_t number, UnicodeString& toInsertInto, int32_t pos, int32
// into the right places in toInsertInto (notice we do the
// substitutions in reverse order so that the offsets don't get
// messed up)
- int32_t pluralRuleStart = ruleText.length();
+ int32_t pluralRuleStart = fRuleText.length();
int32_t lengthOffset = 0;
if (!rulePatternFormat) {
- toInsertInto.insert(pos, ruleText);
+ toInsertInto.insert(pos, fRuleText);
}
else {
- pluralRuleStart = ruleText.indexOf(gDollarOpenParenthesis, -1, 0);
- int pluralRuleEnd = ruleText.indexOf(gClosedParenthesisDollar, -1, pluralRuleStart);
+ pluralRuleStart = fRuleText.indexOf(gDollarOpenParenthesis, -1, 0);
+ int pluralRuleEnd = fRuleText.indexOf(gClosedParenthesisDollar, -1, pluralRuleStart);
int initialLength = toInsertInto.length();
- if (pluralRuleEnd < ruleText.length() - 1) {
- toInsertInto.insert(pos, ruleText.tempSubString(pluralRuleEnd + 2));
+ if (pluralRuleEnd < fRuleText.length() - 1) {
+ toInsertInto.insert(pos, fRuleText.tempSubString(pluralRuleEnd + 2));
}
toInsertInto.insert(pos,
rulePatternFormat->format((int32_t)(number/util64_pow(radix, exponent)), status));
if (pluralRuleStart > 0) {
- toInsertInto.insert(pos, ruleText.tempSubString(0, pluralRuleStart));
+ toInsertInto.insert(pos, fRuleText.tempSubString(0, pluralRuleStart));
}
- lengthOffset = ruleText.length() - (toInsertInto.length() - initialLength);
+ lengthOffset = fRuleText.length() - (toInsertInto.length() - initialLength);
}
if (sub2 != NULL) {
@@ -789,17 +789,17 @@ NFRule::doFormat(double number, UnicodeString& toInsertInto, int32_t pos, int32_
// [again, we have two copies of this routine that do the same thing
// so that we don't sacrifice precision in a long by casting it
// to a double]
- int32_t pluralRuleStart = ruleText.length();
+ int32_t pluralRuleStart = fRuleText.length();
int32_t lengthOffset = 0;
if (!rulePatternFormat) {
- toInsertInto.insert(pos, ruleText);
+ toInsertInto.insert(pos, fRuleText);
}
else {
- pluralRuleStart = ruleText.indexOf(gDollarOpenParenthesis, -1, 0);
- int pluralRuleEnd = ruleText.indexOf(gClosedParenthesisDollar, -1, pluralRuleStart);
+ pluralRuleStart = fRuleText.indexOf(gDollarOpenParenthesis, -1, 0);
+ int pluralRuleEnd = fRuleText.indexOf(gClosedParenthesisDollar, -1, pluralRuleStart);
int initialLength = toInsertInto.length();
- if (pluralRuleEnd < ruleText.length() - 1) {
- toInsertInto.insert(pos, ruleText.tempSubString(pluralRuleEnd + 2));
+ if (pluralRuleEnd < fRuleText.length() - 1) {
+ toInsertInto.insert(pos, fRuleText.tempSubString(pluralRuleEnd + 2));
}
double pluralVal = number;
if (0 <= pluralVal && pluralVal < 1) {
@@ -812,9 +812,9 @@ NFRule::doFormat(double number, UnicodeString& toInsertInto, int32_t pos, int32_
}
toInsertInto.insert(pos, rulePatternFormat->format((int32_t)(pluralVal), status));
if (pluralRuleStart > 0) {
- toInsertInto.insert(pos, ruleText.tempSubString(0, pluralRuleStart));
+ toInsertInto.insert(pos, fRuleText.tempSubString(0, pluralRuleStart));
}
- lengthOffset = ruleText.length() - (toInsertInto.length() - initialLength);
+ lengthOffset = fRuleText.length() - (toInsertInto.length() - initialLength);
}
if (sub2 != NULL) {
@@ -908,15 +908,15 @@ NFRule::doParse(const UnicodeString& text,
ParsePosition pp;
UnicodeString workText(text);
- int32_t sub1Pos = sub1 != NULL ? sub1->getPos() : ruleText.length();
- int32_t sub2Pos = sub2 != NULL ? sub2->getPos() : ruleText.length();
+ int32_t sub1Pos = sub1 != NULL ? sub1->getPos() : fRuleText.length();
+ int32_t sub2Pos = sub2 != NULL ? sub2->getPos() : fRuleText.length();
// check to see whether the text before the first substitution
// matches the text at the beginning of the string being
// parsed. If it does, strip that off the front of workText;
// otherwise, dump out with a mismatch
UnicodeString prefix;
- prefix.setTo(ruleText, 0, sub1Pos);
+ prefix.setTo(fRuleText, 0, sub1Pos);
#ifdef RBNF_DEBUG
fprintf(stderr, "doParse %p ", this);
@@ -1000,7 +1000,7 @@ NFRule::doParse(const UnicodeString& text,
// the substitution, giving us a new partial parse result
pp.setIndex(0);
- temp.setTo(ruleText, sub1Pos, sub2Pos - sub1Pos);
+ temp.setTo(fRuleText, sub1Pos, sub2Pos - sub1Pos);
double partialResult = matchToDelimiter(workText, start, tempBaseValue,
temp, pp, sub1,
nonNumericalExecutedRuleMask,
@@ -1021,7 +1021,7 @@ NFRule::doParse(const UnicodeString& text,
// partial result with whatever it gets back from its
// substitution if there's a successful match, giving us
// a real result
- temp.setTo(ruleText, sub2Pos, ruleText.length() - sub2Pos);
+ temp.setTo(fRuleText, sub2Pos, fRuleText.length() - sub2Pos);
partialResult = matchToDelimiter(workText2, 0, partialResult,
temp, pp2, sub2,
nonNumericalExecutedRuleMask,
@@ -1039,18 +1039,18 @@ NFRule::doParse(const UnicodeString& text,
else {
// commented out because ParsePosition doesn't have error index in 1.1.x
// restored for ICU4C port
- int32_t temp = pp2.getErrorIndex() + sub1Pos + pp.getIndex();
- if (temp> parsePosition.getErrorIndex()) {
- parsePosition.setErrorIndex(temp);
+ int32_t i_temp = pp2.getErrorIndex() + sub1Pos + pp.getIndex();
+ if (i_temp> parsePosition.getErrorIndex()) {
+ parsePosition.setErrorIndex(i_temp);
}
}
}
else {
// commented out because ParsePosition doesn't have error index in 1.1.x
// restored for ICU4C port
- int32_t temp = sub1Pos + pp.getErrorIndex();
- if (temp > parsePosition.getErrorIndex()) {
- parsePosition.setErrorIndex(temp);
+ int32_t i_temp = sub1Pos + pp.getErrorIndex();
+ if (i_temp > parsePosition.getErrorIndex()) {
+ parsePosition.setErrorIndex(i_temp);
}
}
// keep trying to match things until the outer matchToDelimiter()
@@ -1483,11 +1483,11 @@ NFRule::findText(const UnicodeString& str,
rulePatternFormat->parseType(str, this, result, position);
int start = position.getBeginIndex();
if (start >= 0) {
- int32_t pluralRuleStart = ruleText.indexOf(gDollarOpenParenthesis, -1, 0);
- int32_t pluralRuleSuffix = ruleText.indexOf(gClosedParenthesisDollar, -1, pluralRuleStart) + 2;
+ int32_t pluralRuleStart = fRuleText.indexOf(gDollarOpenParenthesis, -1, 0);
+ int32_t pluralRuleSuffix = fRuleText.indexOf(gClosedParenthesisDollar, -1, pluralRuleStart) + 2;
int32_t matchLen = position.getEndIndex() - start;
- UnicodeString prefix(ruleText.tempSubString(0, pluralRuleStart));
- UnicodeString suffix(ruleText.tempSubString(pluralRuleSuffix));
+ UnicodeString prefix(fRuleText.tempSubString(0, pluralRuleStart));
+ UnicodeString suffix(fRuleText.tempSubString(pluralRuleSuffix));
if (str.compare(start - prefix.length(), prefix.length(), prefix, 0, prefix.length()) == 0
&& str.compare(start + matchLen, suffix.length(), suffix, 0, suffix.length()) == 0)
{
diff --git a/deps/icu-small/source/i18n/nfrule.h b/deps/icu-small/source/i18n/nfrule.h
index 843a4a0762..2b030390ea 100644
--- a/deps/icu-small/source/i18n/nfrule.h
+++ b/deps/icu-small/source/i18n/nfrule.h
@@ -109,7 +109,7 @@ private:
int32_t radix;
int16_t exponent;
UChar decimalPoint;
- UnicodeString ruleText;
+ UnicodeString fRuleText;
NFSubstitution* sub1;
NFSubstitution* sub2;
const RuleBasedNumberFormat* formatter;
diff --git a/deps/icu-small/source/i18n/number_compact.cpp b/deps/icu-small/source/i18n/number_compact.cpp
index 40278e1a01..10942c35f5 100644
--- a/deps/icu-small/source/i18n/number_compact.cpp
+++ b/deps/icu-small/source/i18n/number_compact.cpp
@@ -273,13 +273,13 @@ void CompactHandler::processQuantity(DecimalQuantity &quantity, MicroProps &micr
if (U_FAILURE(status)) { return; }
// Treat zero as if it had magnitude 0
- int magnitude;
+ int32_t magnitude;
if (quantity.isZero()) {
magnitude = 0;
micros.rounder.apply(quantity, status);
} else {
// TODO: Revisit chooseMultiplierAndApply
- int multiplier = micros.rounder.chooseMultiplierAndApply(quantity, data, status);
+ int32_t multiplier = micros.rounder.chooseMultiplierAndApply(quantity, data, status);
magnitude = quantity.isZero() ? 0 : quantity.getMagnitude();
magnitude -= multiplier;
}
diff --git a/deps/icu-small/source/i18n/number_decimalquantity.cpp b/deps/icu-small/source/i18n/number_decimalquantity.cpp
index 9d80e3349c..2c4182b1c6 100644
--- a/deps/icu-small/source/i18n/number_decimalquantity.cpp
+++ b/deps/icu-small/source/i18n/number_decimalquantity.cpp
@@ -1154,8 +1154,31 @@ const char16_t* DecimalQuantity::checkHealth() const {
}
bool DecimalQuantity::operator==(const DecimalQuantity& other) const {
- // FIXME: Make a faster implementation.
- return toString() == other.toString();
+ bool basicEquals =
+ scale == other.scale
+ && precision == other.precision
+ && flags == other.flags
+ && lOptPos == other.lOptPos
+ && lReqPos == other.lReqPos
+ && rReqPos == other.rReqPos
+ && rOptPos == other.rOptPos
+ && isApproximate == other.isApproximate;
+ if (!basicEquals) {
+ return false;
+ }
+
+ if (precision == 0) {
+ return true;
+ } else if (isApproximate) {
+ return origDouble == other.origDouble && origDelta == other.origDelta;
+ } else {
+ for (int m = getUpperDisplayMagnitude(); m >= getLowerDisplayMagnitude(); m--) {
+ if (getDigit(m) != other.getDigit(m)) {
+ return false;
+ }
+ }
+ return true;
+ }
}
UnicodeString DecimalQuantity::toString() const {
diff --git a/deps/icu-small/source/i18n/number_decimfmtprops.cpp b/deps/icu-small/source/i18n/number_decimfmtprops.cpp
index 6754fe19ec..12fe7060e2 100644
--- a/deps/icu-small/source/i18n/number_decimfmtprops.cpp
+++ b/deps/icu-small/source/i18n/number_decimfmtprops.cpp
@@ -15,6 +15,7 @@ using namespace icu::number::impl;
namespace {
+alignas(DecimalFormatProperties)
char kRawDefaultProperties[sizeof(DecimalFormatProperties)];
icu::UInitOnce gDefaultPropertiesInitOnce = U_INITONCE_INITIALIZER;
diff --git a/deps/icu-small/source/i18n/number_fluent.cpp b/deps/icu-small/source/i18n/number_fluent.cpp
index 687adb6b5b..a66e3bd0f2 100644
--- a/deps/icu-small/source/i18n/number_fluent.cpp
+++ b/deps/icu-small/source/i18n/number_fluent.cpp
@@ -363,6 +363,7 @@ UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(const NFS<UNF>& other)
// No additional fields to assign
}
+// Make default copy constructor call the NumberFormatterSettings copy constructor.
UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(UNF&& src) U_NOEXCEPT
: UNF(static_cast<NFS<UNF>&&>(src)) {}
@@ -383,6 +384,7 @@ UnlocalizedNumberFormatter& UnlocalizedNumberFormatter::operator=(UNF&& src) U_N
return *this;
}
+// Make default copy constructor call the NumberFormatterSettings copy constructor.
LocalizedNumberFormatter::LocalizedNumberFormatter(const LNF& other)
: LNF(static_cast<const NFS<LNF>&>(other)) {}
@@ -405,7 +407,8 @@ LocalizedNumberFormatter::LocalizedNumberFormatter(NFS<LNF>&& src) U_NOEXCEPT
LocalizedNumberFormatter& LocalizedNumberFormatter::operator=(const LNF& other) {
NFS<LNF>::operator=(static_cast<const NFS<LNF>&>(other));
- // No additional fields to assign (let call count and compiled formatter reset to defaults)
+ // Reset to default values.
+ clear();
return *this;
}
@@ -417,20 +420,26 @@ LocalizedNumberFormatter& LocalizedNumberFormatter::operator=(LNF&& src) U_NOEXC
// Formatter is compiled
lnfMoveHelper(static_cast<LNF&&>(src));
} else {
- // Reset to default values.
- auto* callCount = reinterpret_cast<u_atomic_int32_t*>(fUnsafeCallCount);
- umtx_storeRelease(*callCount, 0);
- fCompiled = nullptr;
+ clear();
}
return *this;
}
+void LocalizedNumberFormatter::clear() {
+ // Reset to default values.
+ auto* callCount = reinterpret_cast<u_atomic_int32_t*>(fUnsafeCallCount);
+ umtx_storeRelease(*callCount, 0);
+ delete fCompiled;
+ fCompiled = nullptr;
+}
+
void LocalizedNumberFormatter::lnfMoveHelper(LNF&& src) {
// Copy over the compiled formatter and set call count to INT32_MIN as in computeCompiled().
// Don't copy the call count directly because doing so requires a loadAcquire/storeRelease.
// The bits themselves appear to be platform-dependent, so copying them might not be safe.
auto* callCount = reinterpret_cast<u_atomic_int32_t*>(fUnsafeCallCount);
umtx_storeRelease(*callCount, INT32_MIN);
+ delete fCompiled;
fCompiled = src.fCompiled;
// Reset the source object to leave it in a safe state.
auto* srcCallCount = reinterpret_cast<u_atomic_int32_t*>(src.fUnsafeCallCount);
@@ -657,9 +666,9 @@ LocalizedNumberFormatter::formatDecimalQuantity(const DecimalQuantity& dq, UErro
void LocalizedNumberFormatter::formatImpl(impl::UFormattedNumberData* results, UErrorCode& status) const {
if (computeCompiled(status)) {
- fCompiled->apply(results->quantity, results->string, status);
+ fCompiled->format(results->quantity, results->string, status);
} else {
- NumberFormatterImpl::applyStatic(fMacros, results->quantity, results->string, status);
+ NumberFormatterImpl::formatStatic(fMacros, results->quantity, results->string, status);
}
}
@@ -706,7 +715,11 @@ bool LocalizedNumberFormatter::computeCompiled(UErrorCode& status) const {
if (currentCount == fMacros.threshold && fMacros.threshold > 0) {
// Build the data structure and then use it (slow to fast path).
- const NumberFormatterImpl* compiled = NumberFormatterImpl::fromMacros(fMacros, status);
+ const NumberFormatterImpl* compiled = new NumberFormatterImpl(fMacros, status);
+ if (compiled == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
U_ASSERT(fCompiled == nullptr);
const_cast<LocalizedNumberFormatter*>(this)->fCompiled = compiled;
umtx_storeRelease(*callCount, INT32_MIN);
@@ -776,7 +789,7 @@ Appendable& FormattedNumber::appendTo(Appendable& appendable) {
return appendTo(appendable, localStatus);
}
-Appendable& FormattedNumber::appendTo(Appendable& appendable, UErrorCode& status) {
+Appendable& FormattedNumber::appendTo(Appendable& appendable, UErrorCode& status) const {
if (U_FAILURE(status)) {
return appendable;
}
diff --git a/deps/icu-small/source/i18n/number_formatimpl.cpp b/deps/icu-small/source/i18n/number_formatimpl.cpp
index 3f887128bc..60c18ee284 100644
--- a/deps/icu-small/source/i18n/number_formatimpl.cpp
+++ b/deps/icu-small/source/i18n/number_formatimpl.cpp
@@ -67,14 +67,18 @@ getCurrencyFormatInfo(const Locale& locale, const char* isoCode, UErrorCode& sta
MicroPropsGenerator::~MicroPropsGenerator() = default;
-NumberFormatterImpl* NumberFormatterImpl::fromMacros(const MacroProps& macros, UErrorCode& status) {
- return new NumberFormatterImpl(macros, true, status);
+NumberFormatterImpl::NumberFormatterImpl(const MacroProps& macros, UErrorCode& status)
+ : NumberFormatterImpl(macros, true, status) {
}
-void NumberFormatterImpl::applyStatic(const MacroProps& macros, DecimalQuantity& inValue,
- NumberStringBuilder& outString, UErrorCode& status) {
+int32_t NumberFormatterImpl::formatStatic(const MacroProps& macros, DecimalQuantity& inValue,
+ NumberStringBuilder& outString, UErrorCode& status) {
NumberFormatterImpl impl(macros, false, status);
- impl.applyUnsafe(inValue, outString, status);
+ MicroProps& micros = impl.preProcessUnsafe(inValue, status);
+ if (U_FAILURE(status)) { return 0; }
+ int32_t length = writeNumber(micros, inValue, outString, 0, status);
+ length += writeAffixes(micros, outString, 0, length, status);
+ return length;
}
int32_t NumberFormatterImpl::getPrefixSuffixStatic(const MacroProps& macros, int8_t signum,
@@ -89,22 +93,40 @@ int32_t NumberFormatterImpl::getPrefixSuffixStatic(const MacroProps& macros, int
// The "unsafe" method simply re-uses fMicros, eliminating the extra copy operation.
// See MicroProps::processQuantity() for details.
-void NumberFormatterImpl::apply(DecimalQuantity& inValue, NumberStringBuilder& outString,
+int32_t NumberFormatterImpl::format(DecimalQuantity& inValue, NumberStringBuilder& outString,
UErrorCode& status) const {
- if (U_FAILURE(status)) { return; }
MicroProps micros;
- if (!fMicroPropsGenerator) { return; }
- fMicroPropsGenerator->processQuantity(inValue, micros, status);
- if (U_FAILURE(status)) { return; }
- microsToString(micros, inValue, outString, status);
+ preProcess(inValue, micros, status);
+ if (U_FAILURE(status)) { return 0; }
+ int32_t length = writeNumber(micros, inValue, outString, 0, status);
+ length += writeAffixes(micros, outString, 0, length, status);
+ return length;
}
-void NumberFormatterImpl::applyUnsafe(DecimalQuantity& inValue, NumberStringBuilder& outString,
- UErrorCode& status) {
+void NumberFormatterImpl::preProcess(DecimalQuantity& inValue, MicroProps& microsOut,
+ UErrorCode& status) const {
if (U_FAILURE(status)) { return; }
+ if (fMicroPropsGenerator == nullptr) {
+ status = U_INTERNAL_PROGRAM_ERROR;
+ return;
+ }
+ fMicroPropsGenerator->processQuantity(inValue, microsOut, status);
+ microsOut.rounder.apply(inValue, status);
+ microsOut.integerWidth.apply(inValue, status);
+}
+
+MicroProps& NumberFormatterImpl::preProcessUnsafe(DecimalQuantity& inValue, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return fMicros; // must always return a value
+ }
+ if (fMicroPropsGenerator == nullptr) {
+ status = U_INTERNAL_PROGRAM_ERROR;
+ return fMicros; // must always return a value
+ }
fMicroPropsGenerator->processQuantity(inValue, fMicros, status);
- if (U_FAILURE(status)) { return; }
- microsToString(fMicros, inValue, outString, status);
+ fMicros.rounder.apply(inValue, status);
+ fMicros.integerWidth.apply(inValue, status);
+ return fMicros;
}
int32_t NumberFormatterImpl::getPrefixSuffix(int8_t signum, StandardPlural::Form plural,
@@ -115,7 +137,7 @@ int32_t NumberFormatterImpl::getPrefixSuffix(int8_t signum, StandardPlural::Form
const Modifier* modifier = fImmutablePatternModifier->getModifier(signum, plural);
modifier->apply(outString, 0, 0, status);
if (U_FAILURE(status)) { return 0; }
- return modifier->getPrefixLength(status);
+ return modifier->getPrefixLength();
}
int32_t NumberFormatterImpl::getPrefixSuffixUnsafe(int8_t signum, StandardPlural::Form plural,
@@ -126,7 +148,7 @@ int32_t NumberFormatterImpl::getPrefixSuffixUnsafe(int8_t signum, StandardPlural
fPatternModifier->setNumberProperties(signum, plural);
fPatternModifier->apply(outString, 0, 0, status);
if (U_FAILURE(status)) { return 0; }
- return fPatternModifier->getPrefixLength(status);
+ return fPatternModifier->getPrefixLength();
}
NumberFormatterImpl::NumberFormatterImpl(const MacroProps& macros, bool safe, UErrorCode& status) {
@@ -344,25 +366,23 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps& macros, bool safe,
// Outer modifier (CLDR units and currency long names)
if (isCldrUnit) {
fLongNameHandler.adoptInstead(
- new LongNameHandler(
- LongNameHandler::forMeasureUnit(
- macros.locale,
- macros.unit,
- macros.perUnit,
- unitWidth,
- resolvePluralRules(macros.rules, macros.locale, status),
- chain,
- status)));
+ LongNameHandler::forMeasureUnit(
+ macros.locale,
+ macros.unit,
+ macros.perUnit,
+ unitWidth,
+ resolvePluralRules(macros.rules, macros.locale, status),
+ chain,
+ status));
chain = fLongNameHandler.getAlias();
} else if (isCurrency && unitWidth == UNUM_UNIT_WIDTH_FULL_NAME) {
fLongNameHandler.adoptInstead(
- new LongNameHandler(
- LongNameHandler::forCurrencyLongNames(
- macros.locale,
- currency,
- resolvePluralRules(macros.rules, macros.locale, status),
- chain,
- status)));
+ LongNameHandler::forCurrencyLongNames(
+ macros.locale,
+ currency,
+ resolvePluralRules(macros.rules, macros.locale, status),
+ chain,
+ status));
chain = fLongNameHandler.getAlias();
} else {
// No outer modifier required
@@ -404,50 +424,46 @@ NumberFormatterImpl::resolvePluralRules(const PluralRules* rulesPtr, const Local
return fRules.getAlias();
}
-int32_t NumberFormatterImpl::microsToString(const MicroProps& micros, DecimalQuantity& quantity,
- NumberStringBuilder& string, UErrorCode& status) {
- micros.rounder.apply(quantity, status);
- micros.integerWidth.apply(quantity, status);
- int32_t length = writeNumber(micros, quantity, string, status);
- // NOTE: When range formatting is added, these modifiers can bubble up.
- // For now, apply them all here at once.
+int32_t NumberFormatterImpl::writeAffixes(const MicroProps& micros, NumberStringBuilder& string,
+ int32_t start, int32_t end, UErrorCode& status) {
// Always apply the inner modifier (which is "strong").
- length += micros.modInner->apply(string, 0, length, status);
+ int32_t length = micros.modInner->apply(string, start, end, status);
if (micros.padding.isValid()) {
length += micros.padding
- .padAndApply(*micros.modMiddle, *micros.modOuter, string, 0, length, status);
+ .padAndApply(*micros.modMiddle, *micros.modOuter, string, start, length + end, status);
} else {
- length += micros.modMiddle->apply(string, 0, length, status);
- length += micros.modOuter->apply(string, 0, length, status);
+ length += micros.modMiddle->apply(string, start, length + end, status);
+ length += micros.modOuter->apply(string, start, length + end, status);
}
return length;
}
int32_t NumberFormatterImpl::writeNumber(const MicroProps& micros, DecimalQuantity& quantity,
- NumberStringBuilder& string, UErrorCode& status) {
+ NumberStringBuilder& string, int32_t index,
+ UErrorCode& status) {
int32_t length = 0;
if (quantity.isInfinite()) {
length += string.insert(
- length,
+ length + index,
micros.symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kInfinitySymbol),
UNUM_INTEGER_FIELD,
status);
} else if (quantity.isNaN()) {
length += string.insert(
- length,
+ length + index,
micros.symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kNaNSymbol),
UNUM_INTEGER_FIELD,
status);
} else {
// Add the integer digits
- length += writeIntegerDigits(micros, quantity, string, status);
+ length += writeIntegerDigits(micros, quantity, string, length + index, status);
// Add the decimal point
if (quantity.getLowerDisplayMagnitude() < 0 || micros.decimal == UNUM_DECIMAL_SEPARATOR_ALWAYS) {
length += string.insert(
- length,
+ length + index,
micros.useCurrency ? micros.symbols->getSymbol(
DecimalFormatSymbols::ENumberFormatSymbol::kMonetarySeparatorSymbol) : micros
.symbols
@@ -458,21 +474,22 @@ int32_t NumberFormatterImpl::writeNumber(const MicroProps& micros, DecimalQuanti
}
// Add the fraction digits
- length += writeFractionDigits(micros, quantity, string, status);
+ length += writeFractionDigits(micros, quantity, string, length + index, status);
}
return length;
}
int32_t NumberFormatterImpl::writeIntegerDigits(const MicroProps& micros, DecimalQuantity& quantity,
- NumberStringBuilder& string, UErrorCode& status) {
+ NumberStringBuilder& string, int32_t index,
+ UErrorCode& status) {
int length = 0;
int integerCount = quantity.getUpperDisplayMagnitude() + 1;
for (int i = 0; i < integerCount; i++) {
// Add grouping separator
if (micros.grouping.groupAtPosition(i, quantity)) {
length += string.insert(
- 0,
+ index,
micros.useCurrency ? micros.symbols->getSymbol(
DecimalFormatSymbols::ENumberFormatSymbol::kMonetaryGroupingSeparatorSymbol)
: micros.symbols->getSymbol(
@@ -484,20 +501,21 @@ int32_t NumberFormatterImpl::writeIntegerDigits(const MicroProps& micros, Decima
// Get and append the next digit value
int8_t nextDigit = quantity.getDigit(i);
length += utils::insertDigitFromSymbols(
- string, 0, nextDigit, *micros.symbols, UNUM_INTEGER_FIELD, status);
+ string, index, nextDigit, *micros.symbols, UNUM_INTEGER_FIELD, status);
}
return length;
}
int32_t NumberFormatterImpl::writeFractionDigits(const MicroProps& micros, DecimalQuantity& quantity,
- NumberStringBuilder& string, UErrorCode& status) {
+ NumberStringBuilder& string, int32_t index,
+ UErrorCode& status) {
int length = 0;
int fractionCount = -quantity.getLowerDisplayMagnitude();
for (int i = 0; i < fractionCount; i++) {
// Get and append the next digit value
int8_t nextDigit = quantity.getDigit(-i - 1);
length += utils::insertDigitFromSymbols(
- string, string.length(), nextDigit, *micros.symbols, UNUM_FRACTION_FIELD, status);
+ string, length + index, nextDigit, *micros.symbols, UNUM_FRACTION_FIELD, status);
}
return length;
}
diff --git a/deps/icu-small/source/i18n/number_formatimpl.h b/deps/icu-small/source/i18n/number_formatimpl.h
index 744fecec13..fda38c9284 100644
--- a/deps/icu-small/source/i18n/number_formatimpl.h
+++ b/deps/icu-small/source/i18n/number_formatimpl.h
@@ -29,14 +29,14 @@ class NumberFormatterImpl : public UMemory {
* Builds a "safe" MicroPropsGenerator, which is thread-safe and can be used repeatedly.
* The caller owns the returned NumberFormatterImpl.
*/
- static NumberFormatterImpl *fromMacros(const MacroProps &macros, UErrorCode &status);
+ NumberFormatterImpl(const MacroProps &macros, UErrorCode &status);
/**
* Builds and evaluates an "unsafe" MicroPropsGenerator, which is cheaper but can be used only once.
*/
- static void
- applyStatic(const MacroProps &macros, DecimalQuantity &inValue, NumberStringBuilder &outString,
- UErrorCode &status);
+ static int32_t
+ formatStatic(const MacroProps &macros, DecimalQuantity &inValue, NumberStringBuilder &outString,
+ UErrorCode &status);
/**
* Prints only the prefix and suffix; used for DecimalFormat getters.
@@ -51,7 +51,12 @@ class NumberFormatterImpl : public UMemory {
/**
* Evaluates the "safe" MicroPropsGenerator created by "fromMacros".
*/
- void apply(DecimalQuantity& inValue, NumberStringBuilder& outString, UErrorCode& status) const;
+ int32_t format(DecimalQuantity& inValue, NumberStringBuilder& outString, UErrorCode& status) const;
+
+ /**
+ * Like format(), but saves the result into an output MicroProps without additional processing.
+ */
+ void preProcess(DecimalQuantity& inValue, MicroProps& microsOut, UErrorCode& status) const;
/**
* Like getPrefixSuffixStatic() but uses the safe compiled object.
@@ -59,6 +64,19 @@ class NumberFormatterImpl : public UMemory {
int32_t getPrefixSuffix(int8_t signum, StandardPlural::Form plural, NumberStringBuilder& outString,
UErrorCode& status) const;
+ /**
+ * Synthesizes the output string from a MicroProps and DecimalQuantity.
+ * This method formats only the main number, not affixes.
+ */
+ static int32_t writeNumber(const MicroProps& micros, DecimalQuantity& quantity,
+ NumberStringBuilder& string, int32_t index, UErrorCode& status);
+
+ /**
+ * Adds the affixes. Intended to be called immediately after formatNumber.
+ */
+ static int32_t writeAffixes(const MicroProps& micros, NumberStringBuilder& string, int32_t start,
+ int32_t end, UErrorCode& status);
+
private:
// Head of the MicroPropsGenerator linked list:
const MicroPropsGenerator *fMicroPropsGenerator = nullptr;
@@ -85,7 +103,7 @@ class NumberFormatterImpl : public UMemory {
NumberFormatterImpl(const MacroProps &macros, bool safe, UErrorCode &status);
- void applyUnsafe(DecimalQuantity &inValue, NumberStringBuilder &outString, UErrorCode &status);
+ MicroProps& preProcessUnsafe(DecimalQuantity &inValue, UErrorCode &status);
int32_t getPrefixSuffixUnsafe(int8_t signum, StandardPlural::Form plural,
NumberStringBuilder& outString, UErrorCode& status);
@@ -113,31 +131,13 @@ class NumberFormatterImpl : public UMemory {
const MicroPropsGenerator *
macrosToMicroGenerator(const MacroProps &macros, bool safe, UErrorCode &status);
- /**
- * Synthesizes the output string from a MicroProps and DecimalQuantity.
- *
- * @param micros
- * The MicroProps after the quantity has been consumed. Will not be mutated.
- * @param quantity
- * The DecimalQuantity to be rendered. May be mutated.
- * @param string
- * The output string. Will be mutated.
- */
- static int32_t
- microsToString(const MicroProps &micros, DecimalQuantity &quantity, NumberStringBuilder &string,
- UErrorCode &status);
-
- static int32_t
- writeNumber(const MicroProps &micros, DecimalQuantity &quantity, NumberStringBuilder &string,
- UErrorCode &status);
-
static int32_t
writeIntegerDigits(const MicroProps &micros, DecimalQuantity &quantity, NumberStringBuilder &string,
- UErrorCode &status);
+ int32_t index, UErrorCode &status);
static int32_t
writeFractionDigits(const MicroProps &micros, DecimalQuantity &quantity, NumberStringBuilder &string,
- UErrorCode &status);
+ int32_t index, UErrorCode &status);
};
} // namespace impl
diff --git a/deps/icu-small/source/i18n/number_grouping.cpp b/deps/icu-small/source/i18n/number_grouping.cpp
index 4a1cceb499..da32cca99a 100644
--- a/deps/icu-small/source/i18n/number_grouping.cpp
+++ b/deps/icu-small/source/i18n/number_grouping.cpp
@@ -80,7 +80,7 @@ void Grouper::setLocaleData(const impl::ParsedPatternInfo &patternInfo, const Lo
if (fMinGrouping == -2) {
fMinGrouping = getMinGroupingForLocale(locale);
} else if (fMinGrouping == -3) {
- fMinGrouping = uprv_max(2, getMinGroupingForLocale(locale));
+ fMinGrouping = static_cast<int16_t>(uprv_max(2, getMinGroupingForLocale(locale)));
} else {
// leave fMinGrouping alone
}
diff --git a/deps/icu-small/source/i18n/number_longnames.cpp b/deps/icu-small/source/i18n/number_longnames.cpp
index 26f9af4c9b..fd8e8d381a 100644
--- a/deps/icu-small/source/i18n/number_longnames.cpp
+++ b/deps/icu-small/source/i18n/number_longnames.cpp
@@ -39,7 +39,7 @@ static int32_t getIndex(const char* pluralKeyword, UErrorCode& status) {
static UnicodeString getWithPlural(
const UnicodeString* strings,
- int32_t plural,
+ StandardPlural::Form plural,
UErrorCode& status) {
UnicodeString result = strings[plural];
if (result.isBogus()) {
@@ -156,7 +156,7 @@ UnicodeString getPerUnitFormat(const Locale& locale, const UNumberUnitWidth &wid
} // namespace
-LongNameHandler
+LongNameHandler*
LongNameHandler::forMeasureUnit(const Locale &loc, const MeasureUnit &unitRef, const MeasureUnit &perUnit,
const UNumberUnitWidth &width, const PluralRules *rules,
const MicroPropsGenerator *parent, UErrorCode &status) {
@@ -173,20 +173,28 @@ LongNameHandler::forMeasureUnit(const Locale &loc, const MeasureUnit &unitRef, c
}
}
- LongNameHandler result(rules, parent);
+ auto* result = new LongNameHandler(rules, parent);
+ if (result == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
UnicodeString simpleFormats[ARRAY_LENGTH];
getMeasureData(loc, unit, width, simpleFormats, status);
if (U_FAILURE(status)) { return result; }
// TODO: What field to use for units?
- simpleFormatsToModifiers(simpleFormats, UNUM_FIELD_COUNT, result.fModifiers, status);
+ result->simpleFormatsToModifiers(simpleFormats, UNUM_FIELD_COUNT, status);
return result;
}
-LongNameHandler
+LongNameHandler*
LongNameHandler::forCompoundUnit(const Locale &loc, const MeasureUnit &unit, const MeasureUnit &perUnit,
const UNumberUnitWidth &width, const PluralRules *rules,
const MicroPropsGenerator *parent, UErrorCode &status) {
- LongNameHandler result(rules, parent);
+ auto* result = new LongNameHandler(rules, parent);
+ if (result == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
UnicodeString primaryData[ARRAY_LENGTH];
getMeasureData(loc, unit, width, primaryData, status);
if (U_FAILURE(status)) { return result; }
@@ -213,46 +221,52 @@ LongNameHandler::forCompoundUnit(const Locale &loc, const MeasureUnit &unit, con
if (U_FAILURE(status)) { return result; }
}
// TODO: What field to use for units?
- multiSimpleFormatsToModifiers(primaryData, perUnitFormat, UNUM_FIELD_COUNT, result.fModifiers, status);
+ result->multiSimpleFormatsToModifiers(primaryData, perUnitFormat, UNUM_FIELD_COUNT, status);
return result;
}
-LongNameHandler LongNameHandler::forCurrencyLongNames(const Locale &loc, const CurrencyUnit &currency,
+LongNameHandler* LongNameHandler::forCurrencyLongNames(const Locale &loc, const CurrencyUnit &currency,
const PluralRules *rules,
const MicroPropsGenerator *parent,
UErrorCode &status) {
- LongNameHandler result(rules, parent);
+ auto* result = new LongNameHandler(rules, parent);
+ if (result == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
UnicodeString simpleFormats[ARRAY_LENGTH];
getCurrencyLongNameData(loc, currency, simpleFormats, status);
- if (U_FAILURE(status)) { return result; }
- simpleFormatsToModifiers(simpleFormats, UNUM_CURRENCY_FIELD, result.fModifiers, status);
+ if (U_FAILURE(status)) { return nullptr; }
+ result->simpleFormatsToModifiers(simpleFormats, UNUM_CURRENCY_FIELD, status);
return result;
}
void LongNameHandler::simpleFormatsToModifiers(const UnicodeString *simpleFormats, Field field,
- SimpleModifier *output, UErrorCode &status) {
+ UErrorCode &status) {
for (int32_t i = 0; i < StandardPlural::Form::COUNT; i++) {
- UnicodeString simpleFormat = getWithPlural(simpleFormats, i, status);
+ StandardPlural::Form plural = static_cast<StandardPlural::Form>(i);
+ UnicodeString simpleFormat = getWithPlural(simpleFormats, plural, status);
if (U_FAILURE(status)) { return; }
SimpleFormatter compiledFormatter(simpleFormat, 0, 1, status);
if (U_FAILURE(status)) { return; }
- output[i] = SimpleModifier(compiledFormatter, field, false);
+ fModifiers[i] = SimpleModifier(compiledFormatter, field, false, {this, 0, plural});
}
}
void LongNameHandler::multiSimpleFormatsToModifiers(const UnicodeString *leadFormats, UnicodeString trailFormat,
- Field field, SimpleModifier *output, UErrorCode &status) {
+ Field field, UErrorCode &status) {
SimpleFormatter trailCompiled(trailFormat, 1, 1, status);
if (U_FAILURE(status)) { return; }
for (int32_t i = 0; i < StandardPlural::Form::COUNT; i++) {
- UnicodeString leadFormat = getWithPlural(leadFormats, i, status);
+ StandardPlural::Form plural = static_cast<StandardPlural::Form>(i);
+ UnicodeString leadFormat = getWithPlural(leadFormats, plural, status);
if (U_FAILURE(status)) { return; }
UnicodeString compoundFormat;
trailCompiled.format(leadFormat, compoundFormat, status);
if (U_FAILURE(status)) { return; }
SimpleFormatter compoundCompiled(compoundFormat, 0, 1, status);
if (U_FAILURE(status)) { return; }
- output[i] = SimpleModifier(compoundCompiled, field, false);
+ fModifiers[i] = SimpleModifier(compoundCompiled, field, false, {this, 0, plural});
}
}
@@ -265,4 +279,8 @@ void LongNameHandler::processQuantity(DecimalQuantity &quantity, MicroProps &mic
micros.modOuter = &fModifiers[utils::getStandardPlural(rules, copy)];
}
+const Modifier* LongNameHandler::getModifier(int8_t /*signum*/, StandardPlural::Form plural) const {
+ return &fModifiers[plural];
+}
+
#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/deps/icu-small/source/i18n/number_longnames.h b/deps/icu-small/source/i18n/number_longnames.h
index 1d1e7dd3e8..a71d0caadf 100644
--- a/deps/icu-small/source/i18n/number_longnames.h
+++ b/deps/icu-small/source/i18n/number_longnames.h
@@ -14,13 +14,13 @@
U_NAMESPACE_BEGIN namespace number {
namespace impl {
-class LongNameHandler : public MicroPropsGenerator, public UMemory {
+class LongNameHandler : public MicroPropsGenerator, public ModifierStore, public UMemory {
public:
- static LongNameHandler
+ static LongNameHandler*
forCurrencyLongNames(const Locale &loc, const CurrencyUnit &currency, const PluralRules *rules,
const MicroPropsGenerator *parent, UErrorCode &status);
- static LongNameHandler
+ static LongNameHandler*
forMeasureUnit(const Locale &loc, const MeasureUnit &unit, const MeasureUnit &perUnit,
const UNumberUnitWidth &width, const PluralRules *rules,
const MicroPropsGenerator *parent, UErrorCode &status);
@@ -28,6 +28,8 @@ class LongNameHandler : public MicroPropsGenerator, public UMemory {
void
processQuantity(DecimalQuantity &quantity, MicroProps &micros, UErrorCode &status) const U_OVERRIDE;
+ const Modifier* getModifier(int8_t signum, StandardPlural::Form plural) const U_OVERRIDE;
+
private:
SimpleModifier fModifiers[StandardPlural::Form::COUNT];
const PluralRules *rules;
@@ -36,15 +38,14 @@ class LongNameHandler : public MicroPropsGenerator, public UMemory {
LongNameHandler(const PluralRules *rules, const MicroPropsGenerator *parent)
: rules(rules), parent(parent) {}
- static LongNameHandler
+ static LongNameHandler*
forCompoundUnit(const Locale &loc, const MeasureUnit &unit, const MeasureUnit &perUnit,
const UNumberUnitWidth &width, const PluralRules *rules,
const MicroPropsGenerator *parent, UErrorCode &status);
- static void simpleFormatsToModifiers(const UnicodeString *simpleFormats, Field field,
- SimpleModifier *output, UErrorCode &status);
- static void multiSimpleFormatsToModifiers(const UnicodeString *leadFormats, UnicodeString trailFormat,
- Field field, SimpleModifier *output, UErrorCode &status);
+ void simpleFormatsToModifiers(const UnicodeString *simpleFormats, Field field, UErrorCode &status);
+ void multiSimpleFormatsToModifiers(const UnicodeString *leadFormats, UnicodeString trailFormat,
+ Field field, UErrorCode &status);
};
} // namespace impl
diff --git a/deps/icu-small/source/i18n/number_mapper.cpp b/deps/icu-small/source/i18n/number_mapper.cpp
index d260632f93..2c9a8e5178 100644
--- a/deps/icu-small/source/i18n/number_mapper.cpp
+++ b/deps/icu-small/source/i18n/number_mapper.cpp
@@ -225,8 +225,8 @@ MacroProps NumberPropertyMapper::oldToNew(const DecimalFormatProperties& propert
// TODO: Overriding here is a bit of a hack. Should this logic go earlier?
if (macros.precision.fType == Precision::PrecisionType::RND_FRACTION) {
// For the purposes of rounding, get the original min/max int/frac, since the local
- // variables
- // have been manipulated for display purposes.
+ // variables have been manipulated for display purposes.
+ int maxInt_ = properties.maximumIntegerDigits;
int minInt_ = properties.minimumIntegerDigits;
int minFrac_ = properties.minimumFractionDigits;
int maxFrac_ = properties.maximumFractionDigits;
@@ -237,9 +237,15 @@ MacroProps NumberPropertyMapper::oldToNew(const DecimalFormatProperties& propert
// Patterns like "#.##E0" (no zeros in the mantissa), which mean round to maxFrac+1
macros.precision = Precision::constructSignificant(1, maxFrac_ + 1).withMode(roundingMode);
} else {
- // All other scientific patterns, which mean round to minInt+maxFrac
- macros.precision = Precision::constructSignificant(
- minInt_ + minFrac_, minInt_ + maxFrac_).withMode(roundingMode);
+ int maxSig_ = minInt_ + maxFrac_;
+ // Bug #20058: if maxInt_ > minInt_ > 1, then minInt_ should be 1.
+ if (maxInt_ > minInt_ && minInt_ > 1) {
+ minInt_ = 1;
+ }
+ int minSig_ = minInt_ + minFrac_;
+ // To avoid regression, maxSig is not reset when minInt_ set to 1.
+ // TODO: Reset maxSig_ = 1 + minFrac_ to follow the spec.
+ macros.precision = Precision::constructSignificant(minSig_, maxSig_).withMode(roundingMode);
}
}
}
diff --git a/deps/icu-small/source/i18n/number_modifiers.cpp b/deps/icu-small/source/i18n/number_modifiers.cpp
index 4385499b54..d92ec63b08 100644
--- a/deps/icu-small/source/i18n/number_modifiers.cpp
+++ b/deps/icu-small/source/i18n/number_modifiers.cpp
@@ -53,6 +53,21 @@ void U_CALLCONV initDefaultCurrencySpacing(UErrorCode &status) {
Modifier::~Modifier() = default;
+Modifier::Parameters::Parameters()
+ : obj(nullptr) {}
+
+Modifier::Parameters::Parameters(
+ const ModifierStore* _obj, int8_t _signum, StandardPlural::Form _plural)
+ : obj(_obj), signum(_signum), plural(_plural) {}
+
+ModifierStore::~ModifierStore() = default;
+
+AdoptingModifierStore::~AdoptingModifierStore() {
+ for (const Modifier *mod : mods) {
+ delete mod;
+ }
+}
+
int32_t ConstantAffixModifier::apply(NumberStringBuilder &output, int leftIndex, int rightIndex,
UErrorCode &status) const {
@@ -62,13 +77,11 @@ int32_t ConstantAffixModifier::apply(NumberStringBuilder &output, int leftIndex,
return length;
}
-int32_t ConstantAffixModifier::getPrefixLength(UErrorCode &status) const {
- (void)status;
+int32_t ConstantAffixModifier::getPrefixLength() const {
return fPrefix.length();
}
-int32_t ConstantAffixModifier::getCodePointCount(UErrorCode &status) const {
- (void)status;
+int32_t ConstantAffixModifier::getCodePointCount() const {
return fPrefix.countChar32() + fSuffix.countChar32();
}
@@ -76,8 +89,38 @@ bool ConstantAffixModifier::isStrong() const {
return fStrong;
}
+bool ConstantAffixModifier::containsField(UNumberFormatFields field) const {
+ (void)field;
+ // This method is not currently used.
+ U_ASSERT(false);
+ return false;
+}
+
+void ConstantAffixModifier::getParameters(Parameters& output) const {
+ (void)output;
+ // This method is not currently used.
+ U_ASSERT(false);
+}
+
+bool ConstantAffixModifier::semanticallyEquivalent(const Modifier& other) const {
+ auto* _other = dynamic_cast<const ConstantAffixModifier*>(&other);
+ if (_other == nullptr) {
+ return false;
+ }
+ return fPrefix == _other->fPrefix
+ && fSuffix == _other->fSuffix
+ && fField == _other->fField
+ && fStrong == _other->fStrong;
+}
+
+
SimpleModifier::SimpleModifier(const SimpleFormatter &simpleFormatter, Field field, bool strong)
- : fCompiledPattern(simpleFormatter.compiledPattern), fField(field), fStrong(strong) {
+ : SimpleModifier(simpleFormatter, field, strong, {}) {}
+
+SimpleModifier::SimpleModifier(const SimpleFormatter &simpleFormatter, Field field, bool strong,
+ const Modifier::Parameters parameters)
+ : fCompiledPattern(simpleFormatter.compiledPattern), fField(field), fStrong(strong),
+ fParameters(parameters) {
int32_t argLimit = SimpleFormatter::getArgumentLimit(
fCompiledPattern.getBuffer(), fCompiledPattern.length());
if (argLimit == 0) {
@@ -90,15 +133,19 @@ SimpleModifier::SimpleModifier(const SimpleFormatter &simpleFormatter, Field fie
} else {
U_ASSERT(argLimit == 1);
if (fCompiledPattern.charAt(1) != 0) {
+ // Found prefix
fPrefixLength = fCompiledPattern.charAt(1) - ARG_NUM_LIMIT;
fSuffixOffset = 3 + fPrefixLength;
} else {
+ // No prefix
fPrefixLength = 0;
fSuffixOffset = 2;
}
if (3 + fPrefixLength < fCompiledPattern.length()) {
+ // Found suffix
fSuffixLength = fCompiledPattern.charAt(fSuffixOffset) - ARG_NUM_LIMIT;
} else {
+ // No suffix
fSuffixLength = 0;
}
}
@@ -113,13 +160,11 @@ int32_t SimpleModifier::apply(NumberStringBuilder &output, int leftIndex, int ri
return formatAsPrefixSuffix(output, leftIndex, rightIndex, fField, status);
}
-int32_t SimpleModifier::getPrefixLength(UErrorCode &status) const {
- (void)status;
+int32_t SimpleModifier::getPrefixLength() const {
return fPrefixLength;
}
-int32_t SimpleModifier::getCodePointCount(UErrorCode &status) const {
- (void)status;
+int32_t SimpleModifier::getCodePointCount() const {
int32_t count = 0;
if (fPrefixLength > 0) {
count += fCompiledPattern.countChar32(2, fPrefixLength);
@@ -134,10 +179,35 @@ bool SimpleModifier::isStrong() const {
return fStrong;
}
+bool SimpleModifier::containsField(UNumberFormatFields field) const {
+ (void)field;
+ // This method is not currently used.
+ U_ASSERT(false);
+ return false;
+}
+
+void SimpleModifier::getParameters(Parameters& output) const {
+ output = fParameters;
+}
+
+bool SimpleModifier::semanticallyEquivalent(const Modifier& other) const {
+ auto* _other = dynamic_cast<const SimpleModifier*>(&other);
+ if (_other == nullptr) {
+ return false;
+ }
+ if (fParameters.obj != nullptr) {
+ return fParameters.obj == _other->fParameters.obj;
+ }
+ return fCompiledPattern == _other->fCompiledPattern
+ && fField == _other->fField
+ && fStrong == _other->fStrong;
+}
+
+
int32_t
SimpleModifier::formatAsPrefixSuffix(NumberStringBuilder &result, int32_t startIndex, int32_t endIndex,
Field field, UErrorCode &status) const {
- if (fSuffixOffset == -1) {
+ if (fSuffixOffset == -1 && fPrefixLength + fSuffixLength > 0) {
// There is no argument for the inner number; overwrite the entire segment with our string.
return result.splice(startIndex, endIndex, fCompiledPattern, 2, 2 + fPrefixLength, field, status);
} else {
@@ -157,6 +227,65 @@ SimpleModifier::formatAsPrefixSuffix(NumberStringBuilder &result, int32_t startI
}
}
+
+int32_t
+SimpleModifier::formatTwoArgPattern(const SimpleFormatter& compiled, NumberStringBuilder& result,
+ int32_t index, int32_t* outPrefixLength, int32_t* outSuffixLength,
+ Field field, UErrorCode& status) {
+ const UnicodeString& compiledPattern = compiled.compiledPattern;
+ int32_t argLimit = SimpleFormatter::getArgumentLimit(
+ compiledPattern.getBuffer(), compiledPattern.length());
+ if (argLimit != 2) {
+ status = U_INTERNAL_PROGRAM_ERROR;
+ return 0;
+ }
+ int32_t offset = 1; // offset into compiledPattern
+ int32_t length = 0; // chars added to result
+
+ int32_t prefixLength = compiledPattern.charAt(offset);
+ offset++;
+ if (prefixLength < ARG_NUM_LIMIT) {
+ // No prefix
+ prefixLength = 0;
+ } else {
+ prefixLength -= ARG_NUM_LIMIT;
+ result.insert(index + length, compiledPattern, offset, offset + prefixLength, field, status);
+ offset += prefixLength;
+ length += prefixLength;
+ offset++;
+ }
+
+ int32_t infixLength = compiledPattern.charAt(offset);
+ offset++;
+ if (infixLength < ARG_NUM_LIMIT) {
+ // No infix
+ infixLength = 0;
+ } else {
+ infixLength -= ARG_NUM_LIMIT;
+ result.insert(index + length, compiledPattern, offset, offset + infixLength, field, status);
+ offset += infixLength;
+ length += infixLength;
+ offset++;
+ }
+
+ int32_t suffixLength;
+ if (offset == compiledPattern.length()) {
+ // No suffix
+ suffixLength = 0;
+ } else {
+ suffixLength = compiledPattern.charAt(offset) - ARG_NUM_LIMIT;
+ offset++;
+ result.insert(index + length, compiledPattern, offset, offset + suffixLength, field, status);
+ length += suffixLength;
+ }
+
+ *outPrefixLength = prefixLength;
+ *outSuffixLength = suffixLength;
+
+ return length;
+}
+
+
int32_t ConstantMultiFieldModifier::apply(NumberStringBuilder &output, int leftIndex, int rightIndex,
UErrorCode &status) const {
int32_t length = output.insert(leftIndex, fPrefix, status);
@@ -171,13 +300,11 @@ int32_t ConstantMultiFieldModifier::apply(NumberStringBuilder &output, int leftI
return length;
}
-int32_t ConstantMultiFieldModifier::getPrefixLength(UErrorCode &status) const {
- (void)status;
+int32_t ConstantMultiFieldModifier::getPrefixLength() const {
return fPrefix.length();
}
-int32_t ConstantMultiFieldModifier::getCodePointCount(UErrorCode &status) const {
- (void)status;
+int32_t ConstantMultiFieldModifier::getCodePointCount() const {
return fPrefix.codePointCount() + fSuffix.codePointCount();
}
@@ -185,6 +312,29 @@ bool ConstantMultiFieldModifier::isStrong() const {
return fStrong;
}
+bool ConstantMultiFieldModifier::containsField(UNumberFormatFields field) const {
+ return fPrefix.containsField(field) || fSuffix.containsField(field);
+}
+
+void ConstantMultiFieldModifier::getParameters(Parameters& output) const {
+ output = fParameters;
+}
+
+bool ConstantMultiFieldModifier::semanticallyEquivalent(const Modifier& other) const {
+ auto* _other = dynamic_cast<const ConstantMultiFieldModifier*>(&other);
+ if (_other == nullptr) {
+ return false;
+ }
+ if (fParameters.obj != nullptr) {
+ return fParameters.obj == _other->fParameters.obj;
+ }
+ return fPrefix.contentEquals(_other->fPrefix)
+ && fSuffix.contentEquals(_other->fSuffix)
+ && fOverwrite == _other->fOverwrite
+ && fStrong == _other->fStrong;
+}
+
+
CurrencySpacingEnabledModifier::CurrencySpacingEnabledModifier(const NumberStringBuilder &prefix,
const NumberStringBuilder &suffix,
bool overwrite,
diff --git a/deps/icu-small/source/i18n/number_modifiers.h b/deps/icu-small/source/i18n/number_modifiers.h
index a553100cd9..65ada937d0 100644
--- a/deps/icu-small/source/i18n/number_modifiers.h
+++ b/deps/icu-small/source/i18n/number_modifiers.h
@@ -31,12 +31,18 @@ class U_I18N_API ConstantAffixModifier : public Modifier, public UObject {
int32_t apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
UErrorCode &status) const U_OVERRIDE;
- int32_t getPrefixLength(UErrorCode &status) const U_OVERRIDE;
+ int32_t getPrefixLength() const U_OVERRIDE;
- int32_t getCodePointCount(UErrorCode &status) const U_OVERRIDE;
+ int32_t getCodePointCount() const U_OVERRIDE;
bool isStrong() const U_OVERRIDE;
+ bool containsField(UNumberFormatFields field) const U_OVERRIDE;
+
+ void getParameters(Parameters& output) const U_OVERRIDE;
+
+ bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
+
private:
UnicodeString fPrefix;
UnicodeString fSuffix;
@@ -52,21 +58,30 @@ class U_I18N_API SimpleModifier : public Modifier, public UMemory {
public:
SimpleModifier(const SimpleFormatter &simpleFormatter, Field field, bool strong);
+ SimpleModifier(const SimpleFormatter &simpleFormatter, Field field, bool strong,
+ const Modifier::Parameters parameters);
+
// Default constructor for LongNameHandler.h
SimpleModifier();
int32_t apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
UErrorCode &status) const U_OVERRIDE;
- int32_t getPrefixLength(UErrorCode &status) const U_OVERRIDE;
+ int32_t getPrefixLength() const U_OVERRIDE;
- int32_t getCodePointCount(UErrorCode &status) const U_OVERRIDE;
+ int32_t getCodePointCount() const U_OVERRIDE;
bool isStrong() const U_OVERRIDE;
+ bool containsField(UNumberFormatFields field) const U_OVERRIDE;
+
+ void getParameters(Parameters& output) const U_OVERRIDE;
+
+ bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
+
/**
* TODO: This belongs in SimpleFormatterImpl. The only reason I haven't moved it there yet is because
- * DoubleSidedStringBuilder is an internal class and SimpleFormatterImpl feels like it should not depend on it.
+ * NumberStringBuilder is an internal class and SimpleFormatterImpl feels like it should not depend on it.
*
* <p>
* Formats a value that is already stored inside the StringBuilder <code>result</code> between the indices
@@ -85,16 +100,33 @@ class U_I18N_API SimpleModifier : public Modifier, public UMemory {
* @return The number of characters (UTF-16 code points) that were added to the StringBuilder.
*/
int32_t
- formatAsPrefixSuffix(NumberStringBuilder &result, int32_t startIndex, int32_t endIndex, Field field,
- UErrorCode &status) const;
+ formatAsPrefixSuffix(NumberStringBuilder& result, int32_t startIndex, int32_t endIndex, Field field,
+ UErrorCode& status) const;
+
+ /**
+ * TODO: Like above, this belongs with the rest of the SimpleFormatterImpl code.
+ * I put it here so that the SimpleFormatter uses in NumberStringBuilder are near each other.
+ *
+ * <p>
+ * Applies the compiled two-argument pattern to the NumberStringBuilder.
+ *
+ * <p>
+ * This method is optimized for the case where the prefix and suffix are often empty, such as
+ * in the range pattern like "{0}-{1}".
+ */
+ static int32_t
+ formatTwoArgPattern(const SimpleFormatter& compiled, NumberStringBuilder& result,
+ int32_t index, int32_t* outPrefixLength, int32_t* outSuffixLength,
+ Field field, UErrorCode& status);
private:
UnicodeString fCompiledPattern;
Field fField;
- bool fStrong;
- int32_t fPrefixLength;
- int32_t fSuffixOffset;
- int32_t fSuffixLength;
+ bool fStrong = false;
+ int32_t fPrefixLength = 0;
+ int32_t fSuffixOffset = -1;
+ int32_t fSuffixLength = 0;
+ Modifier::Parameters fParameters;
};
/**
@@ -107,6 +139,18 @@ class U_I18N_API ConstantMultiFieldModifier : public Modifier, public UMemory {
const NumberStringBuilder &prefix,
const NumberStringBuilder &suffix,
bool overwrite,
+ bool strong,
+ const Modifier::Parameters parameters)
+ : fPrefix(prefix),
+ fSuffix(suffix),
+ fOverwrite(overwrite),
+ fStrong(strong),
+ fParameters(parameters) {}
+
+ ConstantMultiFieldModifier(
+ const NumberStringBuilder &prefix,
+ const NumberStringBuilder &suffix,
+ bool overwrite,
bool strong)
: fPrefix(prefix),
fSuffix(suffix),
@@ -116,12 +160,18 @@ class U_I18N_API ConstantMultiFieldModifier : public Modifier, public UMemory {
int32_t apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
UErrorCode &status) const U_OVERRIDE;
- int32_t getPrefixLength(UErrorCode &status) const U_OVERRIDE;
+ int32_t getPrefixLength() const U_OVERRIDE;
- int32_t getCodePointCount(UErrorCode &status) const U_OVERRIDE;
+ int32_t getCodePointCount() const U_OVERRIDE;
bool isStrong() const U_OVERRIDE;
+ bool containsField(UNumberFormatFields field) const U_OVERRIDE;
+
+ void getParameters(Parameters& output) const U_OVERRIDE;
+
+ bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
+
protected:
// NOTE: In Java, these are stored as array pointers. In C++, the NumberStringBuilder is stored by
// value and is treated internally as immutable.
@@ -129,6 +179,7 @@ class U_I18N_API ConstantMultiFieldModifier : public Modifier, public UMemory {
NumberStringBuilder fSuffix;
bool fOverwrite;
bool fStrong;
+ Modifier::Parameters fParameters;
};
/** Identical to {@link ConstantMultiFieldModifier}, but supports currency spacing. */
@@ -192,13 +243,11 @@ class U_I18N_API EmptyModifier : public Modifier, public UMemory {
return 0;
}
- int32_t getPrefixLength(UErrorCode &status) const U_OVERRIDE {
- (void)status;
+ int32_t getPrefixLength() const U_OVERRIDE {
return 0;
}
- int32_t getCodePointCount(UErrorCode &status) const U_OVERRIDE {
- (void)status;
+ int32_t getCodePointCount() const U_OVERRIDE {
return 0;
}
@@ -206,55 +255,75 @@ class U_I18N_API EmptyModifier : public Modifier, public UMemory {
return fStrong;
}
+ bool containsField(UNumberFormatFields field) const U_OVERRIDE {
+ (void)field;
+ return false;
+ }
+
+ void getParameters(Parameters& output) const U_OVERRIDE {
+ output.obj = nullptr;
+ }
+
+ bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE {
+ return other.getCodePointCount() == 0;
+ }
+
private:
bool fStrong;
};
/**
- * A ParameterizedModifier by itself is NOT a Modifier. Rather, it wraps a data structure containing two or more
- * Modifiers and returns the modifier appropriate for the current situation.
+ * This implementation of ModifierStore adopts Modifer pointers.
*/
-class U_I18N_API ParameterizedModifier : public UMemory {
+class U_I18N_API AdoptingModifierStore : public ModifierStore, public UMemory {
public:
- // NOTE: mods is zero-initialized (to nullptr)
- ParameterizedModifier() : mods() {
- }
+ virtual ~AdoptingModifierStore();
- // No copying!
- ParameterizedModifier(const ParameterizedModifier &other) = delete;
+ static constexpr StandardPlural::Form DEFAULT_STANDARD_PLURAL = StandardPlural::OTHER;
- ~ParameterizedModifier() {
- for (const Modifier *mod : mods) {
- delete mod;
- }
- }
+ AdoptingModifierStore() = default;
- void adoptPositiveNegativeModifiers(
- const Modifier *positive, const Modifier *zero, const Modifier *negative) {
- mods[2] = positive;
- mods[1] = zero;
- mods[0] = negative;
- }
+ // No copying!
+ AdoptingModifierStore(const AdoptingModifierStore &other) = delete;
- /** The modifier is ADOPTED. */
- void adoptSignPluralModifier(int8_t signum, StandardPlural::Form plural, const Modifier *mod) {
+ /**
+ * Sets the Modifier with the specified signum and plural form.
+ */
+ void adoptModifier(int8_t signum, StandardPlural::Form plural, const Modifier *mod) {
+ U_ASSERT(mods[getModIndex(signum, plural)] == nullptr);
mods[getModIndex(signum, plural)] = mod;
}
+ /**
+ * Sets the Modifier with the specified signum.
+ * The modifier will apply to all plural forms.
+ */
+ void adoptModifierWithoutPlural(int8_t signum, const Modifier *mod) {
+ U_ASSERT(mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)] == nullptr);
+ mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)] = mod;
+ }
+
/** Returns a reference to the modifier; no ownership change. */
- const Modifier *getModifier(int8_t signum) const {
- return mods[signum + 1];
+ const Modifier *getModifier(int8_t signum, StandardPlural::Form plural) const U_OVERRIDE {
+ const Modifier* modifier = mods[getModIndex(signum, plural)];
+ if (modifier == nullptr && plural != DEFAULT_STANDARD_PLURAL) {
+ modifier = mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)];
+ }
+ return modifier;
}
/** Returns a reference to the modifier; no ownership change. */
- const Modifier *getModifier(int8_t signum, StandardPlural::Form plural) const {
- return mods[getModIndex(signum, plural)];
+ const Modifier *getModifierWithoutPlural(int8_t signum) const {
+ return mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)];
}
private:
- const Modifier *mods[3 * StandardPlural::COUNT];
+ // NOTE: mods is zero-initialized (to nullptr)
+ const Modifier *mods[3 * StandardPlural::COUNT] = {};
inline static int32_t getModIndex(int8_t signum, StandardPlural::Form plural) {
+ U_ASSERT(signum >= -1 && signum <= 1);
+ U_ASSERT(plural >= 0 && plural < StandardPlural::COUNT);
return static_cast<int32_t>(plural) * 3 + (signum + 1);
}
};
diff --git a/deps/icu-small/source/i18n/number_multiplier.cpp b/deps/icu-small/source/i18n/number_multiplier.cpp
index a27142c9bd..ecb50dd9b8 100644
--- a/deps/icu-small/source/i18n/number_multiplier.cpp
+++ b/deps/icu-small/source/i18n/number_multiplier.cpp
@@ -143,14 +143,14 @@ void Scale::applyReciprocalTo(impl::DecimalQuantity& quantity) const {
void
MultiplierFormatHandler::setAndChain(const Scale& multiplier, const MicroPropsGenerator* parent) {
- this->multiplier = multiplier;
- this->parent = parent;
+ fMultiplier = multiplier;
+ fParent = parent;
}
void MultiplierFormatHandler::processQuantity(DecimalQuantity& quantity, MicroProps& micros,
UErrorCode& status) const {
- parent->processQuantity(quantity, micros, status);
- multiplier.applyTo(quantity);
+ fParent->processQuantity(quantity, micros, status);
+ fMultiplier.applyTo(quantity);
}
#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/deps/icu-small/source/i18n/number_multiplier.h b/deps/icu-small/source/i18n/number_multiplier.h
index 82c30c7842..d8235dc601 100644
--- a/deps/icu-small/source/i18n/number_multiplier.h
+++ b/deps/icu-small/source/i18n/number_multiplier.h
@@ -28,8 +28,8 @@ class U_I18N_API MultiplierFormatHandler : public MicroPropsGenerator, public UM
UErrorCode& status) const U_OVERRIDE;
private:
- Scale multiplier;
- const MicroPropsGenerator *parent;
+ Scale fMultiplier;
+ const MicroPropsGenerator *fParent;
};
diff --git a/deps/icu-small/source/i18n/number_padding.cpp b/deps/icu-small/source/i18n/number_padding.cpp
index 97e7b6014f..31684d7208 100644
--- a/deps/icu-small/source/i18n/number_padding.cpp
+++ b/deps/icu-small/source/i18n/number_padding.cpp
@@ -62,7 +62,7 @@ Padder Padder::forProperties(const DecimalFormatProperties& properties) {
int32_t Padder::padAndApply(const Modifier &mod1, const Modifier &mod2,
NumberStringBuilder &string, int32_t leftIndex, int32_t rightIndex,
UErrorCode &status) const {
- int32_t modLength = mod1.getCodePointCount(status) + mod2.getCodePointCount(status);
+ int32_t modLength = mod1.getCodePointCount() + mod2.getCodePointCount();
int32_t requiredPadding = fWidth - modLength - string.codePointCount();
U_ASSERT(leftIndex == 0 &&
rightIndex == string.length()); // fix the previous line to remove this assertion
diff --git a/deps/icu-small/source/i18n/number_patternmodifier.cpp b/deps/icu-small/source/i18n/number_patternmodifier.cpp
index 6417e14378..4c61a0d35b 100644
--- a/deps/icu-small/source/i18n/number_patternmodifier.cpp
+++ b/deps/icu-small/source/i18n/number_patternmodifier.cpp
@@ -24,11 +24,11 @@ MutablePatternModifier::MutablePatternModifier(bool isStrong)
: fStrong(isStrong) {}
void MutablePatternModifier::setPatternInfo(const AffixPatternProvider* patternInfo) {
- this->patternInfo = patternInfo;
+ fPatternInfo = patternInfo;
}
void MutablePatternModifier::setPatternAttributes(UNumberSignDisplay signDisplay, bool perMille) {
- this->signDisplay = signDisplay;
+ fSignDisplay = signDisplay;
this->perMilleReplacesPercent = perMille;
}
@@ -36,20 +36,20 @@ void MutablePatternModifier::setSymbols(const DecimalFormatSymbols* symbols,
const CurrencySymbols* currencySymbols,
const UNumberUnitWidth unitWidth, const PluralRules* rules) {
U_ASSERT((rules != nullptr) == needsPlurals());
- this->symbols = symbols;
- this->currencySymbols = currencySymbols;
- this->unitWidth = unitWidth;
- this->rules = rules;
+ fSymbols = symbols;
+ fCurrencySymbols = currencySymbols;
+ fUnitWidth = unitWidth;
+ fRules = rules;
}
void MutablePatternModifier::setNumberProperties(int8_t signum, StandardPlural::Form plural) {
- this->signum = signum;
- this->plural = plural;
+ fSignum = signum;
+ fPlural = plural;
}
bool MutablePatternModifier::needsPlurals() const {
UErrorCode statusLocal = U_ZERO_ERROR;
- return patternInfo->containsSymbolType(AffixPatternType::TYPE_CURRENCY_TRIPLE, statusLocal);
+ return fPatternInfo->containsSymbolType(AffixPatternType::TYPE_CURRENCY_TRIPLE, statusLocal);
// Silently ignore any error codes.
}
@@ -69,7 +69,7 @@ MutablePatternModifier::createImmutableAndChain(const MicroPropsGenerator* paren
StandardPlural::Form::MANY,
StandardPlural::Form::OTHER};
- auto pm = new ParameterizedModifier();
+ auto pm = new AdoptingModifierStore();
if (pm == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
return nullptr;
@@ -79,26 +79,25 @@ MutablePatternModifier::createImmutableAndChain(const MicroPropsGenerator* paren
// Slower path when we require the plural keyword.
for (StandardPlural::Form plural : STANDARD_PLURAL_VALUES) {
setNumberProperties(1, plural);
- pm->adoptSignPluralModifier(1, plural, createConstantModifier(status));
+ pm->adoptModifier(1, plural, createConstantModifier(status));
setNumberProperties(0, plural);
- pm->adoptSignPluralModifier(0, plural, createConstantModifier(status));
+ pm->adoptModifier(0, plural, createConstantModifier(status));
setNumberProperties(-1, plural);
- pm->adoptSignPluralModifier(-1, plural, createConstantModifier(status));
+ pm->adoptModifier(-1, plural, createConstantModifier(status));
}
if (U_FAILURE(status)) {
delete pm;
return nullptr;
}
- return new ImmutablePatternModifier(pm, rules, parent); // adopts pm
+ return new ImmutablePatternModifier(pm, fRules, parent); // adopts pm
} else {
// Faster path when plural keyword is not needed.
setNumberProperties(1, StandardPlural::Form::COUNT);
- Modifier* positive = createConstantModifier(status);
+ pm->adoptModifierWithoutPlural(1, createConstantModifier(status));
setNumberProperties(0, StandardPlural::Form::COUNT);
- Modifier* zero = createConstantModifier(status);
+ pm->adoptModifierWithoutPlural(0, createConstantModifier(status));
setNumberProperties(-1, StandardPlural::Form::COUNT);
- Modifier* negative = createConstantModifier(status);
- pm->adoptPositiveNegativeModifiers(positive, zero, negative);
+ pm->adoptModifierWithoutPlural(-1, createConstantModifier(status));
if (U_FAILURE(status)) {
delete pm;
return nullptr;
@@ -112,15 +111,15 @@ ConstantMultiFieldModifier* MutablePatternModifier::createConstantModifier(UErro
NumberStringBuilder b;
insertPrefix(a, 0, status);
insertSuffix(b, 0, status);
- if (patternInfo->hasCurrencySign()) {
+ if (fPatternInfo->hasCurrencySign()) {
return new CurrencySpacingEnabledModifier(
- a, b, !patternInfo->hasBody(), fStrong, *symbols, status);
+ a, b, !fPatternInfo->hasBody(), fStrong, *fSymbols, status);
} else {
- return new ConstantMultiFieldModifier(a, b, !patternInfo->hasBody(), fStrong);
+ return new ConstantMultiFieldModifier(a, b, !fPatternInfo->hasBody(), fStrong);
}
}
-ImmutablePatternModifier::ImmutablePatternModifier(ParameterizedModifier* pm, const PluralRules* rules,
+ImmutablePatternModifier::ImmutablePatternModifier(AdoptingModifierStore* pm, const PluralRules* rules,
const MicroPropsGenerator* parent)
: pm(pm), rules(rules), parent(parent) {}
@@ -132,7 +131,7 @@ void ImmutablePatternModifier::processQuantity(DecimalQuantity& quantity, MicroP
void ImmutablePatternModifier::applyToMicros(MicroProps& micros, DecimalQuantity& quantity) const {
if (rules == nullptr) {
- micros.modMiddle = pm->getModifier(quantity.signum());
+ micros.modMiddle = pm->getModifierWithoutPlural(quantity.signum());
} else {
// TODO: Fix this. Avoid the copy.
DecimalQuantity copy(quantity);
@@ -144,7 +143,7 @@ void ImmutablePatternModifier::applyToMicros(MicroProps& micros, DecimalQuantity
const Modifier* ImmutablePatternModifier::getModifier(int8_t signum, StandardPlural::Form plural) const {
if (rules == nullptr) {
- return pm->getModifier(signum);
+ return pm->getModifierWithoutPlural(signum);
} else {
return pm->getModifier(signum, plural);
}
@@ -153,13 +152,13 @@ const Modifier* ImmutablePatternModifier::getModifier(int8_t signum, StandardPlu
/** Used by the unsafe code path. */
MicroPropsGenerator& MutablePatternModifier::addToChain(const MicroPropsGenerator* parent) {
- this->parent = parent;
+ fParent = parent;
return *this;
}
void MutablePatternModifier::processQuantity(DecimalQuantity& fq, MicroProps& micros,
UErrorCode& status) const {
- parent->processQuantity(fq, micros, status);
+ fParent->processQuantity(fq, micros, status);
// The unsafe code path performs self-mutation, so we need a const_cast.
// This method needs to be const because it overrides a const method in the parent class.
auto nonConstThis = const_cast<MutablePatternModifier*>(this);
@@ -167,7 +166,7 @@ void MutablePatternModifier::processQuantity(DecimalQuantity& fq, MicroProps& mi
// TODO: Fix this. Avoid the copy.
DecimalQuantity copy(fq);
micros.rounder.apply(copy, status);
- nonConstThis->setNumberProperties(fq.signum(), utils::getStandardPlural(rules, copy));
+ nonConstThis->setNumberProperties(fq.signum(), utils::getStandardPlural(fRules, copy));
} else {
nonConstThis->setNumberProperties(fq.signum(), StandardPlural::Form::COUNT);
}
@@ -183,7 +182,7 @@ int32_t MutablePatternModifier::apply(NumberStringBuilder& output, int32_t leftI
int32_t suffixLen = nonConstThis->insertSuffix(output, rightIndex + prefixLen, status);
// If the pattern had no decimal stem body (like #,##0.00), overwrite the value.
int32_t overwriteLen = 0;
- if (!patternInfo->hasBody()) {
+ if (!fPatternInfo->hasBody()) {
overwriteLen = output.splice(
leftIndex + prefixLen,
rightIndex + prefixLen,
@@ -199,28 +198,30 @@ int32_t MutablePatternModifier::apply(NumberStringBuilder& output, int32_t leftI
prefixLen,
rightIndex + overwriteLen + prefixLen,
suffixLen,
- *symbols,
+ *fSymbols,
status);
return prefixLen + overwriteLen + suffixLen;
}
-int32_t MutablePatternModifier::getPrefixLength(UErrorCode& status) const {
+int32_t MutablePatternModifier::getPrefixLength() const {
// The unsafe code path performs self-mutation, so we need a const_cast.
// This method needs to be const because it overrides a const method in the parent class.
auto nonConstThis = const_cast<MutablePatternModifier*>(this);
// Enter and exit CharSequence Mode to get the length.
+ UErrorCode status = U_ZERO_ERROR; // status fails only with an iilegal argument exception
nonConstThis->prepareAffix(true);
int result = AffixUtils::unescapedCodePointCount(currentAffix, *this, status); // prefix length
return result;
}
-int32_t MutablePatternModifier::getCodePointCount(UErrorCode& status) const {
+int32_t MutablePatternModifier::getCodePointCount() const {
// The unsafe code path performs self-mutation, so we need a const_cast.
// This method needs to be const because it overrides a const method in the parent class.
auto nonConstThis = const_cast<MutablePatternModifier*>(this);
// Render the affixes to get the length
+ UErrorCode status = U_ZERO_ERROR; // status fails only with an iilegal argument exception
nonConstThis->prepareAffix(true);
int result = AffixUtils::unescapedCodePointCount(currentAffix, *this, status); // prefix length
nonConstThis->prepareAffix(false);
@@ -232,6 +233,26 @@ bool MutablePatternModifier::isStrong() const {
return fStrong;
}
+bool MutablePatternModifier::containsField(UNumberFormatFields field) const {
+ (void)field;
+ // This method is not currently used.
+ U_ASSERT(false);
+ return false;
+}
+
+void MutablePatternModifier::getParameters(Parameters& output) const {
+ (void)output;
+ // This method is not currently used.
+ U_ASSERT(false);
+}
+
+bool MutablePatternModifier::semanticallyEquivalent(const Modifier& other) const {
+ (void)other;
+ // This method is not currently used.
+ U_ASSERT(false);
+ return false;
+}
+
int32_t MutablePatternModifier::insertPrefix(NumberStringBuilder& sb, int position, UErrorCode& status) {
prepareAffix(true);
int length = AffixUtils::unescape(currentAffix, sb, position, *this, status);
@@ -247,40 +268,40 @@ int32_t MutablePatternModifier::insertSuffix(NumberStringBuilder& sb, int positi
/** This method contains the heart of the logic for rendering LDML affix strings. */
void MutablePatternModifier::prepareAffix(bool isPrefix) {
PatternStringUtils::patternInfoToStringBuilder(
- *patternInfo, isPrefix, signum, signDisplay, plural, perMilleReplacesPercent, currentAffix);
+ *fPatternInfo, isPrefix, fSignum, fSignDisplay, fPlural, perMilleReplacesPercent, currentAffix);
}
UnicodeString MutablePatternModifier::getSymbol(AffixPatternType type) const {
UErrorCode localStatus = U_ZERO_ERROR;
switch (type) {
case AffixPatternType::TYPE_MINUS_SIGN:
- return symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kMinusSignSymbol);
+ return fSymbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kMinusSignSymbol);
case AffixPatternType::TYPE_PLUS_SIGN:
- return symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPlusSignSymbol);
+ return fSymbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPlusSignSymbol);
case AffixPatternType::TYPE_PERCENT:
- return symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPercentSymbol);
+ return fSymbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPercentSymbol);
case AffixPatternType::TYPE_PERMILLE:
- return symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPerMillSymbol);
+ return fSymbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPerMillSymbol);
case AffixPatternType::TYPE_CURRENCY_SINGLE: {
// UnitWidth ISO and HIDDEN overrides the singular currency symbol.
- if (unitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE) {
- return currencySymbols->getIntlCurrencySymbol(localStatus);
- } else if (unitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_HIDDEN) {
+ if (fUnitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE) {
+ return fCurrencySymbols->getIntlCurrencySymbol(localStatus);
+ } else if (fUnitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_HIDDEN) {
return UnicodeString();
- } else if (unitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW) {
- return currencySymbols->getNarrowCurrencySymbol(localStatus);
+ } else if (fUnitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW) {
+ return fCurrencySymbols->getNarrowCurrencySymbol(localStatus);
} else {
- return currencySymbols->getCurrencySymbol(localStatus);
+ return fCurrencySymbols->getCurrencySymbol(localStatus);
}
}
case AffixPatternType::TYPE_CURRENCY_DOUBLE:
- return currencySymbols->getIntlCurrencySymbol(localStatus);
+ return fCurrencySymbols->getIntlCurrencySymbol(localStatus);
case AffixPatternType::TYPE_CURRENCY_TRIPLE:
// NOTE: This is the code path only for patterns containing "¤¤¤".
// Plural currencies set via the API are formatted in LongNameHandler.
// This code path is used by DecimalFormat via CurrencyPluralInfo.
- U_ASSERT(plural != StandardPlural::Form::COUNT);
- return currencySymbols->getPluralName(plural, localStatus);
+ U_ASSERT(fPlural != StandardPlural::Form::COUNT);
+ return fCurrencySymbols->getPluralName(fPlural, localStatus);
case AffixPatternType::TYPE_CURRENCY_QUAD:
return UnicodeString(u"\uFFFD");
case AffixPatternType::TYPE_CURRENCY_QUINT:
diff --git a/deps/icu-small/source/i18n/number_patternmodifier.h b/deps/icu-small/source/i18n/number_patternmodifier.h
index f1359bd574..ea80d6305e 100644
--- a/deps/icu-small/source/i18n/number_patternmodifier.h
+++ b/deps/icu-small/source/i18n/number_patternmodifier.h
@@ -18,13 +18,13 @@
U_NAMESPACE_BEGIN
// Export an explicit template instantiation of the LocalPointer that is used as a
-// data member of ParameterizedModifier.
+// data member of AdoptingModifierStore.
// (When building DLLs for Windows this is required.)
#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
// Ignore warning 4661 as LocalPointerBase does not use operator== or operator!=
#pragma warning(suppress: 4661)
-template class U_I18N_API LocalPointerBase<number::impl::ParameterizedModifier>;
-template class U_I18N_API LocalPointer<number::impl::ParameterizedModifier>;
+template class U_I18N_API LocalPointerBase<number::impl::AdoptingModifierStore>;
+template class U_I18N_API LocalPointer<number::impl::AdoptingModifierStore>;
#endif
namespace number {
@@ -45,10 +45,10 @@ class U_I18N_API ImmutablePatternModifier : public MicroPropsGenerator, public U
const Modifier* getModifier(int8_t signum, StandardPlural::Form plural) const;
private:
- ImmutablePatternModifier(ParameterizedModifier* pm, const PluralRules* rules,
+ ImmutablePatternModifier(AdoptingModifierStore* pm, const PluralRules* rules,
const MicroPropsGenerator* parent);
- const LocalPointer<ParameterizedModifier> pm;
+ const LocalPointer<AdoptingModifierStore> pm;
const PluralRules* rules;
const MicroPropsGenerator* parent;
@@ -178,12 +178,18 @@ class U_I18N_API MutablePatternModifier
int32_t apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
UErrorCode &status) const U_OVERRIDE;
- int32_t getPrefixLength(UErrorCode &status) const U_OVERRIDE;
+ int32_t getPrefixLength() const U_OVERRIDE;
- int32_t getCodePointCount(UErrorCode &status) const U_OVERRIDE;
+ int32_t getCodePointCount() const U_OVERRIDE;
bool isStrong() const U_OVERRIDE;
+ bool containsField(UNumberFormatFields field) const U_OVERRIDE;
+
+ void getParameters(Parameters& output) const U_OVERRIDE;
+
+ bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
+
/**
* Returns the string that substitutes a given symbol type in a pattern.
*/
@@ -196,22 +202,22 @@ class U_I18N_API MutablePatternModifier
const bool fStrong;
// Pattern details (initialized in setPatternInfo and setPatternAttributes)
- const AffixPatternProvider *patternInfo;
- UNumberSignDisplay signDisplay;
+ const AffixPatternProvider *fPatternInfo;
+ UNumberSignDisplay fSignDisplay;
bool perMilleReplacesPercent;
// Symbol details (initialized in setSymbols)
- const DecimalFormatSymbols *symbols;
- UNumberUnitWidth unitWidth;
- const CurrencySymbols *currencySymbols;
- const PluralRules *rules;
+ const DecimalFormatSymbols *fSymbols;
+ UNumberUnitWidth fUnitWidth;
+ const CurrencySymbols *fCurrencySymbols;
+ const PluralRules *fRules;
// Number details (initialized in setNumberProperties)
- int8_t signum;
- StandardPlural::Form plural;
+ int8_t fSignum;
+ StandardPlural::Form fPlural;
// QuantityChain details (initialized in addToChain)
- const MicroPropsGenerator *parent;
+ const MicroPropsGenerator *fParent;
// Transient fields for rendering
UnicodeString currentAffix;
diff --git a/deps/icu-small/source/i18n/number_scientific.cpp b/deps/icu-small/source/i18n/number_scientific.cpp
index 40952024e9..07c1ce9dac 100644
--- a/deps/icu-small/source/i18n/number_scientific.cpp
+++ b/deps/icu-small/source/i18n/number_scientific.cpp
@@ -76,17 +76,16 @@ int32_t ScientificModifier::apply(NumberStringBuilder &output, int32_t /*leftInd
return i - rightIndex;
}
-int32_t ScientificModifier::getPrefixLength(UErrorCode &status) const {
- (void)status;
+int32_t ScientificModifier::getPrefixLength() const {
// TODO: Localized exponent separator location.
return 0;
}
-int32_t ScientificModifier::getCodePointCount(UErrorCode &status) const {
- (void)status;
- // This method is not used for strong modifiers.
- U_ASSERT(false);
- return 0;
+int32_t ScientificModifier::getCodePointCount() const {
+ // NOTE: This method is only called one place, NumberRangeFormatterImpl.
+ // The call site only cares about != 0 and != 1.
+ // Return a very large value so that if this method is used elsewhere, we should notice.
+ return 999;
}
bool ScientificModifier::isStrong() const {
@@ -94,6 +93,27 @@ bool ScientificModifier::isStrong() const {
return true;
}
+bool ScientificModifier::containsField(UNumberFormatFields field) const {
+ (void)field;
+ // This method is not used for inner modifiers.
+ U_ASSERT(false);
+ return false;
+}
+
+void ScientificModifier::getParameters(Parameters& output) const {
+ // Not part of any plural sets
+ output.obj = nullptr;
+}
+
+bool ScientificModifier::semanticallyEquivalent(const Modifier& other) const {
+ auto* _other = dynamic_cast<const ScientificModifier*>(&other);
+ if (_other == nullptr) {
+ return false;
+ }
+ // TODO: Check for locale symbols and settings as well? Could be less efficient.
+ return fExponent == _other->fExponent;
+}
+
// Note: Visual Studio does not compile this function without full name space. Why?
icu::number::impl::ScientificHandler::ScientificHandler(const Notation *notation, const DecimalFormatSymbols *symbols,
const MicroPropsGenerator *parent) :
diff --git a/deps/icu-small/source/i18n/number_scientific.h b/deps/icu-small/source/i18n/number_scientific.h
index 974ab3adb6..e377bd941e 100644
--- a/deps/icu-small/source/i18n/number_scientific.h
+++ b/deps/icu-small/source/i18n/number_scientific.h
@@ -24,12 +24,18 @@ class U_I18N_API ScientificModifier : public UMemory, public Modifier {
int32_t apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
UErrorCode &status) const U_OVERRIDE;
- int32_t getPrefixLength(UErrorCode &status) const U_OVERRIDE;
+ int32_t getPrefixLength() const U_OVERRIDE;
- int32_t getCodePointCount(UErrorCode &status) const U_OVERRIDE;
+ int32_t getCodePointCount() const U_OVERRIDE;
bool isStrong() const U_OVERRIDE;
+ bool containsField(UNumberFormatFields field) const U_OVERRIDE;
+
+ void getParameters(Parameters& output) const U_OVERRIDE;
+
+ bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
+
private:
int32_t fExponent;
const ScientificHandler *fHandler;
diff --git a/deps/icu-small/source/i18n/number_stringbuilder.cpp b/deps/icu-small/source/i18n/number_stringbuilder.cpp
index 37770d11d5..74ba33fbbc 100644
--- a/deps/icu-small/source/i18n/number_stringbuilder.cpp
+++ b/deps/icu-small/source/i18n/number_stringbuilder.cpp
@@ -241,6 +241,9 @@ NumberStringBuilder::insert(int32_t index, const NumberStringBuilder &other, UEr
}
int32_t NumberStringBuilder::prepareForInsert(int32_t index, int32_t count, UErrorCode &status) {
+ U_ASSERT(index >= 0);
+ U_ASSERT(index <= fLength);
+ U_ASSERT(count >= 0);
if (index == 0 && fZero - count >= 0) {
// Append to start
fZero -= count;
@@ -485,4 +488,13 @@ void NumberStringBuilder::getAllFieldPositions(FieldPositionIteratorHandler& fpi
}
}
+bool NumberStringBuilder::containsField(Field field) const {
+ for (int32_t i = 0; i < fLength; i++) {
+ if (field == fieldAt(i)) {
+ return true;
+ }
+ }
+ return false;
+}
+
#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/deps/icu-small/source/i18n/number_stringbuilder.h b/deps/icu-small/source/i18n/number_stringbuilder.h
index cd8ce2f805..b14ad9ede2 100644
--- a/deps/icu-small/source/i18n/number_stringbuilder.h
+++ b/deps/icu-small/source/i18n/number_stringbuilder.h
@@ -106,6 +106,8 @@ class U_I18N_API NumberStringBuilder : public UMemory {
void getAllFieldPositions(FieldPositionIteratorHandler& fpih, UErrorCode& status) const;
+ bool containsField(Field field) const;
+
private:
bool fUsingHeap = false;
ValueOrHeapArray<char16_t> fChars;
diff --git a/deps/icu-small/source/i18n/number_types.h b/deps/icu-small/source/i18n/number_types.h
index 57da72f8aa..00a6818869 100644
--- a/deps/icu-small/source/i18n/number_types.h
+++ b/deps/icu-small/source/i18n/number_types.h
@@ -16,6 +16,7 @@
#include "uassert.h"
#include "unicode/platform.h"
#include "unicode/uniset.h"
+#include "standardplural.h"
U_NAMESPACE_BEGIN namespace number {
namespace impl {
@@ -45,6 +46,7 @@ class Modifier;
class MutablePatternModifier;
class DecimalQuantity;
class NumberStringBuilder;
+class ModifierStore;
struct MicroProps;
@@ -127,12 +129,13 @@ class U_I18N_API AffixPatternProvider {
virtual bool hasBody() const = 0;
};
+
/**
* A Modifier is an object that can be passed through the formatting pipeline until it is finally applied to the string
* builder. A Modifier usually contains a prefix and a suffix that are applied, but it could contain something else,
* like a {@link com.ibm.icu.text.SimpleFormatter} pattern.
*
- * A Modifier is usually immutable, except in cases such as {@link MurkyModifier}, which are mutable for performance
+ * A Modifier is usually immutable, except in cases such as {@link MutablePatternModifier}, which are mutable for performance
* reasons.
*
* Exported as U_I18N_API because it is a base class for other exported types
@@ -162,12 +165,12 @@ class U_I18N_API Modifier {
*
* @return The number of characters (UTF-16 code units) in the prefix.
*/
- virtual int32_t getPrefixLength(UErrorCode& status) const = 0;
+ virtual int32_t getPrefixLength() const = 0;
/**
* Returns the number of code points in the modifier, prefix plus suffix.
*/
- virtual int32_t getCodePointCount(UErrorCode& status) const = 0;
+ virtual int32_t getCodePointCount() const = 0;
/**
* Whether this modifier is strong. If a modifier is strong, it should always be applied immediately and not allowed
@@ -177,8 +180,57 @@ class U_I18N_API Modifier {
* @return Whether the modifier is strong.
*/
virtual bool isStrong() const = 0;
+
+ /**
+ * Whether the modifier contains at least one occurrence of the given field.
+ */
+ virtual bool containsField(UNumberFormatFields field) const = 0;
+
+ /**
+ * A fill-in for getParameters(). obj will always be set; if non-null, the other
+ * two fields are also safe to read.
+ */
+ struct U_I18N_API Parameters {
+ const ModifierStore* obj = nullptr;
+ int8_t signum;
+ StandardPlural::Form plural;
+
+ Parameters();
+ Parameters(const ModifierStore* _obj, int8_t _signum, StandardPlural::Form _plural);
+ };
+
+ /**
+ * Gets a set of "parameters" for this Modifier.
+ *
+ * TODO: Make this return a `const Parameters*` more like Java?
+ */
+ virtual void getParameters(Parameters& output) const = 0;
+
+ /**
+ * Returns whether this Modifier is *semantically equivalent* to the other Modifier;
+ * in many cases, this is the same as equal, but parameters should be ignored.
+ */
+ virtual bool semanticallyEquivalent(const Modifier& other) const = 0;
};
+
+/**
+ * This is *not* a modifier; rather, it is an object that can return modifiers
+ * based on given parameters.
+ *
+ * Exported as U_I18N_API because it is a base class for other exported types.
+ */
+class U_I18N_API ModifierStore {
+ public:
+ virtual ~ModifierStore();
+
+ /**
+ * Returns a Modifier with the given parameters (best-effort).
+ */
+ virtual const Modifier* getModifier(int8_t signum, StandardPlural::Form plural) const = 0;
+};
+
+
/**
* This interface is used when all number formatting settings, including the locale, are known, except for the quantity
* itself. The {@link #processQuantity} method performs the final step in the number processing pipeline: it uses the
diff --git a/deps/icu-small/source/i18n/numfmt.cpp b/deps/icu-small/source/i18n/numfmt.cpp
index 13f23131b1..ef47e1e01b 100644
--- a/deps/icu-small/source/i18n/numfmt.cpp
+++ b/deps/icu-small/source/i18n/numfmt.cpp
@@ -1326,13 +1326,13 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
// if the locale has "@compat=host", create a host-specific NumberFormat
if (U_SUCCESS(status) && count > 0 && uprv_strcmp(buffer, "host") == 0) {
- Win32NumberFormat *f = NULL;
UBool curr = TRUE;
switch (style) {
case UNUM_DECIMAL:
curr = FALSE;
// fall-through
+ U_FALLTHROUGH;
case UNUM_CURRENCY:
case UNUM_CURRENCY_ISO: // do not support plural formatting here
@@ -1340,14 +1340,13 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
case UNUM_CURRENCY_ACCOUNTING:
case UNUM_CASH_CURRENCY:
case UNUM_CURRENCY_STANDARD:
- f = new Win32NumberFormat(desiredLocale, curr, status);
-
+ {
+ LocalPointer<Win32NumberFormat> f(new Win32NumberFormat(desiredLocale, curr, status), status);
if (U_SUCCESS(status)) {
- return f;
+ return f.orphan();
}
-
- delete f;
- break;
+ }
+ break;
default:
break;
}
@@ -1417,8 +1416,7 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
}
}
-
- NumberFormat *f;
+ LocalPointer<NumberFormat> f;
if (ns->isAlgorithmic()) {
UnicodeString nsDesc;
UnicodeString nsRuleSetGroup;
@@ -1453,7 +1451,7 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
return NULL;
}
r->setDefaultRuleSet(nsRuleSetName,status);
- f = r;
+ f.adoptInstead(r);
} else {
// replace single currency sign in the pattern with double currency sign
// if the style is UNUM_CURRENCY_ISO
@@ -1462,9 +1460,22 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
UnicodeString(TRUE, gDoubleCurrencySign, 2));
}
- // "new DecimalFormat()" does not adopt the symbols if its memory allocation fails.
- DecimalFormatSymbols *syms = symbolsToAdopt.orphan();
- DecimalFormat* df = new DecimalFormat(pattern, syms, style, status);
+ // "new DecimalFormat()" does not adopt the symbols argument if its memory allocation fails.
+ // So we can't use adoptInsteadAndCheckErrorCode as we need to know if the 'new' failed.
+ DecimalFormatSymbols *syms = symbolsToAdopt.getAlias();
+ LocalPointer<DecimalFormat> df(new DecimalFormat(pattern, syms, style, status));
+
+ if (df.isValid()) {
+ // if the DecimalFormat object was successfully new'ed, then it will own symbolsToAdopt, even if the status is a failure.
+ symbolsToAdopt.orphan();
+ }
+ else {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
// if it is cash currency style, setCurrencyUsage with usage
if (style == UNUM_CASH_CURRENCY){
@@ -1472,25 +1483,18 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
}
if (U_FAILURE(status)) {
- delete df;
- return NULL;
+ return nullptr;
}
- f = df;
- if (f == NULL) {
- delete syms;
- status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
- }
+ f.adoptInstead(df.orphan());
}
f->setLocaleIDs(ures_getLocaleByType(ownedResource.getAlias(), ULOC_VALID_LOCALE, &status),
ures_getLocaleByType(ownedResource.getAlias(), ULOC_ACTUAL_LOCALE, &status));
if (U_FAILURE(status)) {
- delete f;
return NULL;
}
- return f;
+ return f.orphan();
}
/**
diff --git a/deps/icu-small/source/i18n/numparse_currency.cpp b/deps/icu-small/source/i18n/numparse_currency.cpp
index ae8196ec48..598ace5653 100644
--- a/deps/icu-small/source/i18n/numparse_currency.cpp
+++ b/deps/icu-small/source/i18n/numparse_currency.cpp
@@ -111,7 +111,9 @@ bool CombinedCurrencyMatcher::matchCurrency(StringSegment& segment, ParsedNumber
int32_t overlap2;
if (!fCurrency2.isEmpty()) {
- overlap2 = segment.getCaseSensitivePrefixLength(fCurrency2);
+ // ISO codes should be accepted case-insensitive.
+ // https://unicode-org.atlassian.net/browse/ICU-13696
+ overlap2 = segment.getCommonPrefixLength(fCurrency2);
} else {
overlap2 = -1;
}
diff --git a/deps/icu-small/source/i18n/numparse_impl.cpp b/deps/icu-small/source/i18n/numparse_impl.cpp
index 5fa52f6335..3192a39593 100644
--- a/deps/icu-small/source/i18n/numparse_impl.cpp
+++ b/deps/icu-small/source/i18n/numparse_impl.cpp
@@ -159,10 +159,10 @@ NumberParserImpl::createParserFromProperties(const number::impl::DecimalFormatPr
// ICU-TC meeting, April 11, 2018: accept percent/permille only if it is in the pattern,
// and to maintain regressive behavior, divide by 100 even if no percent sign is present.
- if (affixProvider->containsSymbolType(AffixPatternType::TYPE_PERCENT, status)) {
+ if (!isStrict && affixProvider->containsSymbolType(AffixPatternType::TYPE_PERCENT, status)) {
parser->addMatcher(parser->fLocalMatchers.percent = {symbols});
}
- if (affixProvider->containsSymbolType(AffixPatternType::TYPE_PERMILLE, status)) {
+ if (!isStrict && affixProvider->containsSymbolType(AffixPatternType::TYPE_PERMILLE, status)) {
parser->addMatcher(parser->fLocalMatchers.permille = {symbols});
}
diff --git a/deps/icu-small/source/i18n/numparse_scientific.cpp b/deps/icu-small/source/i18n/numparse_scientific.cpp
index 611695e57d..de38957440 100644
--- a/deps/icu-small/source/i18n/numparse_scientific.cpp
+++ b/deps/icu-small/source/i18n/numparse_scientific.cpp
@@ -56,6 +56,11 @@ bool ScientificMatcher::match(StringSegment& segment, ParsedNumber& result, UErr
return false;
}
+ // Only accept one exponent per string.
+ if (0 != (result.flags & FLAG_HAS_EXPONENT)) {
+ return false;
+ }
+
// First match the scientific separator, and then match another number after it.
// NOTE: This is guarded by the smoke test; no need to check fExponentSeparatorString length again.
int overlap1 = segment.getCommonPrefixLength(fExponentSeparatorString);
diff --git a/deps/icu-small/source/i18n/numrange_fluent.cpp b/deps/icu-small/source/i18n/numrange_fluent.cpp
new file mode 100644
index 0000000000..12b006c8ad
--- /dev/null
+++ b/deps/icu-small/source/i18n/numrange_fluent.cpp
@@ -0,0 +1,472 @@
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+// Allow implicit conversion from char16_t* to UnicodeString for this file:
+// Helpful in toString methods and elsewhere.
+#define UNISTR_FROM_STRING_EXPLICIT
+
+#include "numrange_impl.h"
+#include "util.h"
+#include "number_utypes.h"
+
+using namespace icu;
+using namespace icu::number;
+using namespace icu::number::impl;
+
+
+// This function needs to be declared in this namespace so it can be friended.
+// NOTE: In Java, this logic is handled in the resolve() function.
+void icu::number::impl::touchRangeLocales(RangeMacroProps& macros) {
+ macros.formatter1.fMacros.locale = macros.locale;
+ macros.formatter2.fMacros.locale = macros.locale;
+}
+
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(const UnlocalizedNumberFormatter& formatter) const& {
+ Derived copy(*this);
+ copy.fMacros.formatter1 = formatter;
+ copy.fMacros.singleFormatter = true;
+ touchRangeLocales(copy.fMacros);
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(const UnlocalizedNumberFormatter& formatter) && {
+ Derived move(std::move(*this));
+ move.fMacros.formatter1 = formatter;
+ move.fMacros.singleFormatter = true;
+ touchRangeLocales(move.fMacros);
+ return move;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(UnlocalizedNumberFormatter&& formatter) const& {
+ Derived copy(*this);
+ copy.fMacros.formatter1 = std::move(formatter);
+ copy.fMacros.singleFormatter = true;
+ touchRangeLocales(copy.fMacros);
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(UnlocalizedNumberFormatter&& formatter) && {
+ Derived move(std::move(*this));
+ move.fMacros.formatter1 = std::move(formatter);
+ move.fMacros.singleFormatter = true;
+ touchRangeLocales(move.fMacros);
+ return move;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(const UnlocalizedNumberFormatter& formatter) const& {
+ Derived copy(*this);
+ copy.fMacros.formatter1 = formatter;
+ copy.fMacros.singleFormatter = false;
+ touchRangeLocales(copy.fMacros);
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(const UnlocalizedNumberFormatter& formatter) && {
+ Derived move(std::move(*this));
+ move.fMacros.formatter1 = formatter;
+ move.fMacros.singleFormatter = false;
+ touchRangeLocales(move.fMacros);
+ return move;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(UnlocalizedNumberFormatter&& formatter) const& {
+ Derived copy(*this);
+ copy.fMacros.formatter1 = std::move(formatter);
+ copy.fMacros.singleFormatter = false;
+ touchRangeLocales(copy.fMacros);
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(UnlocalizedNumberFormatter&& formatter) && {
+ Derived move(std::move(*this));
+ move.fMacros.formatter1 = std::move(formatter);
+ move.fMacros.singleFormatter = false;
+ touchRangeLocales(move.fMacros);
+ return move;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(const UnlocalizedNumberFormatter& formatter) const& {
+ Derived copy(*this);
+ copy.fMacros.formatter2 = formatter;
+ copy.fMacros.singleFormatter = false;
+ touchRangeLocales(copy.fMacros);
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(const UnlocalizedNumberFormatter& formatter) && {
+ Derived move(std::move(*this));
+ move.fMacros.formatter2 = formatter;
+ move.fMacros.singleFormatter = false;
+ touchRangeLocales(move.fMacros);
+ return move;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(UnlocalizedNumberFormatter&& formatter) const& {
+ Derived copy(*this);
+ copy.fMacros.formatter2 = std::move(formatter);
+ copy.fMacros.singleFormatter = false;
+ touchRangeLocales(copy.fMacros);
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(UnlocalizedNumberFormatter&& formatter) && {
+ Derived move(std::move(*this));
+ move.fMacros.formatter2 = std::move(formatter);
+ move.fMacros.singleFormatter = false;
+ touchRangeLocales(move.fMacros);
+ return move;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::collapse(UNumberRangeCollapse collapse) const& {
+ Derived copy(*this);
+ copy.fMacros.collapse = collapse;
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::collapse(UNumberRangeCollapse collapse) && {
+ Derived move(std::move(*this));
+ move.fMacros.collapse = collapse;
+ return move;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::identityFallback(UNumberRangeIdentityFallback identityFallback) const& {
+ Derived copy(*this);
+ copy.fMacros.identityFallback = identityFallback;
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::identityFallback(UNumberRangeIdentityFallback identityFallback) && {
+ Derived move(std::move(*this));
+ move.fMacros.identityFallback = identityFallback;
+ return move;
+}
+
+// Declare all classes that implement NumberRangeFormatterSettings
+// See https://stackoverflow.com/a/495056/1407170
+template
+class icu::number::NumberRangeFormatterSettings<icu::number::UnlocalizedNumberRangeFormatter>;
+template
+class icu::number::NumberRangeFormatterSettings<icu::number::LocalizedNumberRangeFormatter>;
+
+
+UnlocalizedNumberRangeFormatter NumberRangeFormatter::with() {
+ UnlocalizedNumberRangeFormatter result;
+ return result;
+}
+
+LocalizedNumberRangeFormatter NumberRangeFormatter::withLocale(const Locale& locale) {
+ return with().locale(locale);
+}
+
+
+template<typename T> using NFS = NumberRangeFormatterSettings<T>;
+using LNF = LocalizedNumberRangeFormatter;
+using UNF = UnlocalizedNumberRangeFormatter;
+
+UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(const UNF& other)
+ : UNF(static_cast<const NFS<UNF>&>(other)) {}
+
+UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(const NFS<UNF>& other)
+ : NFS<UNF>(other) {
+ // No additional fields to assign
+}
+
+// Make default copy constructor call the NumberRangeFormatterSettings copy constructor.
+UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(UNF&& src) U_NOEXCEPT
+ : UNF(static_cast<NFS<UNF>&&>(src)) {}
+
+UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(NFS<UNF>&& src) U_NOEXCEPT
+ : NFS<UNF>(std::move(src)) {
+ // No additional fields to assign
+}
+
+UnlocalizedNumberRangeFormatter& UnlocalizedNumberRangeFormatter::operator=(const UNF& other) {
+ NFS<UNF>::operator=(static_cast<const NFS<UNF>&>(other));
+ // No additional fields to assign
+ return *this;
+}
+
+UnlocalizedNumberRangeFormatter& UnlocalizedNumberRangeFormatter::operator=(UNF&& src) U_NOEXCEPT {
+ NFS<UNF>::operator=(static_cast<NFS<UNF>&&>(src));
+ // No additional fields to assign
+ return *this;
+}
+
+// Make default copy constructor call the NumberRangeFormatterSettings copy constructor.
+LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const LNF& other)
+ : LNF(static_cast<const NFS<LNF>&>(other)) {}
+
+LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const NFS<LNF>& other)
+ : NFS<LNF>(other) {
+ // No additional fields to assign
+}
+
+LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(LocalizedNumberRangeFormatter&& src) U_NOEXCEPT
+ : LNF(static_cast<NFS<LNF>&&>(src)) {}
+
+LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(NFS<LNF>&& src) U_NOEXCEPT
+ : NFS<LNF>(std::move(src)) {
+ // Steal the compiled formatter
+ LNF&& _src = static_cast<LNF&&>(src);
+ auto* stolen = _src.fAtomicFormatter.exchange(nullptr);
+ delete fAtomicFormatter.exchange(stolen);
+}
+
+LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(const LNF& other) {
+ NFS<LNF>::operator=(static_cast<const NFS<LNF>&>(other));
+ // Do not steal; just clear
+ delete fAtomicFormatter.exchange(nullptr);
+ return *this;
+}
+
+LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(LNF&& src) U_NOEXCEPT {
+ NFS<LNF>::operator=(static_cast<NFS<LNF>&&>(src));
+ // Steal the compiled formatter
+ auto* stolen = src.fAtomicFormatter.exchange(nullptr);
+ delete fAtomicFormatter.exchange(stolen);
+ return *this;
+}
+
+
+LocalizedNumberRangeFormatter::~LocalizedNumberRangeFormatter() {
+ delete fAtomicFormatter.exchange(nullptr);
+}
+
+LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const RangeMacroProps& macros, const Locale& locale) {
+ fMacros = macros;
+ fMacros.locale = locale;
+ touchRangeLocales(fMacros);
+}
+
+LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(RangeMacroProps&& macros, const Locale& locale) {
+ fMacros = std::move(macros);
+ fMacros.locale = locale;
+ touchRangeLocales(fMacros);
+}
+
+LocalizedNumberRangeFormatter UnlocalizedNumberRangeFormatter::locale(const Locale& locale) const& {
+ return LocalizedNumberRangeFormatter(fMacros, locale);
+}
+
+LocalizedNumberRangeFormatter UnlocalizedNumberRangeFormatter::locale(const Locale& locale)&& {
+ return LocalizedNumberRangeFormatter(std::move(fMacros), locale);
+}
+
+
+FormattedNumberRange LocalizedNumberRangeFormatter::formatFormattableRange(
+ const Formattable& first, const Formattable& second, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return FormattedNumberRange(U_ILLEGAL_ARGUMENT_ERROR);
+ }
+
+ auto results = new UFormattedNumberRangeData();
+ if (results == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return FormattedNumberRange(status);
+ }
+
+ first.populateDecimalQuantity(results->quantity1, status);
+ if (U_FAILURE(status)) {
+ return FormattedNumberRange(status);
+ }
+
+ second.populateDecimalQuantity(results->quantity2, status);
+ if (U_FAILURE(status)) {
+ return FormattedNumberRange(status);
+ }
+
+ formatImpl(*results, first == second, status);
+
+ // Do not save the results object if we encountered a failure.
+ if (U_SUCCESS(status)) {
+ return FormattedNumberRange(results);
+ } else {
+ delete results;
+ return FormattedNumberRange(status);
+ }
+}
+
+void LocalizedNumberRangeFormatter::formatImpl(
+ UFormattedNumberRangeData& results, bool equalBeforeRounding, UErrorCode& status) const {
+ auto* impl = getFormatter(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (impl == nullptr) {
+ status = U_INTERNAL_PROGRAM_ERROR;
+ return;
+ }
+ impl->format(results, equalBeforeRounding, status);
+}
+
+const impl::NumberRangeFormatterImpl*
+LocalizedNumberRangeFormatter::getFormatter(UErrorCode& status) const {
+ // TODO: Move this into umutex.h? (similar logic also in decimfmt.cpp)
+ // See ICU-20146
+
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+
+ // First try to get the pre-computed formatter
+ auto* ptr = fAtomicFormatter.load();
+ if (ptr != nullptr) {
+ return ptr;
+ }
+
+ // Try computing the formatter on our own
+ auto* temp = new NumberRangeFormatterImpl(fMacros, status);
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+ if (temp == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+
+ // Note: ptr starts as nullptr; during compare_exchange,
+ // it is set to what is actually stored in the atomic
+ // if another thread beat us to computing the formatter object.
+ auto* nonConstThis = const_cast<LocalizedNumberRangeFormatter*>(this);
+ if (!nonConstThis->fAtomicFormatter.compare_exchange_strong(ptr, temp)) {
+ // Another thread beat us to computing the formatter
+ delete temp;
+ return ptr;
+ } else {
+ // Our copy of the formatter got stored in the atomic
+ return temp;
+ }
+
+}
+
+
+FormattedNumberRange::FormattedNumberRange(FormattedNumberRange&& src) U_NOEXCEPT
+ : fResults(src.fResults), fErrorCode(src.fErrorCode) {
+ // Disown src.fResults to prevent double-deletion
+ src.fResults = nullptr;
+ src.fErrorCode = U_INVALID_STATE_ERROR;
+}
+
+FormattedNumberRange& FormattedNumberRange::operator=(FormattedNumberRange&& src) U_NOEXCEPT {
+ delete fResults;
+ fResults = src.fResults;
+ fErrorCode = src.fErrorCode;
+ // Disown src.fResults to prevent double-deletion
+ src.fResults = nullptr;
+ src.fErrorCode = U_INVALID_STATE_ERROR;
+ return *this;
+}
+
+UnicodeString FormattedNumberRange::toString(UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return ICU_Utility::makeBogusString();
+ }
+ if (fResults == nullptr) {
+ status = fErrorCode;
+ return ICU_Utility::makeBogusString();
+ }
+ return fResults->string.toUnicodeString();
+}
+
+Appendable& FormattedNumberRange::appendTo(Appendable& appendable, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return appendable;
+ }
+ if (fResults == nullptr) {
+ status = fErrorCode;
+ return appendable;
+ }
+ appendable.appendString(fResults->string.chars(), fResults->string.length());
+ return appendable;
+}
+
+UBool FormattedNumberRange::nextFieldPosition(FieldPosition& fieldPosition, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ if (fResults == nullptr) {
+ status = fErrorCode;
+ return FALSE;
+ }
+ // NOTE: MSVC sometimes complains when implicitly converting between bool and UBool
+ return fResults->string.nextFieldPosition(fieldPosition, status) ? TRUE : FALSE;
+}
+
+void FormattedNumberRange::getAllFieldPositions(FieldPositionIterator& iterator, UErrorCode& status) const {
+ FieldPositionIteratorHandler fpih(&iterator, status);
+ getAllFieldPositionsImpl(fpih, status);
+}
+
+void FormattedNumberRange::getAllFieldPositionsImpl(
+ FieldPositionIteratorHandler& fpih, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (fResults == nullptr) {
+ status = fErrorCode;
+ return;
+ }
+ fResults->string.getAllFieldPositions(fpih, status);
+}
+
+UnicodeString FormattedNumberRange::getFirstDecimal(UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return ICU_Utility::makeBogusString();
+ }
+ if (fResults == nullptr) {
+ status = fErrorCode;
+ return ICU_Utility::makeBogusString();
+ }
+ return fResults->quantity1.toScientificString();
+}
+
+UnicodeString FormattedNumberRange::getSecondDecimal(UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return ICU_Utility::makeBogusString();
+ }
+ if (fResults == nullptr) {
+ status = fErrorCode;
+ return ICU_Utility::makeBogusString();
+ }
+ return fResults->quantity2.toScientificString();
+}
+
+UNumberRangeIdentityResult FormattedNumberRange::getIdentityResult(UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return UNUM_IDENTITY_RESULT_NOT_EQUAL;
+ }
+ if (fResults == nullptr) {
+ status = fErrorCode;
+ return UNUM_IDENTITY_RESULT_NOT_EQUAL;
+ }
+ return fResults->identityResult;
+}
+
+FormattedNumberRange::~FormattedNumberRange() {
+ delete fResults;
+}
+
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/deps/icu-small/source/i18n/numrange_impl.cpp b/deps/icu-small/source/i18n/numrange_impl.cpp
new file mode 100644
index 0000000000..21365bfc59
--- /dev/null
+++ b/deps/icu-small/source/i18n/numrange_impl.cpp
@@ -0,0 +1,486 @@
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+// Allow implicit conversion from char16_t* to UnicodeString for this file:
+// Helpful in toString methods and elsewhere.
+#define UNISTR_FROM_STRING_EXPLICIT
+
+#include "unicode/numberrangeformatter.h"
+#include "numrange_impl.h"
+#include "patternprops.h"
+#include "uresimp.h"
+#include "util.h"
+
+using namespace icu;
+using namespace icu::number;
+using namespace icu::number::impl;
+
+namespace {
+
+// Helper function for 2-dimensional switch statement
+constexpr int8_t identity2d(UNumberRangeIdentityFallback a, UNumberRangeIdentityResult b) {
+ return static_cast<int8_t>(a) | (static_cast<int8_t>(b) << 4);
+}
+
+
+struct NumberRangeData {
+ SimpleFormatter rangePattern;
+ SimpleFormatter approximatelyPattern;
+};
+
+class NumberRangeDataSink : public ResourceSink {
+ public:
+ NumberRangeDataSink(NumberRangeData& data) : fData(data) {}
+
+ void put(const char* key, ResourceValue& value, UBool /*noFallback*/, UErrorCode& status) U_OVERRIDE {
+ ResourceTable miscTable = value.getTable(status);
+ if (U_FAILURE(status)) { return; }
+ for (int i = 0; miscTable.getKeyAndValue(i, key, value); i++) {
+ if (uprv_strcmp(key, "range") == 0) {
+ if (fData.rangePattern.getArgumentLimit() != 0) {
+ continue; // have already seen this pattern
+ }
+ fData.rangePattern = {value.getUnicodeString(status), status};
+ } else if (uprv_strcmp(key, "approximately") == 0) {
+ if (fData.approximatelyPattern.getArgumentLimit() != 0) {
+ continue; // have already seen this pattern
+ }
+ fData.approximatelyPattern = {value.getUnicodeString(status), status};
+ }
+ }
+ }
+
+ private:
+ NumberRangeData& fData;
+};
+
+void getNumberRangeData(const char* localeName, const char* nsName, NumberRangeData& data, UErrorCode& status) {
+ if (U_FAILURE(status)) { return; }
+ LocalUResourceBundlePointer rb(ures_open(NULL, localeName, &status));
+ if (U_FAILURE(status)) { return; }
+ NumberRangeDataSink sink(data);
+
+ CharString dataPath;
+ dataPath.append("NumberElements/", -1, status);
+ dataPath.append(nsName, -1, status);
+ dataPath.append("/miscPatterns", -1, status);
+ ures_getAllItemsWithFallback(rb.getAlias(), dataPath.data(), sink, status);
+ if (U_FAILURE(status)) { return; }
+
+ // TODO: Is it necessary to manually fall back to latn, or does the data sink take care of that?
+
+ if (data.rangePattern.getArgumentLimit() == 0) {
+ // No data!
+ data.rangePattern = {u"{0}–{1}", status};
+ }
+ if (data.approximatelyPattern.getArgumentLimit() == 0) {
+ // No data!
+ data.approximatelyPattern = {u"~{0}", status};
+ }
+}
+
+class PluralRangesDataSink : public ResourceSink {
+ public:
+ PluralRangesDataSink(StandardPluralRanges& output) : fOutput(output) {}
+
+ void put(const char* /*key*/, ResourceValue& value, UBool /*noFallback*/, UErrorCode& status) U_OVERRIDE {
+ ResourceArray entriesArray = value.getArray(status);
+ if (U_FAILURE(status)) { return; }
+ fOutput.setCapacity(entriesArray.getSize());
+ for (int i = 0; entriesArray.getValue(i, value); i++) {
+ ResourceArray pluralFormsArray = value.getArray(status);
+ if (U_FAILURE(status)) { return; }
+ pluralFormsArray.getValue(0, value);
+ StandardPlural::Form first = StandardPlural::fromString(value.getUnicodeString(status), status);
+ if (U_FAILURE(status)) { return; }
+ pluralFormsArray.getValue(1, value);
+ StandardPlural::Form second = StandardPlural::fromString(value.getUnicodeString(status), status);
+ if (U_FAILURE(status)) { return; }
+ pluralFormsArray.getValue(2, value);
+ StandardPlural::Form result = StandardPlural::fromString(value.getUnicodeString(status), status);
+ if (U_FAILURE(status)) { return; }
+ fOutput.addPluralRange(first, second, result);
+ }
+ }
+
+ private:
+ StandardPluralRanges& fOutput;
+};
+
+void getPluralRangesData(const Locale& locale, StandardPluralRanges& output, UErrorCode& status) {
+ if (U_FAILURE(status)) { return; }
+ LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "pluralRanges", &status));
+ if (U_FAILURE(status)) { return; }
+
+ CharString dataPath;
+ dataPath.append("locales/", -1, status);
+ dataPath.append(locale.getLanguage(), -1, status);
+ if (U_FAILURE(status)) { return; }
+ int32_t setLen;
+ // Not all languages are covered: fail gracefully
+ UErrorCode internalStatus = U_ZERO_ERROR;
+ const UChar* set = ures_getStringByKeyWithFallback(rb.getAlias(), dataPath.data(), &setLen, &internalStatus);
+ if (U_FAILURE(internalStatus)) { return; }
+
+ dataPath.clear();
+ dataPath.append("rules/", -1, status);
+ dataPath.appendInvariantChars(set, setLen, status);
+ if (U_FAILURE(status)) { return; }
+ PluralRangesDataSink sink(output);
+ ures_getAllItemsWithFallback(rb.getAlias(), dataPath.data(), sink, status);
+ if (U_FAILURE(status)) { return; }
+}
+
+} // namespace
+
+
+void StandardPluralRanges::initialize(const Locale& locale, UErrorCode& status) {
+ getPluralRangesData(locale, *this, status);
+}
+
+void StandardPluralRanges::addPluralRange(
+ StandardPlural::Form first,
+ StandardPlural::Form second,
+ StandardPlural::Form result) {
+ U_ASSERT(fTriplesLen < fTriples.getCapacity());
+ fTriples[fTriplesLen] = {first, second, result};
+ fTriplesLen++;
+}
+
+void StandardPluralRanges::setCapacity(int32_t length) {
+ if (length > fTriples.getCapacity()) {
+ fTriples.resize(length, 0);
+ }
+}
+
+StandardPlural::Form
+StandardPluralRanges::resolve(StandardPlural::Form first, StandardPlural::Form second) const {
+ for (int32_t i=0; i<fTriplesLen; i++) {
+ const auto& triple = fTriples[i];
+ if (triple.first == first && triple.second == second) {
+ return triple.result;
+ }
+ }
+ // Default fallback
+ return StandardPlural::OTHER;
+}
+
+
+NumberRangeFormatterImpl::NumberRangeFormatterImpl(const RangeMacroProps& macros, UErrorCode& status)
+ : formatterImpl1(macros.formatter1.fMacros, status),
+ formatterImpl2(macros.formatter2.fMacros, status),
+ fSameFormatters(macros.singleFormatter),
+ fCollapse(macros.collapse),
+ fIdentityFallback(macros.identityFallback) {
+
+ // TODO: As of this writing (ICU 63), there is no locale that has different number miscPatterns
+ // based on numbering system. Therefore, data is loaded only from latn. If this changes,
+ // this part of the code should be updated to load from the local numbering system.
+ // The numbering system could come from the one specified in the NumberFormatter passed to
+ // numberFormatterBoth() or similar.
+ // See ICU-20144
+
+ NumberRangeData data;
+ getNumberRangeData(macros.locale.getName(), "latn", data, status);
+ if (U_FAILURE(status)) { return; }
+ fRangeFormatter = data.rangePattern;
+ fApproximatelyModifier = {data.approximatelyPattern, UNUM_FIELD_COUNT, false};
+
+ // TODO: Get locale from PluralRules instead?
+ fPluralRanges.initialize(macros.locale, status);
+ if (U_FAILURE(status)) { return; }
+}
+
+void NumberRangeFormatterImpl::format(UFormattedNumberRangeData& data, bool equalBeforeRounding, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ MicroProps micros1;
+ MicroProps micros2;
+ formatterImpl1.preProcess(data.quantity1, micros1, status);
+ if (fSameFormatters) {
+ formatterImpl1.preProcess(data.quantity2, micros2, status);
+ } else {
+ formatterImpl2.preProcess(data.quantity2, micros2, status);
+ }
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ // If any of the affixes are different, an identity is not possible
+ // and we must use formatRange().
+ // TODO: Write this as MicroProps operator==() ?
+ // TODO: Avoid the redundancy of these equality operations with the
+ // ones in formatRange?
+ if (!micros1.modInner->semanticallyEquivalent(*micros2.modInner)
+ || !micros1.modMiddle->semanticallyEquivalent(*micros2.modMiddle)
+ || !micros1.modOuter->semanticallyEquivalent(*micros2.modOuter)) {
+ formatRange(data, micros1, micros2, status);
+ data.identityResult = UNUM_IDENTITY_RESULT_NOT_EQUAL;
+ return;
+ }
+
+ // Check for identity
+ if (equalBeforeRounding) {
+ data.identityResult = UNUM_IDENTITY_RESULT_EQUAL_BEFORE_ROUNDING;
+ } else if (data.quantity1 == data.quantity2) {
+ data.identityResult = UNUM_IDENTITY_RESULT_EQUAL_AFTER_ROUNDING;
+ } else {
+ data.identityResult = UNUM_IDENTITY_RESULT_NOT_EQUAL;
+ }
+
+ switch (identity2d(fIdentityFallback, data.identityResult)) {
+ case identity2d(UNUM_IDENTITY_FALLBACK_RANGE,
+ UNUM_IDENTITY_RESULT_NOT_EQUAL):
+ case identity2d(UNUM_IDENTITY_FALLBACK_RANGE,
+ UNUM_IDENTITY_RESULT_EQUAL_AFTER_ROUNDING):
+ case identity2d(UNUM_IDENTITY_FALLBACK_RANGE,
+ UNUM_IDENTITY_RESULT_EQUAL_BEFORE_ROUNDING):
+ case identity2d(UNUM_IDENTITY_FALLBACK_APPROXIMATELY,
+ UNUM_IDENTITY_RESULT_NOT_EQUAL):
+ case identity2d(UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE,
+ UNUM_IDENTITY_RESULT_NOT_EQUAL):
+ case identity2d(UNUM_IDENTITY_FALLBACK_SINGLE_VALUE,
+ UNUM_IDENTITY_RESULT_NOT_EQUAL):
+ formatRange(data, micros1, micros2, status);
+ break;
+
+ case identity2d(UNUM_IDENTITY_FALLBACK_APPROXIMATELY,
+ UNUM_IDENTITY_RESULT_EQUAL_AFTER_ROUNDING):
+ case identity2d(UNUM_IDENTITY_FALLBACK_APPROXIMATELY,
+ UNUM_IDENTITY_RESULT_EQUAL_BEFORE_ROUNDING):
+ case identity2d(UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE,
+ UNUM_IDENTITY_RESULT_EQUAL_AFTER_ROUNDING):
+ formatApproximately(data, micros1, micros2, status);
+ break;
+
+ case identity2d(UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE,
+ UNUM_IDENTITY_RESULT_EQUAL_BEFORE_ROUNDING):
+ case identity2d(UNUM_IDENTITY_FALLBACK_SINGLE_VALUE,
+ UNUM_IDENTITY_RESULT_EQUAL_AFTER_ROUNDING):
+ case identity2d(UNUM_IDENTITY_FALLBACK_SINGLE_VALUE,
+ UNUM_IDENTITY_RESULT_EQUAL_BEFORE_ROUNDING):
+ formatSingleValue(data, micros1, micros2, status);
+ break;
+
+ default:
+ U_ASSERT(false);
+ break;
+ }
+}
+
+
+void NumberRangeFormatterImpl::formatSingleValue(UFormattedNumberRangeData& data,
+ MicroProps& micros1, MicroProps& micros2,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) { return; }
+ if (fSameFormatters) {
+ int32_t length = NumberFormatterImpl::writeNumber(micros1, data.quantity1, data.string, 0, status);
+ NumberFormatterImpl::writeAffixes(micros1, data.string, 0, length, status);
+ } else {
+ formatRange(data, micros1, micros2, status);
+ }
+}
+
+
+void NumberRangeFormatterImpl::formatApproximately (UFormattedNumberRangeData& data,
+ MicroProps& micros1, MicroProps& micros2,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) { return; }
+ if (fSameFormatters) {
+ int32_t length = NumberFormatterImpl::writeNumber(micros1, data.quantity1, data.string, 0, status);
+ // HEURISTIC: Desired modifier order: inner, middle, approximately, outer.
+ length += micros1.modInner->apply(data.string, 0, length, status);
+ length += micros1.modMiddle->apply(data.string, 0, length, status);
+ length += fApproximatelyModifier.apply(data.string, 0, length, status);
+ micros1.modOuter->apply(data.string, 0, length, status);
+ } else {
+ formatRange(data, micros1, micros2, status);
+ }
+}
+
+
+void NumberRangeFormatterImpl::formatRange(UFormattedNumberRangeData& data,
+ MicroProps& micros1, MicroProps& micros2,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) { return; }
+
+ // modInner is always notation (scientific); collapsable in ALL.
+ // modOuter is always units; collapsable in ALL, AUTO, and UNIT.
+ // modMiddle could be either; collapsable in ALL and sometimes AUTO and UNIT.
+ // Never collapse an outer mod but not an inner mod.
+ bool collapseOuter, collapseMiddle, collapseInner;
+ switch (fCollapse) {
+ case UNUM_RANGE_COLLAPSE_ALL:
+ case UNUM_RANGE_COLLAPSE_AUTO:
+ case UNUM_RANGE_COLLAPSE_UNIT:
+ {
+ // OUTER MODIFIER
+ collapseOuter = micros1.modOuter->semanticallyEquivalent(*micros2.modOuter);
+
+ if (!collapseOuter) {
+ // Never collapse inner mods if outer mods are not collapsable
+ collapseMiddle = false;
+ collapseInner = false;
+ break;
+ }
+
+ // MIDDLE MODIFIER
+ collapseMiddle = micros1.modMiddle->semanticallyEquivalent(*micros2.modMiddle);
+
+ if (!collapseMiddle) {
+ // Never collapse inner mods if outer mods are not collapsable
+ collapseInner = false;
+ break;
+ }
+
+ // MIDDLE MODIFIER HEURISTICS
+ // (could disable collapsing of the middle modifier)
+ // The modifiers are equal by this point, so we can look at just one of them.
+ const Modifier* mm = micros1.modMiddle;
+ if (fCollapse == UNUM_RANGE_COLLAPSE_UNIT) {
+ // 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)) {
+ collapseMiddle = false;
+ }
+ } else if (fCollapse == UNUM_RANGE_COLLAPSE_AUTO) {
+ // Heuristic as of ICU 63: collapse only if the modifier is more than one code point.
+ if (mm->getCodePointCount() <= 1) {
+ collapseMiddle = false;
+ }
+ }
+
+ if (!collapseMiddle || fCollapse != UNUM_RANGE_COLLAPSE_ALL) {
+ collapseInner = false;
+ break;
+ }
+
+ // INNER MODIFIER
+ collapseInner = micros1.modInner->semanticallyEquivalent(*micros2.modInner);
+
+ // All done checking for collapsability.
+ break;
+ }
+
+ default:
+ collapseOuter = false;
+ collapseMiddle = false;
+ collapseInner = false;
+ break;
+ }
+
+ NumberStringBuilder& string = data.string;
+ int32_t lengthPrefix = 0;
+ int32_t length1 = 0;
+ int32_t lengthInfix = 0;
+ int32_t length2 = 0;
+ int32_t lengthSuffix = 0;
+
+ // Use #define so that these are evaluated at the call site.
+ #define UPRV_INDEX_0 (lengthPrefix)
+ #define UPRV_INDEX_1 (lengthPrefix + length1)
+ #define UPRV_INDEX_2 (lengthPrefix + length1 + lengthInfix)
+ #define UPRV_INDEX_3 (lengthPrefix + length1 + lengthInfix + length2)
+
+ int32_t lengthRange = SimpleModifier::formatTwoArgPattern(
+ fRangeFormatter,
+ string,
+ 0,
+ &lengthPrefix,
+ &lengthSuffix,
+ UNUM_FIELD_COUNT,
+ status);
+ if (U_FAILURE(status)) { return; }
+ lengthInfix = lengthRange - lengthPrefix - lengthSuffix;
+ U_ASSERT(lengthInfix > 0);
+
+ // SPACING HEURISTIC
+ // Add spacing unless all modifiers are collapsed.
+ // TODO: add API to control this?
+ // TODO: Use a data-driven heuristic like currency spacing?
+ // TODO: Use Unicode [:whitespace:] instead of PatternProps whitespace? (consider speed implications)
+ {
+ bool repeatInner = !collapseInner && micros1.modInner->getCodePointCount() > 0;
+ bool repeatMiddle = !collapseMiddle && micros1.modMiddle->getCodePointCount() > 0;
+ bool repeatOuter = !collapseOuter && micros1.modOuter->getCodePointCount() > 0;
+ 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);
+ }
+ if (!PatternProps::isWhiteSpace(string.charAt(UPRV_INDEX_2 - 1))) {
+ lengthInfix += string.insertCodePoint(UPRV_INDEX_2, u'\u0020', UNUM_FIELD_COUNT, status);
+ }
+ }
+ }
+
+ length1 += NumberFormatterImpl::writeNumber(micros1, data.quantity1, string, UPRV_INDEX_0, status);
+ length2 += NumberFormatterImpl::writeNumber(micros2, data.quantity2, string, UPRV_INDEX_2, status);
+
+ // TODO: Support padding?
+
+ if (collapseInner) {
+ // Note: this is actually a mix of prefix and suffix, but adding to infix length works
+ const Modifier& mod = resolveModifierPlurals(*micros1.modInner, *micros2.modInner);
+ lengthInfix += mod.apply(string, UPRV_INDEX_0, UPRV_INDEX_3, status);
+ } else {
+ length1 += micros1.modInner->apply(string, UPRV_INDEX_0, UPRV_INDEX_1, status);
+ length2 += micros2.modInner->apply(string, UPRV_INDEX_2, UPRV_INDEX_3, status);
+ }
+
+ if (collapseMiddle) {
+ // Note: this is actually a mix of prefix and suffix, but adding to infix length works
+ const Modifier& mod = resolveModifierPlurals(*micros1.modMiddle, *micros2.modMiddle);
+ lengthInfix += mod.apply(string, UPRV_INDEX_0, UPRV_INDEX_3, status);
+ } else {
+ length1 += micros1.modMiddle->apply(string, UPRV_INDEX_0, UPRV_INDEX_1, status);
+ length2 += micros2.modMiddle->apply(string, UPRV_INDEX_2, UPRV_INDEX_3, status);
+ }
+
+ if (collapseOuter) {
+ // Note: this is actually a mix of prefix and suffix, but adding to infix length works
+ const Modifier& mod = resolveModifierPlurals(*micros1.modOuter, *micros2.modOuter);
+ lengthInfix += mod.apply(string, UPRV_INDEX_0, UPRV_INDEX_3, status);
+ } else {
+ length1 += micros1.modOuter->apply(string, UPRV_INDEX_0, UPRV_INDEX_1, status);
+ length2 += micros2.modOuter->apply(string, UPRV_INDEX_2, UPRV_INDEX_3, status);
+ }
+}
+
+
+const Modifier&
+NumberRangeFormatterImpl::resolveModifierPlurals(const Modifier& first, const Modifier& second) const {
+ Modifier::Parameters parameters;
+ first.getParameters(parameters);
+ if (parameters.obj == nullptr) {
+ // No plural form; return a fallback (e.g., the first)
+ return first;
+ }
+ StandardPlural::Form firstPlural = parameters.plural;
+
+ second.getParameters(parameters);
+ if (parameters.obj == nullptr) {
+ // No plural form; return a fallback (e.g., the first)
+ return first;
+ }
+ StandardPlural::Form secondPlural = parameters.plural;
+
+ // Get the required plural form from data
+ StandardPlural::Form resultPlural = fPluralRanges.resolve(firstPlural, secondPlural);
+
+ // Get and return the new Modifier
+ const Modifier* mod = parameters.obj->getModifier(parameters.signum, resultPlural);
+ U_ASSERT(mod != nullptr);
+ return *mod;
+}
+
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/deps/icu-small/source/i18n/numrange_impl.h b/deps/icu-small/source/i18n/numrange_impl.h
new file mode 100644
index 0000000000..787fc65686
--- /dev/null
+++ b/deps/icu-small/source/i18n/numrange_impl.h
@@ -0,0 +1,114 @@
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+#ifndef __SOURCE_NUMRANGE_TYPES_H__
+#define __SOURCE_NUMRANGE_TYPES_H__
+
+#include "unicode/numberformatter.h"
+#include "unicode/numberrangeformatter.h"
+#include "unicode/simpleformatter.h"
+#include "number_types.h"
+#include "number_decimalquantity.h"
+#include "number_formatimpl.h"
+#include "number_stringbuilder.h"
+
+U_NAMESPACE_BEGIN namespace number {
+namespace impl {
+
+
+/**
+ * Class similar to UFormattedNumberData.
+ *
+ * Has incomplete magic number logic that will need to be finished
+ * if this is to be exposed as C API in the future.
+ */
+struct UFormattedNumberRangeData : public UMemory {
+ // The magic number to identify incoming objects.
+ // Reads in ASCII as "FDR" (FormatteDnumberRange with room at the end)
+ static constexpr int32_t kMagic = 0x46445200;
+
+ // Data members:
+ int32_t fMagic = kMagic;
+ DecimalQuantity quantity1;
+ DecimalQuantity quantity2;
+ NumberStringBuilder string;
+ UNumberRangeIdentityResult identityResult = UNUM_IDENTITY_RESULT_COUNT;
+
+ // No C conversion methods (no C API yet)
+};
+
+
+class StandardPluralRanges : public UMemory {
+ public:
+ void initialize(const Locale& locale, UErrorCode& status);
+ StandardPlural::Form resolve(StandardPlural::Form first, StandardPlural::Form second) const;
+
+ /** Used for data loading. */
+ void addPluralRange(
+ StandardPlural::Form first,
+ StandardPlural::Form second,
+ StandardPlural::Form result);
+
+ /** Used for data loading. */
+ void setCapacity(int32_t length);
+
+ private:
+ struct StandardPluralRangeTriple {
+ StandardPlural::Form first;
+ StandardPlural::Form second;
+ StandardPlural::Form result;
+ };
+
+ // TODO: An array is simple here, but it results in linear lookup time.
+ // Certain locales have 20-30 entries in this list.
+ // Consider changing to a smarter data structure.
+ typedef MaybeStackArray<StandardPluralRangeTriple, 3> PluralRangeTriples;
+ PluralRangeTriples fTriples;
+ int32_t fTriplesLen = 0;
+};
+
+
+class NumberRangeFormatterImpl : public UMemory {
+ public:
+ NumberRangeFormatterImpl(const RangeMacroProps& macros, UErrorCode& status);
+
+ void format(UFormattedNumberRangeData& data, bool equalBeforeRounding, UErrorCode& status) const;
+
+ private:
+ NumberFormatterImpl formatterImpl1;
+ NumberFormatterImpl formatterImpl2;
+ bool fSameFormatters;
+
+ UNumberRangeCollapse fCollapse;
+ UNumberRangeIdentityFallback fIdentityFallback;
+
+ SimpleFormatter fRangeFormatter;
+ SimpleModifier fApproximatelyModifier;
+
+ StandardPluralRanges fPluralRanges;
+
+ void formatSingleValue(UFormattedNumberRangeData& data,
+ MicroProps& micros1, MicroProps& micros2,
+ UErrorCode& status) const;
+
+ void formatApproximately(UFormattedNumberRangeData& data,
+ MicroProps& micros1, MicroProps& micros2,
+ UErrorCode& status) const;
+
+ void formatRange(UFormattedNumberRangeData& data,
+ MicroProps& micros1, MicroProps& micros2,
+ UErrorCode& status) const;
+
+ const Modifier& resolveModifierPlurals(const Modifier& first, const Modifier& second) const;
+};
+
+
+} // namespace impl
+} // namespace number
+U_NAMESPACE_END
+
+#endif //__SOURCE_NUMRANGE_TYPES_H__
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/deps/icu-small/source/i18n/numsys.cpp b/deps/icu-small/source/i18n/numsys.cpp
index 087dd277eb..514fe05e5a 100644
--- a/deps/icu-small/source/i18n/numsys.cpp
+++ b/deps/icu-small/source/i18n/numsys.cpp
@@ -79,43 +79,45 @@ NumberingSystem* U_EXPORT2
NumberingSystem::createInstance(int32_t radix_in, UBool isAlgorithmic_in, const UnicodeString & desc_in, UErrorCode &status) {
if (U_FAILURE(status)) {
- return NULL;
+ return nullptr;
}
if ( radix_in < 2 ) {
status = U_ILLEGAL_ARGUMENT_ERROR;
- return NULL;
+ return nullptr;
}
if ( !isAlgorithmic_in ) {
if ( desc_in.countChar32() != radix_in ) {
status = U_ILLEGAL_ARGUMENT_ERROR;
- return NULL;
+ return nullptr;
}
}
- NumberingSystem *ns = new NumberingSystem();
+ LocalPointer<NumberingSystem> ns(new NumberingSystem(), status);
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
ns->setRadix(radix_in);
ns->setDesc(desc_in);
ns->setAlgorithmic(isAlgorithmic_in);
- ns->setName(NULL);
- return ns;
+ ns->setName(nullptr);
+ return ns.orphan();
}
-
NumberingSystem* U_EXPORT2
NumberingSystem::createInstance(const Locale & inLocale, UErrorCode& status) {
if (U_FAILURE(status)) {
- return NULL;
+ return nullptr;
}
UBool nsResolved = TRUE;
UBool usingFallback = FALSE;
char buffer[ULOC_KEYWORDS_CAPACITY];
- int32_t count = inLocale.getKeywordValue("numbers",buffer, sizeof(buffer),status);
+ int32_t count = inLocale.getKeywordValue("numbers", buffer, sizeof(buffer), status);
if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) {
// the "numbers" keyword exceeds ULOC_KEYWORDS_CAPACITY; ignore and use default.
count = 0;
@@ -129,20 +131,30 @@ NumberingSystem::createInstance(const Locale & inLocale, UErrorCode& status) {
nsResolved = FALSE;
}
} else {
- uprv_strcpy(buffer,gDefault);
+ uprv_strcpy(buffer, gDefault);
nsResolved = FALSE;
}
if (!nsResolved) { // Resolve the numbering system ( default, native, traditional or finance ) into a "real" numbering system
UErrorCode localStatus = U_ZERO_ERROR;
- UResourceBundle *resource = ures_open(NULL, inLocale.getName(), &localStatus);
- UResourceBundle *numberElementsRes = ures_getByKey(resource,gNumberElements,NULL,&localStatus);
+ LocalUResourceBundlePointer resource(ures_open(nullptr, inLocale.getName(), &localStatus));
+ LocalUResourceBundlePointer numberElementsRes(ures_getByKey(resource.getAlias(), gNumberElements, nullptr, &localStatus));
+ // Don't stomp on the catastrophic failure of OOM.
+ if (localStatus == U_MEMORY_ALLOCATION_ERROR) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
while (!nsResolved) {
localStatus = U_ZERO_ERROR;
count = 0;
- const UChar *nsName = ures_getStringByKeyWithFallback(numberElementsRes, buffer, &count, &localStatus);
+ const UChar *nsName = ures_getStringByKeyWithFallback(numberElementsRes.getAlias(), buffer, &count, &localStatus);
+ // Don't stomp on the catastrophic failure of OOM.
+ if (localStatus == U_MEMORY_ALLOCATION_ERROR) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
if ( count > 0 && count < ULOC_KEYWORDS_CAPACITY ) { // numbering system found
- u_UCharsToChars(nsName,buffer,count);
+ u_UCharsToChars(nsName, buffer, count);
buffer[count] = '\0'; // Make sure it is null terminated.
nsResolved = TRUE;
}
@@ -158,16 +170,17 @@ NumberingSystem::createInstance(const Locale & inLocale, UErrorCode& status) {
}
}
}
- ures_close(numberElementsRes);
- ures_close(resource);
}
if (usingFallback) {
status = U_USING_FALLBACK_WARNING;
NumberingSystem *ns = new NumberingSystem();
+ if (ns == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
return ns;
} else {
- return NumberingSystem::createInstanceByName(buffer,status);
+ return NumberingSystem::createInstanceByName(buffer, status);
}
}
@@ -178,36 +191,37 @@ NumberingSystem::createInstance(UErrorCode& status) {
NumberingSystem* U_EXPORT2
NumberingSystem::createInstanceByName(const char *name, UErrorCode& status) {
- UResourceBundle *numberingSystemsInfo = NULL;
- UResourceBundle *nsTop, *nsCurrent;
int32_t radix = 10;
int32_t algorithmic = 0;
- numberingSystemsInfo = ures_openDirect(NULL,gNumberingSystems, &status);
- nsCurrent = ures_getByKey(numberingSystemsInfo,gNumberingSystems,NULL,&status);
- nsTop = ures_getByKey(nsCurrent,name,NULL,&status);
- UnicodeString nsd = ures_getUnicodeStringByKey(nsTop,gDesc,&status);
+ LocalUResourceBundlePointer numberingSystemsInfo(ures_openDirect(nullptr, gNumberingSystems, &status));
+ LocalUResourceBundlePointer nsCurrent(ures_getByKey(numberingSystemsInfo.getAlias(), gNumberingSystems, nullptr, &status));
+ LocalUResourceBundlePointer nsTop(ures_getByKey(nsCurrent.getAlias(), name, nullptr, &status));
- ures_getByKey(nsTop,gRadix,nsCurrent,&status);
- radix = ures_getInt(nsCurrent,&status);
+ UnicodeString nsd = ures_getUnicodeStringByKey(nsTop.getAlias(), gDesc, &status);
- ures_getByKey(nsTop,gAlgorithmic,nsCurrent,&status);
- algorithmic = ures_getInt(nsCurrent,&status);
+ ures_getByKey(nsTop.getAlias(), gRadix, nsCurrent.getAlias(), &status);
+ radix = ures_getInt(nsCurrent.getAlias(), &status);
- UBool isAlgorithmic = ( algorithmic == 1 );
+ ures_getByKey(nsTop.getAlias(), gAlgorithmic, nsCurrent.getAlias(), &status);
+ algorithmic = ures_getInt(nsCurrent.getAlias(), &status);
- ures_close(nsCurrent);
- ures_close(nsTop);
- ures_close(numberingSystemsInfo);
+ UBool isAlgorithmic = ( algorithmic == 1 );
if (U_FAILURE(status)) {
- status = U_UNSUPPORTED_ERROR;
- return NULL;
+ // Don't stomp on the catastrophic failure of OOM.
+ if (status != U_MEMORY_ALLOCATION_ERROR) {
+ status = U_UNSUPPORTED_ERROR;
+ }
+ return nullptr;
}
- NumberingSystem* ns = NumberingSystem::createInstance(radix,isAlgorithmic,nsd,status);
+ LocalPointer<NumberingSystem> ns(NumberingSystem::createInstance(radix, isAlgorithmic, nsd, status), status);
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
ns->setName(name);
- return ns;
+ return ns.orphan();
}
/**
@@ -241,11 +255,11 @@ void NumberingSystem::setDesc(const UnicodeString &d) {
desc.setTo(d);
}
void NumberingSystem::setName(const char *n) {
- if ( n == NULL ) {
+ if ( n == nullptr ) {
name[0] = (char) 0;
} else {
uprv_strncpy(name,n,NUMSYS_NAME_CAPACITY);
- name[NUMSYS_NAME_CAPACITY] = (char)0; // Make sure it is null terminated.
+ name[NUMSYS_NAME_CAPACITY] = '\0'; // Make sure it is null terminated.
}
}
UBool NumberingSystem::isAlgorithmic() const {
@@ -254,43 +268,57 @@ UBool NumberingSystem::isAlgorithmic() const {
StringEnumeration* NumberingSystem::getAvailableNames(UErrorCode &status) {
// TODO(ticket #11908): Init-once static cache, with u_cleanup() callback.
- static StringEnumeration* availableNames = NULL;
+ static StringEnumeration* availableNames = nullptr;
if (U_FAILURE(status)) {
- return NULL;
+ return nullptr;
}
- if ( availableNames == NULL ) {
+ if ( availableNames == nullptr ) {
// TODO: Simple array of UnicodeString objects, based on length of table resource?
- LocalPointer<UVector> numsysNames(new UVector(uprv_deleteUObject, NULL, status), status);
+ LocalPointer<UVector> numsysNames(new UVector(uprv_deleteUObject, nullptr, status), status);
if (U_FAILURE(status)) {
- return NULL;
+ return nullptr;
}
UErrorCode rbstatus = U_ZERO_ERROR;
- UResourceBundle *numberingSystemsInfo = ures_openDirect(NULL, "numberingSystems", &rbstatus);
- numberingSystemsInfo = ures_getByKey(numberingSystemsInfo,"numberingSystems",numberingSystemsInfo,&rbstatus);
- if(U_FAILURE(rbstatus)) {
- status = U_MISSING_RESOURCE_ERROR;
+ UResourceBundle *numberingSystemsInfo = ures_openDirect(nullptr, "numberingSystems", &rbstatus);
+ numberingSystemsInfo = ures_getByKey(numberingSystemsInfo, "numberingSystems", numberingSystemsInfo, &rbstatus);
+ if (U_FAILURE(rbstatus)) {
+ // Don't stomp on the catastrophic failure of OOM.
+ if (rbstatus == U_MEMORY_ALLOCATION_ERROR) {
+ status = rbstatus;
+ } else {
+ status = U_MISSING_RESOURCE_ERROR;
+ }
ures_close(numberingSystemsInfo);
- return NULL;
+ return nullptr;
}
- while ( ures_hasNext(numberingSystemsInfo) ) {
- UResourceBundle *nsCurrent = ures_getNextResource(numberingSystemsInfo,NULL,&rbstatus);
- const char *nsName = ures_getKey(nsCurrent);
- numsysNames->addElement(new UnicodeString(nsName, -1, US_INV),status);
- ures_close(nsCurrent);
+ while ( ures_hasNext(numberingSystemsInfo) && U_SUCCESS(status) ) {
+ LocalUResourceBundlePointer nsCurrent(ures_getNextResource(numberingSystemsInfo, nullptr, &rbstatus));
+ if (rbstatus == U_MEMORY_ALLOCATION_ERROR) {
+ status = rbstatus; // we want to report OOM failure back to the caller.
+ break;
+ }
+ const char *nsName = ures_getKey(nsCurrent.getAlias());
+ LocalPointer<UnicodeString> newElem(new UnicodeString(nsName, -1, US_INV), status);
+ if (U_SUCCESS(status)) {
+ numsysNames->addElement(newElem.getAlias(), status);
+ if (U_SUCCESS(status)) {
+ newElem.orphan(); // on success, the numsysNames vector owns newElem.
+ }
+ }
}
ures_close(numberingSystemsInfo);
if (U_FAILURE(status)) {
- return NULL;
+ return nullptr;
}
availableNames = new NumsysNameEnumeration(numsysNames.getAlias(), status);
- if (availableNames == NULL) {
+ if (availableNames == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
+ return nullptr;
}
numsysNames.orphan(); // The names got adopted.
}
@@ -305,10 +333,10 @@ NumsysNameEnumeration::NumsysNameEnumeration(UVector *numsysNames, UErrorCode& /
const UnicodeString*
NumsysNameEnumeration::snext(UErrorCode& status) {
- if (U_SUCCESS(status) && pos < fNumsysNames->size()) {
+ if (U_SUCCESS(status) && (fNumsysNames != nullptr) && (pos < fNumsysNames->size())) {
return (const UnicodeString*)fNumsysNames->elementAt(pos++);
}
- return NULL;
+ return nullptr;
}
void
@@ -318,7 +346,7 @@ NumsysNameEnumeration::reset(UErrorCode& /*status*/) {
int32_t
NumsysNameEnumeration::count(UErrorCode& /*status*/) const {
- return (fNumsysNames==NULL) ? 0 : fNumsysNames->size();
+ return (fNumsysNames==nullptr) ? 0 : fNumsysNames->size();
}
NumsysNameEnumeration::~NumsysNameEnumeration() {
diff --git a/deps/icu-small/source/i18n/numsys_impl.h b/deps/icu-small/source/i18n/numsys_impl.h
index 6385fa5408..733e102365 100644
--- a/deps/icu-small/source/i18n/numsys_impl.h
+++ b/deps/icu-small/source/i18n/numsys_impl.h
@@ -37,7 +37,7 @@ public:
virtual int32_t count(UErrorCode& status) const;
private:
int32_t pos;
- UVector *fNumsysNames;
+ UVector *fNumsysNames = nullptr;
};
U_NAMESPACE_END
diff --git a/deps/icu-small/source/i18n/olsontz.cpp b/deps/icu-small/source/i18n/olsontz.cpp
index df025c0808..c350057466 100644
--- a/deps/icu-small/source/i18n/olsontz.cpp
+++ b/deps/icu-small/source/i18n/olsontz.cpp
@@ -140,7 +140,7 @@ OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top,
// Pre-32bit second transitions
ures_getByKey(res, kTRANSPRE32, &r, &ec);
transitionTimesPre32 = ures_getIntVector(&r, &len, &ec);
- transitionCountPre32 = len >> 1;
+ transitionCountPre32 = static_cast<int16_t>(len >> 1);
if (ec == U_MISSING_RESOURCE_ERROR) {
// No pre-32bit transitions
transitionTimesPre32 = NULL;
@@ -153,7 +153,7 @@ OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top,
// 32bit second transitions
ures_getByKey(res, kTRANS, &r, &ec);
transitionTimes32 = ures_getIntVector(&r, &len, &ec);
- transitionCount32 = len;
+ transitionCount32 = static_cast<int16_t>(len);
if (ec == U_MISSING_RESOURCE_ERROR) {
// No 32bit transitions
transitionTimes32 = NULL;
@@ -166,7 +166,7 @@ OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top,
// Post-32bit second transitions
ures_getByKey(res, kTRANSPOST32, &r, &ec);
transitionTimesPost32 = ures_getIntVector(&r, &len, &ec);
- transitionCountPost32 = len >> 1;
+ transitionCountPost32 = static_cast<int16_t>(len >> 1);
if (ec == U_MISSING_RESOURCE_ERROR) {
// No pre-32bit transitions
transitionTimesPost32 = NULL;
diff --git a/deps/icu-small/source/i18n/plurrule.cpp b/deps/icu-small/source/i18n/plurrule.cpp
index 9597e8eb00..3caa48a57b 100644
--- a/deps/icu-small/source/i18n/plurrule.cpp
+++ b/deps/icu-small/source/i18n/plurrule.cpp
@@ -65,13 +65,15 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(PluralKeywordEnumeration)
PluralRules::PluralRules(UErrorCode& /*status*/)
: UObject(),
- mRules(NULL)
+ mRules(nullptr),
+ mInternalStatus(U_ZERO_ERROR)
{
}
PluralRules::PluralRules(const PluralRules& other)
: UObject(other),
- mRules(NULL)
+ mRules(nullptr),
+ mInternalStatus(U_ZERO_ERROR)
{
*this=other;
}
@@ -86,54 +88,67 @@ SharedPluralRules::~SharedPluralRules() {
PluralRules*
PluralRules::clone() const {
- return new PluralRules(*this);
+ PluralRules* newObj = new PluralRules(*this);
+ // Since clone doesn't have a 'status' parameter, the best we can do is return nullptr if
+ // the newly created object was not fully constructed properly (an error occurred).
+ if (newObj != nullptr && U_FAILURE(newObj->mInternalStatus)) {
+ delete newObj;
+ newObj = nullptr;
+ }
+ return newObj;
}
PluralRules&
PluralRules::operator=(const PluralRules& other) {
if (this != &other) {
delete mRules;
- if (other.mRules==NULL) {
- mRules = NULL;
+ mRules = nullptr;
+ mInternalStatus = other.mInternalStatus;
+ if (U_FAILURE(mInternalStatus)) {
+ // bail out early if the object we were copying from was already 'invalid'.
+ return *this;
}
- else {
+ if (other.mRules != nullptr) {
mRules = new RuleChain(*other.mRules);
+ if (mRules == nullptr) {
+ mInternalStatus = U_MEMORY_ALLOCATION_ERROR;
+ }
+ else if (U_FAILURE(mRules->fInternalStatus)) {
+ // If the RuleChain wasn't fully copied, then set our status to failure as well.
+ mInternalStatus = mRules->fInternalStatus;
+ }
}
}
-
return *this;
}
StringEnumeration* PluralRules::getAvailableLocales(UErrorCode &status) {
- StringEnumeration *result = new PluralAvailableLocalesEnumeration(status);
- if (result == NULL && U_SUCCESS(status)) {
- status = U_MEMORY_ALLOCATION_ERROR;
+ if (U_FAILURE(status)) {
+ return nullptr;
}
+ LocalPointer<StringEnumeration> result(new PluralAvailableLocalesEnumeration(status), status);
if (U_FAILURE(status)) {
- delete result;
- result = NULL;
+ return nullptr;
}
- return result;
+ return result.orphan();
}
PluralRules* U_EXPORT2
PluralRules::createRules(const UnicodeString& description, UErrorCode& status) {
if (U_FAILURE(status)) {
- return NULL;
+ return nullptr;
}
-
PluralRuleParser parser;
- PluralRules *newRules = new PluralRules(status);
- if (U_SUCCESS(status) && newRules == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
+ LocalPointer<PluralRules> newRules(new PluralRules(status), status);
+ if (U_FAILURE(status)) {
+ return nullptr;
}
- parser.parse(description, newRules, status);
+ parser.parse(description, newRules.getAlias(), status);
if (U_FAILURE(status)) {
- delete newRules;
- newRules = NULL;
+ newRules.adoptInstead(nullptr);
}
- return newRules;
+ return newRules.orphan();
}
@@ -149,19 +164,17 @@ template<> U_I18N_API
const SharedPluralRules *LocaleCacheKey<SharedPluralRules>::createObject(
const void * /*unused*/, UErrorCode &status) const {
const char *localeId = fLoc.getName();
- PluralRules *pr = PluralRules::internalForLocale(
- localeId, UPLURAL_TYPE_CARDINAL, status);
+ LocalPointer<PluralRules> pr(PluralRules::internalForLocale(localeId, UPLURAL_TYPE_CARDINAL, status), status);
if (U_FAILURE(status)) {
- return NULL;
+ return nullptr;
}
- SharedPluralRules *result = new SharedPluralRules(pr);
- if (result == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- delete pr;
- return NULL;
+ LocalPointer<SharedPluralRules> result(new SharedPluralRules(pr.getAlias()), status);
+ if (U_FAILURE(status)) {
+ return nullptr;
}
+ pr.orphan(); // result was successfully created so it nows pr.
result->addRef();
- return result;
+ return result.orphan();
}
/* end plural rules cache */
@@ -171,13 +184,13 @@ const SharedPluralRules* U_EXPORT2
PluralRules::createSharedInstance(
const Locale& locale, UPluralType type, UErrorCode& status) {
if (U_FAILURE(status)) {
- return NULL;
+ return nullptr;
}
if (type != UPLURAL_TYPE_CARDINAL) {
status = U_UNSUPPORTED_ERROR;
- return NULL;
+ return nullptr;
}
- const SharedPluralRules *result = NULL;
+ const SharedPluralRules *result = nullptr;
UnifiedCache::getByLocale(locale, result, status);
return result;
}
@@ -195,11 +208,11 @@ PluralRules::forLocale(const Locale& locale, UPluralType type, UErrorCode& statu
const SharedPluralRules *shared = createSharedInstance(
locale, type, status);
if (U_FAILURE(status)) {
- return NULL;
+ return nullptr;
}
PluralRules *result = (*shared)->clone();
shared->removeRef();
- if (result == NULL) {
+ if (result == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
}
return result;
@@ -208,20 +221,23 @@ PluralRules::forLocale(const Locale& locale, UPluralType type, UErrorCode& statu
PluralRules* U_EXPORT2
PluralRules::internalForLocale(const Locale& locale, UPluralType type, UErrorCode& status) {
if (U_FAILURE(status)) {
- return NULL;
+ return nullptr;
}
if (type >= UPLURAL_TYPE_COUNT) {
status = U_ILLEGAL_ARGUMENT_ERROR;
- return NULL;
+ return nullptr;
}
- PluralRules *newObj = new PluralRules(status);
- if (newObj==NULL || U_FAILURE(status)) {
- delete newObj;
- return NULL;
+ LocalPointer<PluralRules> newObj(new PluralRules(status), status);
+ if (U_FAILURE(status)) {
+ return nullptr;
}
UnicodeString locRule = newObj->getRuleFromResource(locale, type, status);
- // TODO: which errors, if any, should be returned?
+ // TODO: which other errors, if any, should be returned?
if (locRule.length() == 0) {
+ // If an out-of-memory error occurred, then stop and report the failure.
+ if (status == U_MEMORY_ALLOCATION_ERROR) {
+ return nullptr;
+ }
// Locales with no specific rules (all numbers have the "other" category
// will return a U_MISSING_RESOURCE_ERROR at this point. This is not
// an error.
@@ -229,13 +245,13 @@ PluralRules::internalForLocale(const Locale& locale, UPluralType type, UErrorCod
status = U_ZERO_ERROR;
}
PluralRuleParser parser;
- parser.parse(locRule, newObj, status);
+ parser.parse(locRule, newObj.getAlias(), status);
// TODO: should rule parse errors be returned, or
// should we silently use default rules?
// Original impl used default rules.
// Ask the question to ICU Core.
- return newObj;
+ return newObj.orphan();
}
UnicodeString
@@ -250,7 +266,7 @@ PluralRules::select(double number) const {
UnicodeString
PluralRules::select(const IFixedDecimal &number) const {
- if (mRules == NULL) {
+ if (mRules == nullptr) {
return UnicodeString(TRUE, PLURAL_DEFAULT_RULE, -1);
}
else {
@@ -262,14 +278,18 @@ PluralRules::select(const IFixedDecimal &number) const {
StringEnumeration*
PluralRules::getKeywords(UErrorCode& status) const {
- if (U_FAILURE(status)) return NULL;
- StringEnumeration* nameEnumerator = new PluralKeywordEnumeration(mRules, status);
if (U_FAILURE(status)) {
- delete nameEnumerator;
- return NULL;
+ return nullptr;
}
-
- return nameEnumerator;
+ if (U_FAILURE(mInternalStatus)) {
+ status = mInternalStatus;
+ return nullptr;
+ }
+ LocalPointer<StringEnumeration> nameEnumerator(new PluralKeywordEnumeration(mRules, status), status);
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+ return nameEnumerator.orphan();
}
double
@@ -367,8 +387,15 @@ getSamplesFromString(const UnicodeString &samples, double *dest,
int32_t
PluralRules::getSamples(const UnicodeString &keyword, double *dest,
int32_t destCapacity, UErrorCode& status) {
+ if (destCapacity == 0 || U_FAILURE(status)) {
+ return 0;
+ }
+ if (U_FAILURE(mInternalStatus)) {
+ status = mInternalStatus;
+ return 0;
+ }
RuleChain *rc = rulesForKeyword(keyword);
- if (rc == NULL || destCapacity == 0 || U_FAILURE(status)) {
+ if (rc == nullptr) {
return 0;
}
int32_t numSamples = getSamplesFromString(rc->fIntegerSamples, dest, destCapacity, status);
@@ -381,7 +408,7 @@ PluralRules::getSamples(const UnicodeString &keyword, double *dest,
RuleChain *PluralRules::rulesForKeyword(const UnicodeString &keyword) const {
RuleChain *rc;
- for (rc = mRules; rc != NULL; rc = rc->fNext) {
+ for (rc = mRules; rc != nullptr; rc = rc->fNext) {
if (rc->fKeyword == keyword) {
break;
}
@@ -395,7 +422,7 @@ PluralRules::isKeyword(const UnicodeString& keyword) const {
if (0 == keyword.compare(PLURAL_KEYWORD_OTHER, 5)) {
return true;
}
- return rulesForKeyword(keyword) != NULL;
+ return rulesForKeyword(keyword) != nullptr;
}
UnicodeString
@@ -421,13 +448,13 @@ PluralRules::operator==(const PluralRules& other) const {
return FALSE;
}
myKeywordList->reset(status);
- while ((ptrKeyword=myKeywordList->snext(status))!=NULL) {
+ while ((ptrKeyword=myKeywordList->snext(status))!=nullptr) {
if (!other.isKeyword(*ptrKeyword)) {
return FALSE;
}
}
otherKeywordList->reset(status);
- while ((ptrKeyword=otherKeywordList->snext(status))!=NULL) {
+ while ((ptrKeyword=otherKeywordList->snext(status))!=nullptr) {
if (!this->isKeyword(*ptrKeyword)) {
return FALSE;
}
@@ -460,29 +487,33 @@ PluralRuleParser::parse(const UnicodeString& ruleData, PluralRules *prules, UErr
}
switch (type) {
case tAnd:
- U_ASSERT(curAndConstraint != NULL);
- curAndConstraint = curAndConstraint->add();
+ U_ASSERT(curAndConstraint != nullptr);
+ curAndConstraint = curAndConstraint->add(status);
break;
case tOr:
{
- U_ASSERT(currentChain != NULL);
+ U_ASSERT(currentChain != nullptr);
OrConstraint *orNode=currentChain->ruleHeader;
- while (orNode->next != NULL) {
+ while (orNode->next != nullptr) {
orNode = orNode->next;
}
orNode->next= new OrConstraint();
+ if (orNode->next == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
orNode=orNode->next;
- orNode->next=NULL;
- curAndConstraint = orNode->add();
+ orNode->next=nullptr;
+ curAndConstraint = orNode->add(status);
}
break;
case tIs:
- U_ASSERT(curAndConstraint != NULL);
+ U_ASSERT(curAndConstraint != nullptr);
U_ASSERT(curAndConstraint->value == -1);
- U_ASSERT(curAndConstraint->rangeList == NULL);
+ U_ASSERT(curAndConstraint->rangeList == nullptr);
break;
case tNot:
- U_ASSERT(curAndConstraint != NULL);
+ U_ASSERT(curAndConstraint != nullptr);
curAndConstraint->negated=TRUE;
break;
@@ -492,23 +523,29 @@ PluralRuleParser::parse(const UnicodeString& ruleData, PluralRules *prules, UErr
case tIn:
case tWithin:
case tEqual:
- U_ASSERT(curAndConstraint != NULL);
- curAndConstraint->rangeList = new UVector32(status);
- curAndConstraint->rangeList->addElement(-1, status); // range Low
- curAndConstraint->rangeList->addElement(-1, status); // range Hi
- rangeLowIdx = 0;
- rangeHiIdx = 1;
- curAndConstraint->value=PLURAL_RANGE_HIGH;
- curAndConstraint->integerOnly = (type != tWithin);
+ {
+ U_ASSERT(curAndConstraint != nullptr);
+ LocalPointer<UVector32> newRangeList(new UVector32(status), status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ curAndConstraint->rangeList = newRangeList.orphan();
+ curAndConstraint->rangeList->addElement(-1, status); // range Low
+ curAndConstraint->rangeList->addElement(-1, status); // range Hi
+ rangeLowIdx = 0;
+ rangeHiIdx = 1;
+ curAndConstraint->value=PLURAL_RANGE_HIGH;
+ curAndConstraint->integerOnly = (type != tWithin);
+ }
break;
case tNumber:
- U_ASSERT(curAndConstraint != NULL);
+ U_ASSERT(curAndConstraint != nullptr);
if ( (curAndConstraint->op==AndConstraint::MOD)&&
(curAndConstraint->opNum == -1 ) ) {
curAndConstraint->opNum=getNumberValue(token);
}
else {
- if (curAndConstraint->rangeList == NULL) {
+ if (curAndConstraint->rangeList == nullptr) {
// this is for an 'is' rule
curAndConstraint->value = getNumberValue(token);
} else {
@@ -534,7 +571,7 @@ PluralRuleParser::parse(const UnicodeString& ruleData, PluralRules *prules, UErr
case tComma:
// TODO: rule syntax checking is inadequate, can happen with badly formed rules.
// Catch cases like "n mod 10, is 1" here instead.
- if (curAndConstraint == NULL || curAndConstraint->rangeList == NULL) {
+ if (curAndConstraint == nullptr || curAndConstraint->rangeList == nullptr) {
status = U_UNEXPECTED_TOKEN;
break;
}
@@ -545,7 +582,7 @@ PluralRuleParser::parse(const UnicodeString& ruleData, PluralRules *prules, UErr
curAndConstraint->rangeList->addElement(-1, status); // range Hi
break;
case tMod:
- U_ASSERT(curAndConstraint != NULL);
+ U_ASSERT(curAndConstraint != nullptr);
curAndConstraint->op=AndConstraint::MOD;
break;
case tVariableN:
@@ -553,24 +590,24 @@ PluralRuleParser::parse(const UnicodeString& ruleData, PluralRules *prules, UErr
case tVariableF:
case tVariableT:
case tVariableV:
- U_ASSERT(curAndConstraint != NULL);
+ U_ASSERT(curAndConstraint != nullptr);
curAndConstraint->digitsType = type;
break;
case tKeyword:
{
RuleChain *newChain = new RuleChain;
- if (newChain == NULL) {
+ if (newChain == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
break;
}
newChain->fKeyword = token;
- if (prules->mRules == NULL) {
+ if (prules->mRules == nullptr) {
prules->mRules = newChain;
} else {
// The new rule chain goes at the end of the linked list of rule chains,
// unless there is an "other" keyword & chain. "other" must remain last.
RuleChain *insertAfter = prules->mRules;
- while (insertAfter->fNext!=NULL &&
+ while (insertAfter->fNext!=nullptr &&
insertAfter->fNext->fKeyword.compare(PLURAL_KEYWORD_OTHER, 5) != 0 ){
insertAfter=insertAfter->fNext;
}
@@ -578,8 +615,12 @@ PluralRuleParser::parse(const UnicodeString& ruleData, PluralRules *prules, UErr
insertAfter->fNext = newChain;
}
OrConstraint *orNode = new OrConstraint();
+ if (orNode == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
newChain->ruleHeader = orNode;
- curAndConstraint = orNode->add();
+ curAndConstraint = orNode->add(status);
currentChain = newChain;
}
break;
@@ -629,7 +670,7 @@ PluralRules::getRuleFromResource(const Locale& locale, UPluralType type, UErrorC
if (U_FAILURE(errCode)) {
return emptyStr;
}
- LocalUResourceBundlePointer rb(ures_openDirect(NULL, "plurals", &errCode));
+ LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "plurals", &errCode));
if(U_FAILURE(errCode)) {
return emptyStr;
}
@@ -646,7 +687,7 @@ PluralRules::getRuleFromResource(const Locale& locale, UPluralType type, UErrorC
errCode = U_ILLEGAL_ARGUMENT_ERROR;
return emptyStr;
}
- LocalUResourceBundlePointer locRes(ures_getByKey(rb.getAlias(), typeKey, NULL, &errCode));
+ LocalUResourceBundlePointer locRes(ures_getByKey(rb.getAlias(), typeKey, nullptr, &errCode));
if(U_FAILURE(errCode)) {
return emptyStr;
}
@@ -654,25 +695,25 @@ PluralRules::getRuleFromResource(const Locale& locale, UPluralType type, UErrorC
const char *curLocaleName=locale.getName();
const UChar* s = ures_getStringByKey(locRes.getAlias(), curLocaleName, &resLen, &errCode);
- if (s == NULL) {
+ if (s == nullptr) {
// Check parent locales.
UErrorCode status = U_ZERO_ERROR;
char parentLocaleName[ULOC_FULLNAME_CAPACITY];
- const char *curLocaleName=locale.getName();
- uprv_strcpy(parentLocaleName, curLocaleName);
+ const char *curLocaleName2=locale.getName();
+ uprv_strcpy(parentLocaleName, curLocaleName2);
while (uloc_getParent(parentLocaleName, parentLocaleName,
ULOC_FULLNAME_CAPACITY, &status) > 0) {
resLen=0;
s = ures_getStringByKey(locRes.getAlias(), parentLocaleName, &resLen, &status);
- if (s != NULL) {
+ if (s != nullptr) {
errCode = U_ZERO_ERROR;
break;
}
status = U_ZERO_ERROR;
}
}
- if (s==NULL) {
+ if (s==nullptr) {
return emptyStr;
}
@@ -680,18 +721,18 @@ PluralRules::getRuleFromResource(const Locale& locale, UPluralType type, UErrorC
u_UCharsToChars(s, setKey, resLen + 1);
// printf("\n PluralRule: %s\n", setKey);
- LocalUResourceBundlePointer ruleRes(ures_getByKey(rb.getAlias(), "rules", NULL, &errCode));
+ LocalUResourceBundlePointer ruleRes(ures_getByKey(rb.getAlias(), "rules", nullptr, &errCode));
if(U_FAILURE(errCode)) {
return emptyStr;
}
- LocalUResourceBundlePointer setRes(ures_getByKey(ruleRes.getAlias(), setKey, NULL, &errCode));
+ LocalUResourceBundlePointer setRes(ures_getByKey(ruleRes.getAlias(), setKey, nullptr, &errCode));
if (U_FAILURE(errCode)) {
return emptyStr;
}
int32_t numberKeys = ures_getSize(setRes.getAlias());
UnicodeString result;
- const char *key=NULL;
+ const char *key=nullptr;
for(int32_t i=0; i<numberKeys; ++i) { // Keys are zero, one, few, ...
UnicodeString rules = ures_getNextUnicodeString(setRes.getAlias(), &key, &errCode);
UnicodeString uKey(key, -1, US_INV);
@@ -707,54 +748,46 @@ PluralRules::getRuleFromResource(const Locale& locale, UPluralType type, UErrorC
UnicodeString
PluralRules::getRules() const {
UnicodeString rules;
- if (mRules != NULL) {
+ if (mRules != nullptr) {
mRules->dumpRules(rules);
}
return rules;
}
-
-AndConstraint::AndConstraint() {
- op = AndConstraint::NONE;
- opNum=-1;
- value = -1;
- rangeList = NULL;
- negated = FALSE;
- integerOnly = FALSE;
- digitsType = none;
- next=NULL;
-}
-
-
AndConstraint::AndConstraint(const AndConstraint& other) {
+ this->fInternalStatus = other.fInternalStatus;
+ if (U_FAILURE(fInternalStatus)) {
+ return; // stop early if the object we are copying from is invalid.
+ }
this->op = other.op;
this->opNum=other.opNum;
this->value=other.value;
- this->rangeList=NULL;
- if (other.rangeList != NULL) {
- UErrorCode status = U_ZERO_ERROR;
- this->rangeList = new UVector32(status);
- this->rangeList->assign(*other.rangeList, status);
+ if (other.rangeList != nullptr) {
+ LocalPointer<UVector32> newRangeList(new UVector32(fInternalStatus), fInternalStatus);
+ if (U_FAILURE(fInternalStatus)) {
+ return;
+ }
+ this->rangeList = newRangeList.orphan();
+ this->rangeList->assign(*other.rangeList, fInternalStatus);
}
this->integerOnly=other.integerOnly;
this->negated=other.negated;
this->digitsType = other.digitsType;
- if (other.next==NULL) {
- this->next=NULL;
- }
- else {
+ if (other.next != nullptr) {
this->next = new AndConstraint(*other.next);
+ if (this->next == nullptr) {
+ fInternalStatus = U_MEMORY_ALLOCATION_ERROR;
+ }
}
}
AndConstraint::~AndConstraint() {
delete rangeList;
- if (next!=NULL) {
- delete next;
- }
+ rangeList = nullptr;
+ delete next;
+ next = nullptr;
}
-
UBool
AndConstraint::isFulfilled(const IFixedDecimal &number) {
UBool result = TRUE;
@@ -776,7 +809,7 @@ AndConstraint::isFulfilled(const IFixedDecimal &number) {
if (op == MOD) {
n = fmod(n, opNum);
}
- if (rangeList == NULL) {
+ if (rangeList == nullptr) {
result = value == -1 || // empty rule
n == value; // 'is' rule
break;
@@ -796,53 +829,67 @@ AndConstraint::isFulfilled(const IFixedDecimal &number) {
return result;
}
-
AndConstraint*
-AndConstraint::add()
-{
+AndConstraint::add(UErrorCode& status) {
+ if (U_FAILURE(fInternalStatus)) {
+ status = fInternalStatus;
+ return nullptr;
+ }
this->next = new AndConstraint();
+ if (this->next == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
return this->next;
}
-OrConstraint::OrConstraint() {
- childNode=NULL;
- next=NULL;
-}
OrConstraint::OrConstraint(const OrConstraint& other) {
- if ( other.childNode == NULL ) {
- this->childNode = NULL;
+ this->fInternalStatus = other.fInternalStatus;
+ if (U_FAILURE(fInternalStatus)) {
+ return; // stop early if the object we are copying from is invalid.
}
- else {
+ if ( other.childNode != nullptr ) {
this->childNode = new AndConstraint(*(other.childNode));
+ if (this->childNode == nullptr) {
+ fInternalStatus = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
}
- if (other.next == NULL ) {
- this->next = NULL;
- }
- else {
+ if (other.next != nullptr ) {
this->next = new OrConstraint(*(other.next));
+ if (this->next == nullptr) {
+ fInternalStatus = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ if (U_FAILURE(this->next->fInternalStatus)) {
+ this->fInternalStatus = this->next->fInternalStatus;
+ }
}
}
OrConstraint::~OrConstraint() {
- if (childNode!=NULL) {
- delete childNode;
- }
- if (next!=NULL) {
- delete next;
- }
+ delete childNode;
+ childNode = nullptr;
+ delete next;
+ next = nullptr;
}
AndConstraint*
-OrConstraint::add()
-{
+OrConstraint::add(UErrorCode& status) {
+ if (U_FAILURE(fInternalStatus)) {
+ status = fInternalStatus;
+ return nullptr;
+ }
OrConstraint *curOrConstraint=this;
{
- while (curOrConstraint->next!=NULL) {
+ while (curOrConstraint->next!=nullptr) {
curOrConstraint = curOrConstraint->next;
}
- U_ASSERT(curOrConstraint->childNode == NULL);
+ U_ASSERT(curOrConstraint->childNode == nullptr);
curOrConstraint->childNode = new AndConstraint();
+ if (curOrConstraint->childNode == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
}
return curOrConstraint->childNode;
}
@@ -852,10 +899,10 @@ OrConstraint::isFulfilled(const IFixedDecimal &number) {
OrConstraint* orRule=this;
UBool result=FALSE;
- while (orRule!=NULL && !result) {
+ while (orRule!=nullptr && !result) {
result=TRUE;
AndConstraint* andRule = orRule->childNode;
- while (andRule!=NULL && result) {
+ while (andRule!=nullptr && result) {
result = andRule->isFulfilled(number);
andRule=andRule->next;
}
@@ -866,19 +913,33 @@ OrConstraint::isFulfilled(const IFixedDecimal &number) {
}
-RuleChain::RuleChain(): fKeyword(), fNext(NULL), ruleHeader(NULL), fDecimalSamples(), fIntegerSamples(),
- fDecimalSamplesUnbounded(FALSE), fIntegerSamplesUnbounded(FALSE) {
-}
-
RuleChain::RuleChain(const RuleChain& other) :
- fKeyword(other.fKeyword), fNext(NULL), ruleHeader(NULL), fDecimalSamples(other.fDecimalSamples),
+ fKeyword(other.fKeyword), fDecimalSamples(other.fDecimalSamples),
fIntegerSamples(other.fIntegerSamples), fDecimalSamplesUnbounded(other.fDecimalSamplesUnbounded),
- fIntegerSamplesUnbounded(other.fIntegerSamplesUnbounded) {
- if (other.ruleHeader != NULL) {
+ fIntegerSamplesUnbounded(other.fIntegerSamplesUnbounded), fInternalStatus(other.fInternalStatus) {
+ if (U_FAILURE(this->fInternalStatus)) {
+ return; // stop early if the object we are copying from is invalid.
+ }
+ if (other.ruleHeader != nullptr) {
this->ruleHeader = new OrConstraint(*(other.ruleHeader));
+ if (this->ruleHeader == nullptr) {
+ this->fInternalStatus = U_MEMORY_ALLOCATION_ERROR;
+ }
+ else if (U_FAILURE(this->ruleHeader->fInternalStatus)) {
+ // If the OrConstraint wasn't fully copied, then set our status to failure as well.
+ this->fInternalStatus = this->ruleHeader->fInternalStatus;
+ return; // exit early.
+ }
}
- if (other.fNext != NULL ) {
+ if (other.fNext != nullptr ) {
this->fNext = new RuleChain(*other.fNext);
+ if (this->fNext == nullptr) {
+ this->fInternalStatus = U_MEMORY_ALLOCATION_ERROR;
+ }
+ else if (U_FAILURE(this->fNext->fInternalStatus)) {
+ // If the RuleChain wasn't fully copied, then set our status to failure as well.
+ this->fInternalStatus = this->fNext->fInternalStatus;
+ }
}
}
@@ -887,11 +948,10 @@ RuleChain::~RuleChain() {
delete ruleHeader;
}
-
UnicodeString
RuleChain::select(const IFixedDecimal &number) const {
if (!number.isNaN() && !number.isInfinite()) {
- for (const RuleChain *rules = this; rules != NULL; rules = rules->fNext) {
+ for (const RuleChain *rules = this; rules != nullptr; rules = rules->fNext) {
if (rules->ruleHeader->isFulfilled(number)) {
return rules->fKeyword;
}
@@ -923,17 +983,17 @@ void
RuleChain::dumpRules(UnicodeString& result) {
UChar digitString[16];
- if ( ruleHeader != NULL ) {
+ if ( ruleHeader != nullptr ) {
result += fKeyword;
result += COLON;
result += SPACE;
OrConstraint* orRule=ruleHeader;
- while ( orRule != NULL ) {
+ while ( orRule != nullptr ) {
AndConstraint* andRule=orRule->childNode;
- while ( andRule != NULL ) {
- if ((andRule->op==AndConstraint::NONE) && (andRule->rangeList==NULL) && (andRule->value == -1)) {
+ while ( andRule != nullptr ) {
+ if ((andRule->op==AndConstraint::NONE) && (andRule->rangeList==nullptr) && (andRule->value == -1)) {
// Empty Rules.
- } else if ( (andRule->op==AndConstraint::NONE) && (andRule->rangeList==NULL) ) {
+ } else if ( (andRule->op==AndConstraint::NONE) && (andRule->rangeList==nullptr) ) {
result += tokenString(andRule->digitsType);
result += UNICODE_STRING_SIMPLE(" is ");
if (andRule->negated) {
@@ -950,7 +1010,7 @@ RuleChain::dumpRules(UnicodeString& result) {
uprv_itou(digitString,16, andRule->opNum,10,0);
result += UnicodeString(digitString);
}
- if (andRule->rangeList==NULL) {
+ if (andRule->rangeList==nullptr) {
if (andRule->negated) {
result += UNICODE_STRING_SIMPLE(" is not ");
uprv_itou(digitString,16, andRule->value,10,0);
@@ -993,16 +1053,16 @@ RuleChain::dumpRules(UnicodeString& result) {
}
}
}
- if ( (andRule=andRule->next) != NULL) {
+ if ( (andRule=andRule->next) != nullptr) {
result += UNICODE_STRING_SIMPLE(" and ");
}
}
- if ( (orRule = orRule->next) != NULL ) {
+ if ( (orRule = orRule->next) != nullptr ) {
result += UNICODE_STRING_SIMPLE(" or ");
}
}
}
- if ( fNext != NULL ) {
+ if ( fNext != nullptr ) {
result += UNICODE_STRING_SIMPLE("; ");
fNext->dumpRules(result);
}
@@ -1011,6 +1071,9 @@ RuleChain::dumpRules(UnicodeString& result) {
UErrorCode
RuleChain::getKeywords(int32_t capacityOfKeywords, UnicodeString* keywords, int32_t& arraySize) const {
+ if (U_FAILURE(fInternalStatus)) {
+ return fInternalStatus;
+ }
if ( arraySize < capacityOfKeywords-1 ) {
keywords[arraySize++]=fKeyword;
}
@@ -1018,7 +1081,7 @@ RuleChain::getKeywords(int32_t capacityOfKeywords, UnicodeString* keywords, int3
return U_BUFFER_OVERFLOW_ERROR;
}
- if ( fNext != NULL ) {
+ if ( fNext != nullptr ) {
return fNext->getKeywords(capacityOfKeywords, keywords, arraySize);
}
else {
@@ -1032,7 +1095,7 @@ RuleChain::isKeyword(const UnicodeString& keywordParam) const {
return TRUE;
}
- if ( fNext != NULL ) {
+ if ( fNext != nullptr ) {
return fNext->isKeyword(keywordParam);
}
else {
@@ -1043,7 +1106,7 @@ RuleChain::isKeyword(const UnicodeString& keywordParam) const {
PluralRuleParser::PluralRuleParser() :
ruleIndex(0), token(), type(none), prevType(none),
- curAndConstraint(NULL), currentChain(NULL), rangeLowIdx(-1), rangeHiIdx(-1)
+ curAndConstraint(nullptr), currentChain(nullptr), rangeLowIdx(-1), rangeHiIdx(-1)
{
}
@@ -1341,21 +1404,36 @@ PluralKeywordEnumeration::PluralKeywordEnumeration(RuleChain *header, UErrorCode
return;
}
fKeywordNames.setDeleter(uprv_deleteUObject);
- UBool addKeywordOther=TRUE;
- RuleChain *node=header;
- while(node!=NULL) {
- fKeywordNames.addElement(new UnicodeString(node->fKeyword), status);
+ UBool addKeywordOther = TRUE;
+ RuleChain *node = header;
+ while (node != nullptr) {
+ auto newElem = new UnicodeString(node->fKeyword);
+ if (newElem == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ fKeywordNames.addElement(newElem, status);
if (U_FAILURE(status)) {
+ delete newElem;
return;
}
if (0 == node->fKeyword.compare(PLURAL_KEYWORD_OTHER, 5)) {
- addKeywordOther= FALSE;
+ addKeywordOther = FALSE;
}
- node=node->fNext;
+ node = node->fNext;
}
if (addKeywordOther) {
- fKeywordNames.addElement(new UnicodeString(PLURAL_KEYWORD_OTHER), status);
+ auto newElem = new UnicodeString(PLURAL_KEYWORD_OTHER);
+ if (newElem == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ fKeywordNames.addElement(newElem, status);
+ if (U_FAILURE(status)) {
+ delete newElem;
+ return;
+ }
}
}
@@ -1364,7 +1442,7 @@ PluralKeywordEnumeration::snext(UErrorCode& status) {
if (U_SUCCESS(status) && pos < fKeywordNames.size()) {
return (const UnicodeString*)fKeywordNames.elementAt(pos++);
}
- return NULL;
+ return nullptr;
}
void
@@ -1374,7 +1452,7 @@ PluralKeywordEnumeration::reset(UErrorCode& /*status*/) {
int32_t
PluralKeywordEnumeration::count(UErrorCode& /*status*/) const {
- return fKeywordNames.size();
+ return fKeywordNames.size();
}
PluralKeywordEnumeration::~PluralKeywordEnumeration() {
@@ -1634,41 +1712,39 @@ int32_t FixedDecimal::getVisibleFractionDigitCount() const {
PluralAvailableLocalesEnumeration::PluralAvailableLocalesEnumeration(UErrorCode &status) {
- fLocales = NULL;
- fRes = NULL;
fOpenStatus = status;
if (U_FAILURE(status)) {
return;
}
- fOpenStatus = U_ZERO_ERROR;
- LocalUResourceBundlePointer rb(ures_openDirect(NULL, "plurals", &fOpenStatus));
- fLocales = ures_getByKey(rb.getAlias(), "locales", NULL, &fOpenStatus);
+ fOpenStatus = U_ZERO_ERROR; // clear any warnings.
+ LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "plurals", &fOpenStatus));
+ fLocales = ures_getByKey(rb.getAlias(), "locales", nullptr, &fOpenStatus);
}
PluralAvailableLocalesEnumeration::~PluralAvailableLocalesEnumeration() {
ures_close(fLocales);
ures_close(fRes);
- fLocales = NULL;
- fRes = NULL;
+ fLocales = nullptr;
+ fRes = nullptr;
}
const char *PluralAvailableLocalesEnumeration::next(int32_t *resultLength, UErrorCode &status) {
if (U_FAILURE(status)) {
- return NULL;
+ return nullptr;
}
if (U_FAILURE(fOpenStatus)) {
status = fOpenStatus;
- return NULL;
+ return nullptr;
}
fRes = ures_getNextResource(fLocales, fRes, &status);
- if (fRes == NULL || U_FAILURE(status)) {
+ if (fRes == nullptr || U_FAILURE(status)) {
if (status == U_INDEX_OUTOFBOUNDS_ERROR) {
status = U_ZERO_ERROR;
}
- return NULL;
+ return nullptr;
}
const char *result = ures_getKey(fRes);
- if (resultLength != NULL) {
+ if (resultLength != nullptr) {
*resultLength = static_cast<int32_t>(uprv_strlen(result));
}
return result;
diff --git a/deps/icu-small/source/i18n/plurrule_impl.h b/deps/icu-small/source/i18n/plurrule_impl.h
index 3ab445d584..f23ae16856 100644
--- a/deps/icu-small/source/i18n/plurrule_impl.h
+++ b/deps/icu-small/source/i18n/plurrule_impl.h
@@ -181,7 +181,6 @@ private:
kRangeList,
kSamples
};
-
};
enum PluralOperand {
@@ -311,32 +310,36 @@ public:
NONE,
MOD
} RuleOp;
- RuleOp op;
- int32_t opNum; // for mod expressions, the right operand of the mod.
- int32_t value; // valid for 'is' rules only.
- UVector32 *rangeList; // for 'in', 'within' rules. Null otherwise.
- UBool negated; // TRUE for negated rules.
- UBool integerOnly; // TRUE for 'within' rules.
- tokenType digitsType; // n | i | v | f constraint.
- AndConstraint *next;
-
- AndConstraint();
+ RuleOp op = AndConstraint::NONE;
+ int32_t opNum = -1; // for mod expressions, the right operand of the mod.
+ int32_t value = -1; // valid for 'is' rules only.
+ UVector32 *rangeList = nullptr; // for 'in', 'within' rules. Null otherwise.
+ UBool negated = FALSE; // TRUE for negated rules.
+ UBool integerOnly = FALSE; // TRUE for 'within' rules.
+ tokenType digitsType = none; // n | i | v | f constraint.
+ AndConstraint *next = nullptr;
+ // Internal error status, used for errors that occur during the copy constructor.
+ UErrorCode fInternalStatus = U_ZERO_ERROR;
+
+ AndConstraint() = default;
AndConstraint(const AndConstraint& other);
virtual ~AndConstraint();
- AndConstraint* add();
+ AndConstraint* add(UErrorCode& status);
// UBool isFulfilled(double number);
UBool isFulfilled(const IFixedDecimal &number);
};
class OrConstraint : public UMemory {
public:
- AndConstraint *childNode;
- OrConstraint *next;
- OrConstraint();
+ AndConstraint *childNode = nullptr;
+ OrConstraint *next = nullptr;
+ // Internal error status, used for errors that occur during the copy constructor.
+ UErrorCode fInternalStatus = U_ZERO_ERROR;
+ OrConstraint() = default;
OrConstraint(const OrConstraint& other);
virtual ~OrConstraint();
- AndConstraint* add();
+ AndConstraint* add(UErrorCode& status);
// UBool isFulfilled(double number);
UBool isFulfilled(const IFixedDecimal &number);
};
@@ -344,15 +347,16 @@ public:
class RuleChain : public UMemory {
public:
UnicodeString fKeyword;
- RuleChain *fNext;
- OrConstraint *ruleHeader;
+ RuleChain *fNext = nullptr;
+ OrConstraint *ruleHeader = nullptr;
UnicodeString fDecimalSamples; // Samples strings from rule source
UnicodeString fIntegerSamples; // without @decimal or @integer, otherwise unprocessed.
- UBool fDecimalSamplesUnbounded;
- UBool fIntegerSamplesUnbounded;
-
+ UBool fDecimalSamplesUnbounded = FALSE;
+ UBool fIntegerSamplesUnbounded = FALSE;
+ // Internal error status, used for errors that occur during the copy constructor.
+ UErrorCode fInternalStatus = U_ZERO_ERROR;
- RuleChain();
+ RuleChain() = default;
RuleChain(const RuleChain& other);
virtual ~RuleChain();
@@ -386,8 +390,8 @@ class U_I18N_API PluralAvailableLocalesEnumeration: public StringEnumeration {
virtual int32_t count(UErrorCode& status) const;
private:
UErrorCode fOpenStatus;
- UResourceBundle *fLocales;
- UResourceBundle *fRes;
+ UResourceBundle *fLocales = nullptr;
+ UResourceBundle *fRes = nullptr;
};
U_NAMESPACE_END
diff --git a/deps/icu-small/source/i18n/rbnf.cpp b/deps/icu-small/source/i18n/rbnf.cpp
index ab9ad15e8c..74707ccd22 100644
--- a/deps/icu-small/source/i18n/rbnf.cpp
+++ b/deps/icu-small/source/i18n/rbnf.cpp
@@ -680,7 +680,7 @@ StringLocalizationInfo::getDisplayName(int32_t localeIndex, int32_t ruleIndex) c
RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
const UnicodeString& locs,
const Locale& alocale, UParseError& perror, UErrorCode& status)
- : ruleSets(NULL)
+ : fRuleSets(NULL)
, ruleSetDescriptions(NULL)
, numRuleSets(0)
, defaultRuleSet(NULL)
@@ -689,7 +689,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
, decimalFormatSymbols(NULL)
, defaultInfinityRule(NULL)
, defaultNaNRule(NULL)
- , roundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
+ , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
@@ -705,7 +705,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
const UnicodeString& locs,
UParseError& perror, UErrorCode& status)
- : ruleSets(NULL)
+ : fRuleSets(NULL)
, ruleSetDescriptions(NULL)
, numRuleSets(0)
, defaultRuleSet(NULL)
@@ -714,7 +714,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
, decimalFormatSymbols(NULL)
, defaultInfinityRule(NULL)
, defaultNaNRule(NULL)
- , roundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
+ , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
@@ -730,7 +730,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
LocalizationInfo* info,
const Locale& alocale, UParseError& perror, UErrorCode& status)
- : ruleSets(NULL)
+ : fRuleSets(NULL)
, ruleSetDescriptions(NULL)
, numRuleSets(0)
, defaultRuleSet(NULL)
@@ -739,7 +739,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
, decimalFormatSymbols(NULL)
, defaultInfinityRule(NULL)
, defaultNaNRule(NULL)
- , roundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
+ , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
@@ -754,7 +754,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
UParseError& perror,
UErrorCode& status)
- : ruleSets(NULL)
+ : fRuleSets(NULL)
, ruleSetDescriptions(NULL)
, numRuleSets(0)
, defaultRuleSet(NULL)
@@ -763,7 +763,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
, decimalFormatSymbols(NULL)
, defaultInfinityRule(NULL)
, defaultNaNRule(NULL)
- , roundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
+ , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
@@ -779,7 +779,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
const Locale& aLocale,
UParseError& perror,
UErrorCode& status)
- : ruleSets(NULL)
+ : fRuleSets(NULL)
, ruleSetDescriptions(NULL)
, numRuleSets(0)
, defaultRuleSet(NULL)
@@ -788,7 +788,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
, decimalFormatSymbols(NULL)
, defaultInfinityRule(NULL)
, defaultNaNRule(NULL)
- , roundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
+ , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
@@ -801,7 +801,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
}
RuleBasedNumberFormat::RuleBasedNumberFormat(URBNFRuleSetTag tag, const Locale& alocale, UErrorCode& status)
- : ruleSets(NULL)
+ : fRuleSets(NULL)
, ruleSetDescriptions(NULL)
, numRuleSets(0)
, defaultRuleSet(NULL)
@@ -810,7 +810,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(URBNFRuleSetTag tag, const Locale&
, decimalFormatSymbols(NULL)
, defaultInfinityRule(NULL)
, defaultNaNRule(NULL)
- , roundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
+ , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
@@ -868,7 +868,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(URBNFRuleSetTag tag, const Locale&
RuleBasedNumberFormat::RuleBasedNumberFormat(const RuleBasedNumberFormat& rhs)
: NumberFormat(rhs)
- , ruleSets(NULL)
+ , fRuleSets(NULL)
, ruleSetDescriptions(NULL)
, numRuleSets(0)
, defaultRuleSet(NULL)
@@ -877,7 +877,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const RuleBasedNumberFormat& rhs)
, decimalFormatSymbols(NULL)
, defaultInfinityRule(NULL)
, defaultNaNRule(NULL)
- , roundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
+ , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
@@ -950,8 +950,8 @@ RuleBasedNumberFormat::operator==(const Format& other) const
? FALSE
: *localizations == rhs.localizations))) {
- NFRuleSet** p = ruleSets;
- NFRuleSet** q = rhs.ruleSets;
+ NFRuleSet** p = fRuleSets;
+ NFRuleSet** q = rhs.fRuleSets;
if (p == NULL) {
return q == NULL;
} else if (q == NULL) {
@@ -972,8 +972,8 @@ UnicodeString
RuleBasedNumberFormat::getRules() const
{
UnicodeString result;
- if (ruleSets != NULL) {
- for (NFRuleSet** p = ruleSets; *p; ++p) {
+ if (fRuleSets != NULL) {
+ for (NFRuleSet** p = fRuleSets; *p; ++p) {
(*p)->appendRules(result);
}
}
@@ -987,9 +987,9 @@ RuleBasedNumberFormat::getRuleSetName(int32_t index) const
UnicodeString string(TRUE, localizations->getRuleSetName(index), (int32_t)-1);
return string;
}
- else if (ruleSets) {
+ else if (fRuleSets) {
UnicodeString result;
- for (NFRuleSet** p = ruleSets; *p; ++p) {
+ for (NFRuleSet** p = fRuleSets; *p; ++p) {
NFRuleSet* rs = *p;
if (rs->isPublic()) {
if (--index == -1) {
@@ -1010,8 +1010,8 @@ RuleBasedNumberFormat::getNumberOfRuleSetNames() const
if (localizations) {
result = localizations->getNumberOfRuleSets();
}
- else if (ruleSets) {
- for (NFRuleSet** p = ruleSets; *p; ++p) {
+ else if (fRuleSets) {
+ for (NFRuleSet** p = fRuleSets; *p; ++p) {
if ((**p).isPublic()) {
++result;
}
@@ -1098,8 +1098,8 @@ RuleBasedNumberFormat::getRuleSetDisplayName(const UnicodeString& ruleSetName, c
NFRuleSet*
RuleBasedNumberFormat::findRuleSet(const UnicodeString& name, UErrorCode& status) const
{
- if (U_SUCCESS(status) && ruleSets) {
- for (NFRuleSet** p = ruleSets; *p; ++p) {
+ if (U_SUCCESS(status) && fRuleSets) {
+ for (NFRuleSet** p = fRuleSets; *p; ++p) {
NFRuleSet* rs = *p;
if (rs->isNamed(name)) {
return rs;
@@ -1132,11 +1132,17 @@ RuleBasedNumberFormat::format(const DecimalQuantity &number,
// The DecimalFormat will provide more accurate results.
// TODO this section should probably be optimized. The DecimalFormat is shared in ICU4J.
- NumberFormat *decimalFormat = NumberFormat::createInstance(locale, UNUM_DECIMAL, status);
+ LocalPointer<NumberFormat> decimalFormat(NumberFormat::createInstance(locale, UNUM_DECIMAL, status), status);
+ if (decimalFormat.isNull()) {
+ return appendTo;
+ }
Formattable f;
- f.adoptDecimalQuantity(new DecimalQuantity(number));
+ LocalPointer<DecimalQuantity> decimalQuantity(new DecimalQuantity(number), status);
+ if (decimalQuantity.isNull()) {
+ return appendTo;
+ }
+ f.adoptDecimalQuantity(decimalQuantity.orphan()); // f now owns decimalQuantity.
decimalFormat->format(f, appendTo, posIter, status);
- delete decimalFormat;
}
}
return appendTo;
@@ -1165,11 +1171,17 @@ RuleBasedNumberFormat::format(const DecimalQuantity &number,
// The DecimalFormat will provide more accurate results.
// TODO this section should probably be optimized. The DecimalFormat is shared in ICU4J.
- NumberFormat *decimalFormat = NumberFormat::createInstance(locale, UNUM_DECIMAL, status);
+ LocalPointer<NumberFormat> decimalFormat(NumberFormat::createInstance(locale, UNUM_DECIMAL, status), status);
+ if (decimalFormat.isNull()) {
+ return appendTo;
+ }
Formattable f;
- f.adoptDecimalQuantity(new DecimalQuantity(number));
+ LocalPointer<DecimalQuantity> decimalQuantity(new DecimalQuantity(number), status);
+ if (decimalQuantity.isNull()) {
+ return appendTo;
+ }
+ f.adoptDecimalQuantity(decimalQuantity.orphan()); // f now owns decimalQuantity.
decimalFormat->format(f, appendTo, pos, status);
- delete decimalFormat;
}
}
return appendTo;
@@ -1312,11 +1324,19 @@ RuleBasedNumberFormat::format(int64_t number, NFRuleSet *ruleSet, UnicodeString&
// TODO this section should probably be optimized. The DecimalFormat is shared in ICU4J.
NumberFormat *decimalFormat = NumberFormat::createInstance(locale, UNUM_DECIMAL, status);
+ if (decimalFormat == nullptr) {
+ return toAppendTo;
+ }
Formattable f;
FieldPosition pos(FieldPosition::DONT_CARE);
- DecimalQuantity *digitList = new DecimalQuantity();
- digitList->setToLong(number);
- f.adoptDecimalQuantity(digitList);
+ DecimalQuantity *decimalQuantity = new DecimalQuantity();
+ if (decimalQuantity == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ delete decimalFormat;
+ return toAppendTo;
+ }
+ decimalQuantity->setToLong(number);
+ f.adoptDecimalQuantity(decimalQuantity); // f now owns decimalQuantity.
decimalFormat->format(f, toAppendTo, pos, status);
delete decimalFormat;
}
@@ -1358,7 +1378,7 @@ RuleBasedNumberFormat::parse(const UnicodeString& text,
Formattable& result,
ParsePosition& parsePosition) const
{
- if (!ruleSets) {
+ if (!fRuleSets) {
parsePosition.setErrorIndex(0);
return;
}
@@ -1369,7 +1389,7 @@ RuleBasedNumberFormat::parse(const UnicodeString& text,
ParsePosition high_pp(0);
Formattable high_result;
- for (NFRuleSet** p = ruleSets; *p; ++p) {
+ for (NFRuleSet** p = fRuleSets; *p; ++p) {
NFRuleSet *rp = *p;
if (rp->isPublic() && rp->isParseable()) {
ParsePosition working_pp(0);
@@ -1457,7 +1477,7 @@ void
RuleBasedNumberFormat::initDefaultRuleSet()
{
defaultRuleSet = NULL;
- if (!ruleSets) {
+ if (!fRuleSets) {
return;
}
@@ -1465,7 +1485,7 @@ RuleBasedNumberFormat::initDefaultRuleSet()
const UnicodeString ordinal(UNICODE_STRING_SIMPLE("%digits-ordinal"));
const UnicodeString duration(UNICODE_STRING_SIMPLE("%duration"));
- NFRuleSet**p = &ruleSets[0];
+ NFRuleSet**p = &fRuleSets[0];
while (*p) {
if ((*p)->isNamed(spellout) || (*p)->isNamed(ordinal) || (*p)->isNamed(duration)) {
defaultRuleSet = *p;
@@ -1477,7 +1497,7 @@ RuleBasedNumberFormat::initDefaultRuleSet()
defaultRuleSet = *--p;
if (!defaultRuleSet->isPublic()) {
- while (p != ruleSets) {
+ while (p != fRuleSets) {
if ((*--p)->isPublic()) {
defaultRuleSet = *p;
break;
@@ -1547,7 +1567,7 @@ RuleBasedNumberFormat::init(const UnicodeString& rules, LocalizationInfo* locali
// from the description
lenientParseRules = new UnicodeString();
/* test for NULL */
- if (lenientParseRules == 0) {
+ if (lenientParseRules == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
@@ -1568,15 +1588,15 @@ RuleBasedNumberFormat::init(const UnicodeString& rules, LocalizationInfo* locali
++numRuleSets;
// our rule list is an array of the appropriate size
- ruleSets = (NFRuleSet **)uprv_malloc((numRuleSets + 1) * sizeof(NFRuleSet *));
+ fRuleSets = (NFRuleSet **)uprv_malloc((numRuleSets + 1) * sizeof(NFRuleSet *));
/* test for NULL */
- if (ruleSets == 0) {
+ if (fRuleSets == 0) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
for (int i = 0; i <= numRuleSets; ++i) {
- ruleSets[i] = NULL;
+ fRuleSets[i] = NULL;
}
// divide up the descriptions into individual rule-set descriptions
@@ -1592,7 +1612,7 @@ RuleBasedNumberFormat::init(const UnicodeString& rules, LocalizationInfo* locali
}
ruleSetDescriptions = new UnicodeString[numRuleSets];
- if (ruleSetDescriptions == 0) {
+ if (ruleSetDescriptions == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
@@ -1602,8 +1622,8 @@ RuleBasedNumberFormat::init(const UnicodeString& rules, LocalizationInfo* locali
int32_t start = 0;
for (int32_t p = description.indexOf(gSemiPercent, 2, 0); p != -1; p = description.indexOf(gSemiPercent, 2, start)) {
ruleSetDescriptions[curRuleSet].setTo(description, start, p + 1 - start);
- ruleSets[curRuleSet] = new NFRuleSet(this, ruleSetDescriptions, curRuleSet, status);
- if (ruleSets[curRuleSet] == 0) {
+ fRuleSets[curRuleSet] = new NFRuleSet(this, ruleSetDescriptions, curRuleSet, status);
+ if (fRuleSets[curRuleSet] == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
@@ -1611,8 +1631,8 @@ RuleBasedNumberFormat::init(const UnicodeString& rules, LocalizationInfo* locali
start = p + 1;
}
ruleSetDescriptions[curRuleSet].setTo(description, start, description.length() - start);
- ruleSets[curRuleSet] = new NFRuleSet(this, ruleSetDescriptions, curRuleSet, status);
- if (ruleSets[curRuleSet] == 0) {
+ fRuleSets[curRuleSet] = new NFRuleSet(this, ruleSetDescriptions, curRuleSet, status);
+ if (fRuleSets[curRuleSet] == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
@@ -1630,11 +1650,11 @@ RuleBasedNumberFormat::init(const UnicodeString& rules, LocalizationInfo* locali
initDefaultRuleSet();
// finally, we can go back through the temporary descriptions
- // list and finish seting up the substructure (and we throw
+ // list and finish setting up the substructure (and we throw
// away the temporary descriptions as we go)
{
for (int i = 0; i < numRuleSets; i++) {
- ruleSets[i]->parseRules(ruleSetDescriptions[i], status);
+ fRuleSets[i]->parseRules(ruleSetDescriptions[i], status);
}
}
@@ -1680,7 +1700,7 @@ RuleBasedNumberFormat::setContext(UDisplayContext value, UErrorCode& status)
if ( capitalizationBrkIter == NULL && (value==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
(value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU && capitalizationForUIListMenu) ||
(value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE && capitalizationForStandAlone)) ) {
- UErrorCode status = U_ZERO_ERROR;
+ status = U_ZERO_ERROR;
capitalizationBrkIter = BreakIterator::createSentenceInstance(locale, status);
if (U_FAILURE(status)) {
delete capitalizationBrkIter;
@@ -1704,8 +1724,8 @@ RuleBasedNumberFormat::initCapitalizationContextInfo(const Locale& thelocale)
int32_t len = 0;
const int32_t * intVector = ures_getIntVector(rb, &len, &status);
if (U_SUCCESS(status) && intVector != NULL && len >= 2) {
- capitalizationForUIListMenu = intVector[0];
- capitalizationForStandAlone = intVector[1];
+ capitalizationForUIListMenu = static_cast<UBool>(intVector[0]);
+ capitalizationForStandAlone = static_cast<UBool>(intVector[1]);
}
}
ures_close(rb);
@@ -1740,7 +1760,7 @@ RuleBasedNumberFormat::stripWhitespace(UnicodeString& description)
start = p + 1;
}
- // when we get here, we've seeked off the end of the sring, and
+ // when we get here, we've seeked off the end of the string, and
// we terminate the loop (we continue until *start* is -1 rather
// than until *p* is -1, because otherwise we'd miss the last
// rule in the description)
@@ -1756,12 +1776,12 @@ RuleBasedNumberFormat::stripWhitespace(UnicodeString& description)
void
RuleBasedNumberFormat::dispose()
{
- if (ruleSets) {
- for (NFRuleSet** p = ruleSets; *p; ++p) {
+ if (fRuleSets) {
+ for (NFRuleSet** p = fRuleSets; *p; ++p) {
delete *p;
}
- uprv_free(ruleSets);
- ruleSets = NULL;
+ uprv_free(fRuleSets);
+ fRuleSets = NULL;
}
if (ruleSetDescriptions) {
@@ -1811,7 +1831,7 @@ const RuleBasedCollator*
RuleBasedNumberFormat::getCollator() const
{
#if !UCONFIG_NO_COLLATION
- if (!ruleSets) {
+ if (!fRuleSets) {
return NULL;
}
@@ -1820,7 +1840,7 @@ RuleBasedNumberFormat::getCollator() const
// create a default collator based on the formatter's locale,
// then pull out that collator's rules, append any additional
// rules specified in the description, and create a _new_
- // collator based on the combinaiton of those rules
+ // collator based on the combination of those rules
UErrorCode status = U_ZERO_ERROR;
@@ -1863,13 +1883,10 @@ RuleBasedNumberFormat::initializeDecimalFormatSymbols(UErrorCode &status)
// lazy-evaluate the DecimalFormatSymbols object. This object
// is shared by all DecimalFormat instances belonging to this
// formatter
- if (decimalFormatSymbols == NULL) {
- DecimalFormatSymbols* temp = new DecimalFormatSymbols(locale, status);
+ if (decimalFormatSymbols == nullptr) {
+ LocalPointer<DecimalFormatSymbols> temp(new DecimalFormatSymbols(locale, status), status);
if (U_SUCCESS(status)) {
- decimalFormatSymbols = temp;
- }
- else {
- delete temp;
+ decimalFormatSymbols = temp.orphan();
}
}
return decimalFormatSymbols;
@@ -1889,17 +1906,14 @@ NFRule*
RuleBasedNumberFormat::initializeDefaultInfinityRule(UErrorCode &status)
{
if (U_FAILURE(status)) {
- return NULL;
+ return nullptr;
}
if (defaultInfinityRule == NULL) {
UnicodeString rule(UNICODE_STRING_SIMPLE("Inf: "));
rule.append(getDecimalFormatSymbols()->getSymbol(DecimalFormatSymbols::kInfinitySymbol));
- NFRule* temp = new NFRule(this, rule, status);
+ LocalPointer<NFRule> temp(new NFRule(this, rule, status), status);
if (U_SUCCESS(status)) {
- defaultInfinityRule = temp;
- }
- else {
- delete temp;
+ defaultInfinityRule = temp.orphan();
}
}
return defaultInfinityRule;
@@ -1915,17 +1929,14 @@ NFRule*
RuleBasedNumberFormat::initializeDefaultNaNRule(UErrorCode &status)
{
if (U_FAILURE(status)) {
- return NULL;
+ return nullptr;
}
- if (defaultNaNRule == NULL) {
+ if (defaultNaNRule == nullptr) {
UnicodeString rule(UNICODE_STRING_SIMPLE("NaN: "));
rule.append(getDecimalFormatSymbols()->getSymbol(DecimalFormatSymbols::kNaNSymbol));
- NFRule* temp = new NFRule(this, rule, status);
+ LocalPointer<NFRule> temp(new NFRule(this, rule, status), status);
if (U_SUCCESS(status)) {
- defaultNaNRule = temp;
- }
- else {
- delete temp;
+ defaultNaNRule = temp.orphan();
}
}
return defaultNaNRule;
@@ -1963,15 +1974,15 @@ RuleBasedNumberFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols* symbolsTo
defaultNaNRule = NULL;
initializeDefaultNaNRule(status); // Reset with the new DecimalFormatSymbols
- if (ruleSets) {
+ if (fRuleSets) {
for (int32_t i = 0; i < numRuleSets; i++) {
- ruleSets[i]->setDecimalFormatSymbols(*symbolsToAdopt, status);
+ fRuleSets[i]->setDecimalFormatSymbols(*symbolsToAdopt, status);
}
}
}
}
-// Setting the symbols is equlivalent to adopting a newly created localized symbols.
+// Setting the symbols is equivalent to adopting a newly created localized symbols.
void
RuleBasedNumberFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbols)
{
@@ -1983,7 +1994,11 @@ RuleBasedNumberFormat::createPluralFormat(UPluralType pluralType,
const UnicodeString &pattern,
UErrorCode& status) const
{
- return new PluralFormat(locale, pluralType, pattern, status);
+ auto *pf = new PluralFormat(locale, pluralType, pattern, status);
+ if (pf == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return pf;
}
/**
@@ -1991,7 +2006,7 @@ RuleBasedNumberFormat::createPluralFormat(UPluralType pluralType,
* @return A rounding mode
*/
DecimalFormat::ERoundingMode RuleBasedNumberFormat::getRoundingMode() const {
- return roundingMode;
+ return fRoundingMode;
}
/**
@@ -2000,7 +2015,7 @@ DecimalFormat::ERoundingMode RuleBasedNumberFormat::getRoundingMode() const {
* @param roundingMode A rounding mode
*/
void RuleBasedNumberFormat::setRoundingMode(DecimalFormat::ERoundingMode roundingMode) {
- this->roundingMode = roundingMode;
+ fRoundingMode = roundingMode;
}
U_NAMESPACE_END
diff --git a/deps/icu-small/source/i18n/rbt.h b/deps/icu-small/source/i18n/rbt.h
index 005fb85384..a18452ab2e 100644
--- a/deps/icu-small/source/i18n/rbt.h
+++ b/deps/icu-small/source/i18n/rbt.h
@@ -29,261 +29,9 @@ class TransliterationRuleData;
/**
* <code>RuleBasedTransliterator</code> is a transliterator
- * that reads a set of rules in order to determine how to perform
- * translations. Rule sets are stored in resource bundles indexed by
- * name. Rules within a rule set are separated by semicolons (';').
- * To include a literal semicolon, prefix it with a backslash ('\').
- * Whitespace, as defined by <code>Character.isWhitespace()</code>,
- * is ignored. If the first non-blank character on a line is '#',
- * the entire line is ignored as a comment. </p>
- *
- * <p>Each set of rules consists of two groups, one forward, and one
- * reverse. This is a convention that is not enforced; rules for one
- * direction may be omitted, with the result that translations in
- * that direction will not modify the source text. In addition,
- * bidirectional forward-reverse rules may be specified for
- * symmetrical transformations.</p>
- *
- * <p><b>Rule syntax</b> </p>
- *
- * <p>Rule statements take one of the following forms: </p>
- *
- * <dl>
- * <dt><code>$alefmadda=\u0622;</code></dt>
- * <dd><strong>Variable definition.</strong> The name on the
- * left is assigned the text on the right. In this example,
- * after this statement, instances of the left hand name,
- * &quot;<code>$alefmadda</code>&quot;, will be replaced by
- * the Unicode character U+0622. Variable names must begin
- * with a letter and consist only of letters, digits, and
- * underscores. Case is significant. Duplicate names cause
- * an exception to be thrown, that is, variables cannot be
- * redefined. The right hand side may contain well-formed
- * text of any length, including no text at all (&quot;<code>$empty=;</code>&quot;).
- * The right hand side may contain embedded <code>UnicodeSet</code>
- * patterns, for example, &quot;<code>$softvowel=[eiyEIY]</code>&quot;.</dd>
- * <dd>&nbsp;</dd>
- * <dt><code>ai&gt;$alefmadda;</code></dt>
- * <dd><strong>Forward translation rule.</strong> This rule
- * states that the string on the left will be changed to the
- * string on the right when performing forward
- * transliteration.</dd>
- * <dt>&nbsp;</dt>
- * <dt><code>ai<$alefmadda;</code></dt>
- * <dd><strong>Reverse translation rule.</strong> This rule
- * states that the string on the right will be changed to
- * the string on the left when performing reverse
- * transliteration.</dd>
- * </dl>
- *
- * <dl>
- * <dt><code>ai<>$alefmadda;</code></dt>
- * <dd><strong>Bidirectional translation rule.</strong> This
- * rule states that the string on the right will be changed
- * to the string on the left when performing forward
- * transliteration, and vice versa when performing reverse
- * transliteration.</dd>
- * </dl>
- *
- * <p>Translation rules consist of a <em>match pattern</em> and an <em>output
- * string</em>. The match pattern consists of literal characters,
- * optionally preceded by context, and optionally followed by
- * context. Context characters, like literal pattern characters,
- * must be matched in the text being transliterated. However, unlike
- * literal pattern characters, they are not replaced by the output
- * text. For example, the pattern &quot;<code>abc{def}</code>&quot;
- * indicates the characters &quot;<code>def</code>&quot; must be
- * preceded by &quot;<code>abc</code>&quot; for a successful match.
- * If there is a successful match, &quot;<code>def</code>&quot; will
- * be replaced, but not &quot;<code>abc</code>&quot;. The final '<code>}</code>'
- * is optional, so &quot;<code>abc{def</code>&quot; is equivalent to
- * &quot;<code>abc{def}</code>&quot;. Another example is &quot;<code>{123}456</code>&quot;
- * (or &quot;<code>123}456</code>&quot;) in which the literal
- * pattern &quot;<code>123</code>&quot; must be followed by &quot;<code>456</code>&quot;.
- * </p>
- *
- * <p>The output string of a forward or reverse rule consists of
- * characters to replace the literal pattern characters. If the
- * output string contains the character '<code>|</code>', this is
- * taken to indicate the location of the <em>cursor</em> after
- * replacement. The cursor is the point in the text at which the
- * next replacement, if any, will be applied. The cursor is usually
- * placed within the replacement text; however, it can actually be
- * placed into the precending or following context by using the
- * special character '<code>@</code>'. Examples:</p>
- *
- * <blockquote>
- * <p><code>a {foo} z &gt; | @ bar; # foo -&gt; bar, move cursor
- * before a<br>
- * {foo} xyz &gt; bar @@|; #&nbsp;foo -&gt; bar, cursor between
- * y and z</code></p>
- * </blockquote>
- *
- * <p><b>UnicodeSet</b></p>
- *
- * <p><code>UnicodeSet</code> patterns may appear anywhere that
- * makes sense. They may appear in variable definitions.
- * Contrariwise, <code>UnicodeSet</code> patterns may themselves
- * contain variable references, such as &quot;<code>$a=[a-z];$not_a=[^$a]</code>&quot;,
- * or &quot;<code>$range=a-z;$ll=[$range]</code>&quot;.</p>
- *
- * <p><code>UnicodeSet</code> patterns may also be embedded directly
- * into rule strings. Thus, the following two rules are equivalent:</p>
- *
- * <blockquote>
- * <p><code>$vowel=[aeiou]; $vowel&gt;'*'; # One way to do this<br>
- * [aeiou]&gt;'*';
- * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#
- * Another way</code></p>
- * </blockquote>
- *
- * <p>See {@link UnicodeSet} for more documentation and examples.</p>
- *
- * <p><b>Segments</b></p>
- *
- * <p>Segments of the input string can be matched and copied to the
- * output string. This makes certain sets of rules simpler and more
- * general, and makes reordering possible. For example:</p>
- *
- * <blockquote>
- * <p><code>([a-z]) &gt; $1 $1;
- * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#
- * double lowercase letters<br>
- * ([:Lu:]) ([:Ll:]) &gt; $2 $1; # reverse order of Lu-Ll pairs</code></p>
- * </blockquote>
- *
- * <p>The segment of the input string to be copied is delimited by
- * &quot;<code>(</code>&quot; and &quot;<code>)</code>&quot;. Up to
- * nine segments may be defined. Segments may not overlap. In the
- * output string, &quot;<code>$1</code>&quot; through &quot;<code>$9</code>&quot;
- * represent the input string segments, in left-to-right order of
- * definition.</p>
- *
- * <p><b>Anchors</b></p>
- *
- * <p>Patterns can be anchored to the beginning or the end of the text. This is done with the
- * special characters '<code>^</code>' and '<code>$</code>'. For example:</p>
- *
- * <blockquote>
- * <p><code>^ a&nbsp;&nbsp; &gt; 'BEG_A'; &nbsp;&nbsp;# match 'a' at start of text<br>
- * &nbsp; a&nbsp;&nbsp; &gt; 'A';&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # match other instances
- * of 'a'<br>
- * &nbsp; z $ &gt; 'END_Z'; &nbsp;&nbsp;# match 'z' at end of text<br>
- * &nbsp; z&nbsp;&nbsp; &gt; 'Z';&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # match other instances
- * of 'z'</code></p>
- * </blockquote>
- *
- * <p>It is also possible to match the beginning or the end of the text using a <code>UnicodeSet</code>.
- * This is done by including a virtual anchor character '<code>$</code>' at the end of the
- * set pattern. Although this is usually the match chafacter for the end anchor, the set will
- * match either the beginning or the end of the text, depending on its placement. For
- * example:</p>
- *
- * <blockquote>
- * <p><code>$x = [a-z$]; &nbsp;&nbsp;# match 'a' through 'z' OR anchor<br>
- * $x 1&nbsp;&nbsp;&nbsp; &gt; 2;&nbsp;&nbsp; # match '1' after a-z or at the start<br>
- * &nbsp;&nbsp; 3 $x &gt; 4; &nbsp;&nbsp;# match '3' before a-z or at the end</code></p>
- * </blockquote>
- *
- * <p><b>Example</b> </p>
- *
- * <p>The following example rules illustrate many of the features of
- * the rule language. </p>
- *
- * <table border="0" cellpadding="4">
- * <tr>
- * <td valign="top">Rule 1.</td>
- * <td valign="top" nowrap><code>abc{def}&gt;x|y</code></td>
- * </tr>
- * <tr>
- * <td valign="top">Rule 2.</td>
- * <td valign="top" nowrap><code>xyz&gt;r</code></td>
- * </tr>
- * <tr>
- * <td valign="top">Rule 3.</td>
- * <td valign="top" nowrap><code>yz&gt;q</code></td>
- * </tr>
- * </table>
- *
- * <p>Applying these rules to the string &quot;<code>adefabcdefz</code>&quot;
- * yields the following results: </p>
- *
- * <table border="0" cellpadding="4">
- * <tr>
- * <td valign="top" nowrap><code>|adefabcdefz</code></td>
- * <td valign="top">Initial state, no rules match. Advance
- * cursor.</td>
- * </tr>
- * <tr>
- * <td valign="top" nowrap><code>a|defabcdefz</code></td>
- * <td valign="top">Still no match. Rule 1 does not match
- * because the preceding context is not present.</td>
- * </tr>
- * <tr>
- * <td valign="top" nowrap><code>ad|efabcdefz</code></td>
- * <td valign="top">Still no match. Keep advancing until
- * there is a match...</td>
- * </tr>
- * <tr>
- * <td valign="top" nowrap><code>ade|fabcdefz</code></td>
- * <td valign="top">...</td>
- * </tr>
- * <tr>
- * <td valign="top" nowrap><code>adef|abcdefz</code></td>
- * <td valign="top">...</td>
- * </tr>
- * <tr>
- * <td valign="top" nowrap><code>adefa|bcdefz</code></td>
- * <td valign="top">...</td>
- * </tr>
- * <tr>
- * <td valign="top" nowrap><code>adefab|cdefz</code></td>
- * <td valign="top">...</td>
- * </tr>
- * <tr>
- * <td valign="top" nowrap><code>adefabc|defz</code></td>
- * <td valign="top">Rule 1 matches; replace &quot;<code>def</code>&quot;
- * with &quot;<code>xy</code>&quot; and back up the cursor
- * to before the '<code>y</code>'.</td>
- * </tr>
- * <tr>
- * <td valign="top" nowrap><code>adefabcx|yz</code></td>
- * <td valign="top">Although &quot;<code>xyz</code>&quot; is
- * present, rule 2 does not match because the cursor is
- * before the '<code>y</code>', not before the '<code>x</code>'.
- * Rule 3 does match. Replace &quot;<code>yz</code>&quot;
- * with &quot;<code>q</code>&quot;.</td>
- * </tr>
- * <tr>
- * <td valign="top" nowrap><code>adefabcxq|</code></td>
- * <td valign="top">The cursor is at the end;
- * transliteration is complete.</td>
- * </tr>
- * </table>
- *
- * <p>The order of rules is significant. If multiple rules may match
- * at some point, the first matching rule is applied. </p>
- *
- * <p>Forward and reverse rules may have an empty output string.
- * Otherwise, an empty left or right hand side of any statement is a
- * syntax error. </p>
- *
- * <p>Single quotes are used to quote any character other than a
- * digit or letter. To specify a single quote itself, inside or
- * outside of quotes, use two single quotes in a row. For example,
- * the rule &quot;<code>'&gt;'&gt;o''clock</code>&quot; changes the
- * string &quot;<code>&gt;</code>&quot; to the string &quot;<code>o'clock</code>&quot;.
- * </p>
- *
- * <p><b>Notes</b> </p>
- *
- * <p>While a RuleBasedTransliterator is being built, it checks that
- * the rules are added in proper order. For example, if the rule
- * &quot;a&gt;x&quot; is followed by the rule &quot;ab&gt;y&quot;,
- * then the second rule will throw an exception. The reason is that
- * the second rule can never be triggered, since the first rule
- * always matches anything it matches. In other words, the first
- * rule <em>masks</em> the second rule. </p>
+ * built from a set of rules as defined for
+ * Transliterator::createFromRules().
+ * See the C++ class Transliterator documentation for the rule syntax.
*
* @author Alan Liu
* @internal Use transliterator factory methods instead since this class will be removed in that release.
diff --git a/deps/icu-small/source/i18n/rbt_pars.cpp b/deps/icu-small/source/i18n/rbt_pars.cpp
index 8e49a8473a..e07cc8b63a 100644
--- a/deps/icu-small/source/i18n/rbt_pars.cpp
+++ b/deps/icu-small/source/i18n/rbt_pars.cpp
@@ -194,9 +194,9 @@ const UnicodeFunctor* ParseData::lookupMatcher(UChar32 ch) const {
const UnicodeFunctor* set = NULL;
int32_t i = ch - data->variablesBase;
if (i >= 0 && i < variablesVector->size()) {
- int32_t i = ch - data->variablesBase;
- set = (i < variablesVector->size()) ?
- (UnicodeFunctor*) variablesVector->elementAt(i) : 0;
+ int32_t j = ch - data->variablesBase;
+ set = (j < variablesVector->size()) ?
+ (UnicodeFunctor*) variablesVector->elementAt(j) : 0;
}
return set;
}
@@ -1108,8 +1108,8 @@ void TransliteratorParser::parseRules(const UnicodeString& rule,
}
data->variableNames.removeAll();
- int32_t pos = UHASH_FIRST;
- const UHashElement* he = variableNames.nextElement(pos);
+ int32_t p = UHASH_FIRST;
+ const UHashElement* he = variableNames.nextElement(p);
while (he != NULL) {
UnicodeString* tempus = (UnicodeString*)(((UnicodeString*)(he->value.pointer))->clone());
if (tempus == NULL) {
@@ -1118,7 +1118,7 @@ void TransliteratorParser::parseRules(const UnicodeString& rule,
}
data->variableNames.put(*((UnicodeString*)(he->key.pointer)),
tempus, status);
- he = variableNames.nextElement(pos);
+ he = variableNames.nextElement(p);
}
}
variablesVector.removeAllElements(); // keeps them from getting deleted when we succeed
diff --git a/deps/icu-small/source/i18n/regexcmp.cpp b/deps/icu-small/source/i18n/regexcmp.cpp
index 410ff9513b..0c5fca6f67 100644
--- a/deps/icu-small/source/i18n/regexcmp.cpp
+++ b/deps/icu-small/source/i18n/regexcmp.cpp
@@ -28,6 +28,7 @@
#include "patternprops.h"
#include "putilimp.h"
#include "cmemory.h"
+#include "cstr.h"
#include "cstring.h"
#include "uvectr32.h"
#include "uvectr64.h"
@@ -3892,7 +3893,7 @@ void RegexCompile::stripNOPs() {
//
//------------------------------------------------------------------------------
void RegexCompile::error(UErrorCode e) {
- if (U_SUCCESS(*fStatus)) {
+ if (U_SUCCESS(*fStatus) || e == U_MEMORY_ALLOCATION_ERROR) {
*fStatus = e;
// Hmm. fParseErr (UParseError) line & offset fields are int32_t in public
// API (see common/unicode/parseerr.h), while fLineNum and fCharNum are
@@ -4370,209 +4371,209 @@ static inline void addIdentifierIgnorable(UnicodeSet *set, UErrorCode& ec) {
// Includes trying the Java "properties" that aren't supported as
// normal ICU UnicodeSet properties
//
-static const UChar posSetPrefix[] = {0x5b, 0x5c, 0x70, 0x7b, 0}; // "[\p{"
-static const UChar negSetPrefix[] = {0x5b, 0x5c, 0x50, 0x7b, 0}; // "[\P{"
UnicodeSet *RegexCompile::createSetForProperty(const UnicodeString &propName, UBool negated) {
- UnicodeString setExpr;
- UnicodeSet *set;
- uint32_t usetFlags = 0;
if (U_FAILURE(*fStatus)) {
- return NULL;
+ return nullptr;
}
+ LocalPointer<UnicodeSet> set;
+ UErrorCode status = U_ZERO_ERROR;
- //
- // First try the property as we received it
- //
- if (negated) {
- setExpr.append(negSetPrefix, -1);
- } else {
- setExpr.append(posSetPrefix, -1);
- }
- setExpr.append(propName);
- setExpr.append(chRBrace);
- setExpr.append(chRBracket);
- if (fModeFlags & UREGEX_CASE_INSENSITIVE) {
- usetFlags |= USET_CASE_INSENSITIVE;
- }
- set = new UnicodeSet(setExpr, usetFlags, NULL, *fStatus);
- if (U_SUCCESS(*fStatus)) {
- return set;
- }
- delete set;
- set = NULL;
-
- //
- // The property as it was didn't work.
-
- // Do [:word:]. It is not recognized as a property by UnicodeSet. "word" not standard POSIX
- // or standard Java, but many other regular expression packages do recognize it.
-
- if (propName.caseCompare(UNICODE_STRING_SIMPLE("word"), 0) == 0) {
- *fStatus = U_ZERO_ERROR;
- set = new UnicodeSet(*(fRXPat->fStaticSets[URX_ISWORD_SET]));
- if (set == NULL) {
- *fStatus = U_MEMORY_ALLOCATION_ERROR;
- return set;
+ do { // non-loop, exists to allow breaks from the block.
+ //
+ // First try the property as we received it
+ //
+ UnicodeString setExpr;
+ uint32_t usetFlags = 0;
+ setExpr.append(u"[\\p{", -1);
+ setExpr.append(propName);
+ setExpr.append(u"}]", -1);
+ if (fModeFlags & UREGEX_CASE_INSENSITIVE) {
+ usetFlags |= USET_CASE_INSENSITIVE;
}
- if (negated) {
- set->complement();
+ set.adoptInsteadAndCheckErrorCode(new UnicodeSet(setExpr, usetFlags, NULL, status), status);
+ if (U_SUCCESS(status) || status == U_MEMORY_ALLOCATION_ERROR) {
+ break;
}
- return set;
- }
+ //
+ // The incoming property wasn't directly recognized by ICU.
- // Do Java fixes -
- // InGreek -> InGreek or Coptic, that being the official Unicode name for that block.
- // InCombiningMarksforSymbols -> InCombiningDiacriticalMarksforSymbols.
- //
- // Note on Spaces: either "InCombiningMarksForSymbols" or "InCombining Marks for Symbols"
- // is accepted by Java. The property part of the name is compared
- // case-insenstively. The spaces must be exactly as shown, either
- // all there, or all omitted, with exactly one at each position
- // if they are present. From checking against JDK 1.6
- //
- // This code should be removed when ICU properties support the Java compatibility names
- // (ICU 4.0?)
- //
- UnicodeString mPropName = propName;
- if (mPropName.caseCompare(UNICODE_STRING_SIMPLE("InGreek"), 0) == 0) {
- mPropName = UNICODE_STRING_SIMPLE("InGreek and Coptic");
- }
- if (mPropName.caseCompare(UNICODE_STRING_SIMPLE("InCombining Marks for Symbols"), 0) == 0 ||
- mPropName.caseCompare(UNICODE_STRING_SIMPLE("InCombiningMarksforSymbols"), 0) == 0) {
- mPropName = UNICODE_STRING_SIMPLE("InCombining Diacritical Marks for Symbols");
- }
- else if (mPropName.compare(UNICODE_STRING_SIMPLE("all")) == 0) {
- mPropName = UNICODE_STRING_SIMPLE("javaValidCodePoint");
- }
+ // Check [:word:] and [:all:]. These are not recognized as a properties by ICU UnicodeSet.
+ // Java accepts 'word' with mixed case.
+ // Java accepts 'all' only in all lower case.
- // See if the property looks like a Java "InBlockName", which
- // we will recast as "Block=BlockName"
- //
- if (mPropName.startsWith(u"In", 2) && propName.length()>=3) {
- setExpr.truncate(4); // Leaves "[\p{", or "[\P{"
- setExpr.append(u"Block=", -1);
- setExpr.append(UnicodeString(mPropName, 2)); // Property with the leading "In" removed.
- setExpr.append(chRBrace);
- setExpr.append(chRBracket);
- *fStatus = U_ZERO_ERROR;
- set = new UnicodeSet(setExpr, usetFlags, NULL, *fStatus);
- if (U_SUCCESS(*fStatus)) {
- return set;
+ status = U_ZERO_ERROR;
+ if (propName.caseCompare(u"word", -1, 0) == 0) {
+ set.adoptInsteadAndCheckErrorCode(new UnicodeSet(*(fRXPat->fStaticSets[URX_ISWORD_SET])), status);
+ break;
+ }
+ if (propName.compare(u"all", -1) == 0) {
+ set.adoptInsteadAndCheckErrorCode(new UnicodeSet(0, 0x10ffff), status);
+ break;
}
- delete set;
- set = NULL;
- }
- if (propName.startsWith(UNICODE_STRING_SIMPLE("java")) ||
- propName.compare(UNICODE_STRING_SIMPLE("all")) == 0)
- {
- UErrorCode localStatus = U_ZERO_ERROR;
- //setExpr.remove();
- set = new UnicodeSet();
- //
- // Try the various Java specific properties.
- // These all begin with "java"
+
+ // Do Java InBlock expressions
//
- if (mPropName.compare(UNICODE_STRING_SIMPLE("javaDefined")) == 0) {
- addCategory(set, U_GC_CN_MASK, localStatus);
- set->complement();
- }
- else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaDigit")) == 0) {
- addCategory(set, U_GC_ND_MASK, localStatus);
- }
- else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaIdentifierIgnorable")) == 0) {
- addIdentifierIgnorable(set, localStatus);
- }
- else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaISOControl")) == 0) {
- set->add(0, 0x1F).add(0x7F, 0x9F);
- }
- else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaJavaIdentifierPart")) == 0) {
- addCategory(set, U_GC_L_MASK, localStatus);
- addCategory(set, U_GC_SC_MASK, localStatus);
- addCategory(set, U_GC_PC_MASK, localStatus);
- addCategory(set, U_GC_ND_MASK, localStatus);
- addCategory(set, U_GC_NL_MASK, localStatus);
- addCategory(set, U_GC_MC_MASK, localStatus);
- addCategory(set, U_GC_MN_MASK, localStatus);
- addIdentifierIgnorable(set, localStatus);
- }
- else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaJavaIdentifierStart")) == 0) {
- addCategory(set, U_GC_L_MASK, localStatus);
- addCategory(set, U_GC_NL_MASK, localStatus);
- addCategory(set, U_GC_SC_MASK, localStatus);
- addCategory(set, U_GC_PC_MASK, localStatus);
- }
- else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaLetter")) == 0) {
- addCategory(set, U_GC_L_MASK, localStatus);
- }
- else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaLetterOrDigit")) == 0) {
- addCategory(set, U_GC_L_MASK, localStatus);
- addCategory(set, U_GC_ND_MASK, localStatus);
- }
- else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaLowerCase")) == 0) {
- addCategory(set, U_GC_LL_MASK, localStatus);
- }
- else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaMirrored")) == 0) {
- set->applyIntPropertyValue(UCHAR_BIDI_MIRRORED, 1, localStatus);
- }
- else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaSpaceChar")) == 0) {
- addCategory(set, U_GC_Z_MASK, localStatus);
- }
- else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaSupplementaryCodePoint")) == 0) {
- set->add(0x10000, UnicodeSet::MAX_VALUE);
- }
- else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaTitleCase")) == 0) {
- addCategory(set, U_GC_LT_MASK, localStatus);
- }
- else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaUnicodeIdentifierStart")) == 0) {
- addCategory(set, U_GC_L_MASK, localStatus);
- addCategory(set, U_GC_NL_MASK, localStatus);
- }
- else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaUnicodeIdentifierPart")) == 0) {
- addCategory(set, U_GC_L_MASK, localStatus);
- addCategory(set, U_GC_PC_MASK, localStatus);
- addCategory(set, U_GC_ND_MASK, localStatus);
- addCategory(set, U_GC_NL_MASK, localStatus);
- addCategory(set, U_GC_MC_MASK, localStatus);
- addCategory(set, U_GC_MN_MASK, localStatus);
- addIdentifierIgnorable(set, localStatus);
- }
- else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaUpperCase")) == 0) {
- addCategory(set, U_GC_LU_MASK, localStatus);
- }
- else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaValidCodePoint")) == 0) {
- set->add(0, UnicodeSet::MAX_VALUE);
- }
- else if (mPropName.compare(UNICODE_STRING_SIMPLE("javaWhitespace")) == 0) {
- addCategory(set, U_GC_Z_MASK, localStatus);
- set->removeAll(UnicodeSet().add(0xa0).add(0x2007).add(0x202f));
- set->add(9, 0x0d).add(0x1c, 0x1f);
- }
- else if (mPropName.compare(UNICODE_STRING_SIMPLE("all")) == 0) {
- set->add(0, UnicodeSet::MAX_VALUE);
+ UnicodeString mPropName = propName;
+ if (mPropName.startsWith(u"In", 2) && mPropName.length() >= 3) {
+ status = U_ZERO_ERROR;
+ set.adoptInsteadAndCheckErrorCode(new UnicodeSet(), status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ UnicodeString blockName(mPropName, 2); // Property with the leading "In" removed.
+ set->applyPropertyAlias(UnicodeString(u"Block"), blockName, status);
+ break;
}
- if (U_SUCCESS(localStatus) && !set->isEmpty()) {
- *fStatus = U_ZERO_ERROR;
- if (usetFlags & USET_CASE_INSENSITIVE) {
+ // Check for the Java form "IsBooleanPropertyValue", which we will recast
+ // as "BooleanPropertyValue". The property value can be either a
+ // a General Category or a Script Name.
+
+ if (propName.startsWith(u"Is", 2) && propName.length()>=3) {
+ mPropName.remove(0, 2); // Strip the "Is"
+ if (mPropName.indexOf(u'=') >= 0) {
+ // Reject any "Is..." property expression containing an '=', that is,
+ // any non-binary property expression.
+ status = U_REGEX_PROPERTY_SYNTAX;
+ break;
+ }
+
+ if (mPropName.caseCompare(u"assigned", -1, 0) == 0) {
+ mPropName.setTo(u"unassigned", -1);
+ negated = !negated;
+ } else if (mPropName.caseCompare(u"TitleCase", -1, 0) == 0) {
+ mPropName.setTo(u"Titlecase_Letter", -1);
+ }
+
+ mPropName.insert(0, u"[\\p{", -1);
+ mPropName.append(u"}]", -1);
+ set.adoptInsteadAndCheckErrorCode(new UnicodeSet(mPropName, *fStatus), status);
+
+ if (U_SUCCESS(status) && !set->isEmpty() && (usetFlags & USET_CASE_INSENSITIVE)) {
set->closeOver(USET_CASE_INSENSITIVE);
}
- if (negated) {
+ break;
+
+ }
+
+ if (propName.startsWith(u"java", -1)) {
+ status = U_ZERO_ERROR;
+ set.adoptInsteadAndCheckErrorCode(new UnicodeSet(), status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ //
+ // Try the various Java specific properties.
+ // These all begin with "java"
+ //
+ if (propName.compare(u"javaDefined", -1) == 0) {
+ addCategory(set.getAlias(), U_GC_CN_MASK, status);
set->complement();
}
- return set;
+ else if (propName.compare(u"javaDigit", -1) == 0) {
+ addCategory(set.getAlias(), U_GC_ND_MASK, status);
+ }
+ else if (propName.compare(u"javaIdentifierIgnorable", -1) == 0) {
+ addIdentifierIgnorable(set.getAlias(), status);
+ }
+ else if (propName.compare(u"javaISOControl", -1) == 0) {
+ set->add(0, 0x1F).add(0x7F, 0x9F);
+ }
+ else if (propName.compare(u"javaJavaIdentifierPart", -1) == 0) {
+ addCategory(set.getAlias(), U_GC_L_MASK, status);
+ addCategory(set.getAlias(), U_GC_SC_MASK, status);
+ addCategory(set.getAlias(), U_GC_PC_MASK, status);
+ addCategory(set.getAlias(), U_GC_ND_MASK, status);
+ addCategory(set.getAlias(), U_GC_NL_MASK, status);
+ addCategory(set.getAlias(), U_GC_MC_MASK, status);
+ addCategory(set.getAlias(), U_GC_MN_MASK, status);
+ addIdentifierIgnorable(set.getAlias(), status);
+ }
+ else if (propName.compare(u"javaJavaIdentifierStart", -1) == 0) {
+ addCategory(set.getAlias(), U_GC_L_MASK, status);
+ addCategory(set.getAlias(), U_GC_NL_MASK, status);
+ addCategory(set.getAlias(), U_GC_SC_MASK, status);
+ addCategory(set.getAlias(), U_GC_PC_MASK, status);
+ }
+ else if (propName.compare(u"javaLetter", -1) == 0) {
+ addCategory(set.getAlias(), U_GC_L_MASK, status);
+ }
+ else if (propName.compare(u"javaLetterOrDigit", -1) == 0) {
+ addCategory(set.getAlias(), U_GC_L_MASK, status);
+ addCategory(set.getAlias(), U_GC_ND_MASK, status);
+ }
+ else if (propName.compare(u"javaLowerCase", -1) == 0) {
+ addCategory(set.getAlias(), U_GC_LL_MASK, status);
+ }
+ else if (propName.compare(u"javaMirrored", -1) == 0) {
+ set->applyIntPropertyValue(UCHAR_BIDI_MIRRORED, 1, status);
+ }
+ else if (propName.compare(u"javaSpaceChar", -1) == 0) {
+ addCategory(set.getAlias(), U_GC_Z_MASK, status);
+ }
+ else if (propName.compare(u"javaSupplementaryCodePoint", -1) == 0) {
+ set->add(0x10000, UnicodeSet::MAX_VALUE);
+ }
+ else if (propName.compare(u"javaTitleCase", -1) == 0) {
+ addCategory(set.getAlias(), U_GC_LT_MASK, status);
+ }
+ else if (propName.compare(u"javaUnicodeIdentifierStart", -1) == 0) {
+ addCategory(set.getAlias(), U_GC_L_MASK, status);
+ addCategory(set.getAlias(), U_GC_NL_MASK, status);
+ }
+ else if (propName.compare(u"javaUnicodeIdentifierPart", -1) == 0) {
+ addCategory(set.getAlias(), U_GC_L_MASK, status);
+ addCategory(set.getAlias(), U_GC_PC_MASK, status);
+ addCategory(set.getAlias(), U_GC_ND_MASK, status);
+ addCategory(set.getAlias(), U_GC_NL_MASK, status);
+ addCategory(set.getAlias(), U_GC_MC_MASK, status);
+ addCategory(set.getAlias(), U_GC_MN_MASK, status);
+ addIdentifierIgnorable(set.getAlias(), status);
+ }
+ else if (propName.compare(u"javaUpperCase", -1) == 0) {
+ addCategory(set.getAlias(), U_GC_LU_MASK, status);
+ }
+ else if (propName.compare(u"javaValidCodePoint", -1) == 0) {
+ set->add(0, UnicodeSet::MAX_VALUE);
+ }
+ else if (propName.compare(u"javaWhitespace", -1) == 0) {
+ addCategory(set.getAlias(), U_GC_Z_MASK, status);
+ set->removeAll(UnicodeSet().add(0xa0).add(0x2007).add(0x202f));
+ set->add(9, 0x0d).add(0x1c, 0x1f);
+ } else {
+ status = U_REGEX_PROPERTY_SYNTAX;
+ }
+
+ if (U_SUCCESS(status) && !set->isEmpty() && (usetFlags & USET_CASE_INSENSITIVE)) {
+ set->closeOver(USET_CASE_INSENSITIVE);
+ }
+ break;
+ }
+
+ // Unrecognized property. ICU didn't like it as it was, and none of the Java compatibility
+ // extensions matched it.
+ status = U_REGEX_PROPERTY_SYNTAX;
+ } while (false); // End of do loop block. Code above breaks out of the block on success or hard failure.
+
+ if (U_SUCCESS(status)) {
+ U_ASSERT(set.isValid());
+ if (negated) {
+ set->complement();
}
- delete set;
- set = NULL;
+ return set.orphan();
+ } else {
+ if (status == U_ILLEGAL_ARGUMENT_ERROR) {
+ status = U_REGEX_PROPERTY_SYNTAX;
+ }
+ error(status);
+ return nullptr;
}
- error(*fStatus);
- return NULL;
}
-
//
// SetEval Part of the evaluation of [set expressions].
// Perform any pending (stacked) operations with precedence
diff --git a/deps/icu-small/source/i18n/region.cpp b/deps/icu-small/source/i18n/region.cpp
index 66f9ef35de..f182f61486 100644
--- a/deps/icu-small/source/i18n/region.cpp
+++ b/deps/icu-small/source/i18n/region.cpp
@@ -168,10 +168,18 @@ void U_CALLCONV Region::loadRegionData(UErrorCode &status) {
continents->addElement(continentName,status);
}
+ UResourceBundle *groupingBundle = nullptr;
while ( ures_hasNext(groupingContainment.getAlias()) ) {
- UnicodeString *groupingName = new UnicodeString(ures_getNextUnicodeString(groupingContainment.getAlias(),NULL,&status));
- groupings->addElement(groupingName,status);
+ groupingBundle = ures_getNextResource(groupingContainment.getAlias(), groupingBundle, &status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ UnicodeString *groupingName = new UnicodeString(ures_getKey(groupingBundle), -1, US_INV);
+ if (groupingName) {
+ groupings->addElement(groupingName,status);
+ }
}
+ ures_close(groupingBundle);
for ( int32_t i = 0 ; i < allRegions->size() ; i++ ) {
LocalPointer<Region> r(new Region(), status);
@@ -182,7 +190,7 @@ void U_CALLCONV Region::loadRegionData(UErrorCode &status) {
r->idStr = *regionName;
r->idStr.extract(0,r->idStr.length(),r->id,sizeof(r->id),US_INV);
- r->type = URGN_TERRITORY; // Only temporary - figure out the real type later once the aliases are known.
+ r->fType = URGN_TERRITORY; // Only temporary - figure out the real type later once the aliases are known.
Formattable result;
UErrorCode ps = U_ZERO_ERROR;
@@ -190,7 +198,7 @@ void U_CALLCONV Region::loadRegionData(UErrorCode &status) {
if ( U_SUCCESS(ps) ) {
r->code = result.getLong(); // Convert string to number
uhash_iput(newNumericCodeMap.getAlias(),r->code,(void *)(r.getAlias()),&status);
- r->type = URGN_SUBCONTINENT;
+ r->fType = URGN_SUBCONTINENT;
} else {
r->code = -1;
}
@@ -231,9 +239,9 @@ void U_CALLCONV Region::loadRegionData(UErrorCode &status) {
} else {
aliasFromRegion->code = -1;
}
- aliasFromRegion->type = URGN_DEPRECATED;
+ aliasFromRegion->fType = URGN_DEPRECATED;
} else {
- aliasFromRegion->type = URGN_DEPRECATED;
+ aliasFromRegion->fType = URGN_DEPRECATED;
}
{
@@ -290,26 +298,26 @@ void U_CALLCONV Region::loadRegionData(UErrorCode &status) {
UnicodeString WORLD_ID_STRING(WORLD_ID);
r = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)&WORLD_ID_STRING);
if ( r ) {
- r->type = URGN_WORLD;
+ r->fType = URGN_WORLD;
}
UnicodeString UNKNOWN_REGION_ID_STRING(UNKNOWN_REGION_ID);
r = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)&UNKNOWN_REGION_ID_STRING);
if ( r ) {
- r->type = URGN_UNKNOWN;
+ r->fType = URGN_UNKNOWN;
}
for ( int32_t i = 0 ; i < continents->size() ; i++ ) {
r = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)continents->elementAt(i));
if ( r ) {
- r->type = URGN_CONTINENT;
+ r->fType = URGN_CONTINENT;
}
}
for ( int32_t i = 0 ; i < groupings->size() ; i++ ) {
r = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)groupings->elementAt(i));
if ( r ) {
- r->type = URGN_GROUPING;
+ r->fType = URGN_GROUPING;
}
}
@@ -319,7 +327,7 @@ void U_CALLCONV Region::loadRegionData(UErrorCode &status) {
UnicodeString OUTLYING_OCEANIA_REGION_ID_STRING(OUTLYING_OCEANIA_REGION_ID);
r = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)&OUTLYING_OCEANIA_REGION_ID_STRING);
if ( r ) {
- r->type = URGN_SUBCONTINENT;
+ r->fType = URGN_SUBCONTINENT;
}
// Load territory containment info from the supplemental data.
@@ -356,7 +364,7 @@ void U_CALLCONV Region::loadRegionData(UErrorCode &status) {
// Set the parent region to be the containing region of the child.
// Regions of type GROUPING can't be set as the parent, since another region
// such as a SUBCONTINENT, CONTINENT, or WORLD must always be the parent.
- if ( parentRegion->type != URGN_GROUPING) {
+ if ( parentRegion->fType != URGN_GROUPING) {
childRegion->containingRegion = parentRegion;
}
}
@@ -367,15 +375,15 @@ void U_CALLCONV Region::loadRegionData(UErrorCode &status) {
int32_t pos = UHASH_FIRST;
while ( const UHashElement* element = uhash_nextElement(newRegionIDMap.getAlias(),&pos)) {
Region *ar = (Region *)element->value.pointer;
- if ( availableRegions[ar->type] == NULL ) {
+ if ( availableRegions[ar->fType] == NULL ) {
LocalPointer<UVector> newAr(new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status), status);
- availableRegions[ar->type] = newAr.orphan();
+ availableRegions[ar->fType] = newAr.orphan();
}
LocalPointer<UnicodeString> arString(new UnicodeString(ar->idStr), status);
if( U_FAILURE(status) ) {
return; // error out
}
- availableRegions[ar->type]->addElement((void *)arString.orphan(),status);
+ availableRegions[ar->fType]->addElement((void *)arString.orphan(),status);
}
ucln_i18n_registerCleanup(UCLN_I18N_REGION, region_cleanup);
@@ -416,7 +424,7 @@ void Region::cleanupRegionData() {
Region::Region ()
: code(-1),
- type(URGN_UNKNOWN),
+ fType(URGN_UNKNOWN),
containingRegion(NULL),
containedRegions(NULL),
preferredValues(NULL) {
@@ -481,7 +489,7 @@ Region::getInstance(const char *region_code, UErrorCode &status) {
return NULL;
}
- if ( r->type == URGN_DEPRECATED && r->preferredValues->size() == 1) {
+ if ( r->fType == URGN_DEPRECATED && r->preferredValues->size() == 1) {
StringEnumeration *pv = r->getPreferredValues(status);
pv->reset(status);
const UnicodeString *ustr = pv->snext(status);
@@ -529,7 +537,7 @@ Region::getInstance (int32_t code, UErrorCode &status) {
return NULL;
}
- if ( r->type == URGN_DEPRECATED && r->preferredValues->size() == 1) {
+ if ( r->fType == URGN_DEPRECATED && r->preferredValues->size() == 1) {
StringEnumeration *pv = r->getPreferredValues(status);
pv->reset(status);
const UnicodeString *ustr = pv->snext(status);
@@ -580,7 +588,7 @@ Region::getContainingRegion(URegionType type) const {
return NULL;
}
- return ( containingRegion->type == type )? containingRegion: containingRegion->getContainingRegion(type);
+ return ( containingRegion->fType == type)? containingRegion: containingRegion->getContainingRegion(type);
}
/**
@@ -618,9 +626,9 @@ Region::getContainedRegions( URegionType type, UErrorCode &status ) const {
StringEnumeration *cr = getContainedRegions(status);
for ( int32_t i = 0 ; i < cr->count(status) ; i++ ) {
- const char *id = cr->next(NULL,status);
- const Region *r = Region::getInstance(id,status);
- if ( r->getType() == type ) {
+ const char *regionId = cr->next(NULL,status);
+ const Region *r = Region::getInstance(regionId,status);
+ if ( r->getType() == type) {
result->addElement((void *)&r->idStr,status);
} else {
StringEnumeration *children = r->getContainedRegions(type, status);
@@ -672,7 +680,7 @@ Region::contains(const Region &other) const {
StringEnumeration*
Region::getPreferredValues(UErrorCode &status) const {
umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status); // returns immediately if U_FAILURE(status)
- if (U_FAILURE(status) || type != URGN_DEPRECATED) {
+ if (U_FAILURE(status) || fType != URGN_DEPRECATED) {
return NULL;
}
return new RegionNameEnumeration(preferredValues,status);
@@ -697,7 +705,7 @@ Region::getNumericCode() const {
*/
URegionType
Region::getType() const {
- return type;
+ return fType;
}
RegionNameEnumeration::RegionNameEnumeration(UVector *fNameList, UErrorCode& status) {
diff --git a/deps/icu-small/source/i18n/reldatefmt.cpp b/deps/icu-small/source/i18n/reldatefmt.cpp
index 42ede7ae4d..ae251ed20b 100644
--- a/deps/icu-small/source/i18n/reldatefmt.cpp
+++ b/deps/icu-small/source/i18n/reldatefmt.cpp
@@ -51,13 +51,13 @@ U_NAMESPACE_BEGIN
// RelativeDateTimeFormatter specific data for a single locale
class RelativeDateTimeCacheData: public SharedObject {
public:
- RelativeDateTimeCacheData() : combinedDateAndTime(NULL) {
+ RelativeDateTimeCacheData() : combinedDateAndTime(nullptr) {
// Initialize the cache arrays
for (int32_t style = 0; style < UDAT_STYLE_COUNT; ++style) {
- for (int32_t relUnit = 0; relUnit < UDAT_RELATIVE_UNIT_COUNT; ++relUnit) {
+ for (int32_t relUnit = 0; relUnit < UDAT_REL_UNIT_COUNT; ++relUnit) {
for (int32_t pl = 0; pl < StandardPlural::COUNT; ++pl) {
- relativeUnitsFormatters[style][relUnit][0][pl] = NULL;
- relativeUnitsFormatters[style][relUnit][1][pl] = NULL;
+ relativeUnitsFormatters[style][relUnit][0][pl] = nullptr;
+ relativeUnitsFormatters[style][relUnit][1][pl] = nullptr;
}
}
}
@@ -74,7 +74,7 @@ public:
// e.g., Next Tuesday; Yesterday; etc. For third index, 0
// means past, e.g., 5 days ago; 1 means future, e.g., in 5 days.
SimpleFormatter *relativeUnitsFormatters[UDAT_STYLE_COUNT]
- [UDAT_RELATIVE_UNIT_COUNT][2][StandardPlural::COUNT];
+ [UDAT_REL_UNIT_COUNT][2][StandardPlural::COUNT];
const UnicodeString& getAbsoluteUnitString(int32_t fStyle,
UDateAbsoluteUnit unit,
@@ -83,6 +83,10 @@ public:
UDateRelativeUnit unit,
int32_t pastFutureIndex,
int32_t pluralUnit) const;
+ const SimpleFormatter* getRelativeDateTimeUnitFormatter(int32_t fStyle,
+ URelativeDateTimeUnit unit,
+ int32_t pastFutureIndex,
+ int32_t pluralUnit) const;
const UnicodeString emptyString;
@@ -107,7 +111,7 @@ private:
RelativeDateTimeCacheData::~RelativeDateTimeCacheData() {
// clear out the cache arrays
for (int32_t style = 0; style < UDAT_STYLE_COUNT; ++style) {
- for (int32_t relUnit = 0; relUnit < UDAT_RELATIVE_UNIT_COUNT; ++relUnit) {
+ for (int32_t relUnit = 0; relUnit < UDAT_REL_UNIT_COUNT; ++relUnit) {
for (int32_t pl = 0; pl < StandardPlural::COUNT; ++pl) {
delete relativeUnitsFormatters[style][relUnit][0][pl];
delete relativeUnitsFormatters[style][relUnit][1][pl];
@@ -131,20 +135,41 @@ const UnicodeString& RelativeDateTimeCacheData::getAbsoluteUnitString(
return emptyString;
}
- // Use fallback cache for SimpleFormatter relativeUnits.
const SimpleFormatter* RelativeDateTimeCacheData::getRelativeUnitFormatter(
int32_t fStyle,
UDateRelativeUnit unit,
int32_t pastFutureIndex,
int32_t pluralUnit) const {
+ URelativeDateTimeUnit rdtunit = UDAT_REL_UNIT_COUNT;
+ switch (unit) {
+ case UDAT_RELATIVE_YEARS: rdtunit = UDAT_REL_UNIT_YEAR; break;
+ case UDAT_RELATIVE_MONTHS: rdtunit = UDAT_REL_UNIT_MONTH; break;
+ case UDAT_RELATIVE_WEEKS: rdtunit = UDAT_REL_UNIT_WEEK; break;
+ case UDAT_RELATIVE_DAYS: rdtunit = UDAT_REL_UNIT_DAY; break;
+ case UDAT_RELATIVE_HOURS: rdtunit = UDAT_REL_UNIT_HOUR; break;
+ case UDAT_RELATIVE_MINUTES: rdtunit = UDAT_REL_UNIT_MINUTE; break;
+ case UDAT_RELATIVE_SECONDS: rdtunit = UDAT_REL_UNIT_SECOND; break;
+ default: // a unit that the above method does not handle
+ return nullptr;
+ }
+
+ return getRelativeDateTimeUnitFormatter(fStyle, rdtunit, pastFutureIndex, pluralUnit);
+ }
+
+ // Use fallback cache for SimpleFormatter relativeUnits.
+ const SimpleFormatter* RelativeDateTimeCacheData::getRelativeDateTimeUnitFormatter(
+ int32_t fStyle,
+ URelativeDateTimeUnit unit,
+ int32_t pastFutureIndex,
+ int32_t pluralUnit) const {
int32_t style = fStyle;
do {
- if (relativeUnitsFormatters[style][unit][pastFutureIndex][pluralUnit] != NULL) {
+ if (relativeUnitsFormatters[style][unit][pastFutureIndex][pluralUnit] != nullptr) {
return relativeUnitsFormatters[style][unit][pastFutureIndex][pluralUnit];
}
style = fallBackCache[style];
} while (style != -1);
- return NULL; // No formatter found.
+ return nullptr; // No formatter found.
}
static UBool getStringWithFallback(
@@ -217,23 +242,35 @@ struct RelDateTimeFmtDataSink : public ResourceSink {
// Converts the generic units to UDAT_RELATIVE version.
switch (genUnit) {
case SECOND:
- return UDAT_RELATIVE_SECONDS;
+ return UDAT_REL_UNIT_SECOND;
case MINUTE:
- return UDAT_RELATIVE_MINUTES;
+ return UDAT_REL_UNIT_MINUTE;
case HOUR:
- return UDAT_RELATIVE_HOURS;
+ return UDAT_REL_UNIT_HOUR;
case DAY:
- return UDAT_RELATIVE_DAYS;
+ return UDAT_REL_UNIT_DAY;
case WEEK:
- return UDAT_RELATIVE_WEEKS;
+ return UDAT_REL_UNIT_WEEK;
case MONTH:
- return UDAT_RELATIVE_MONTHS;
- /*
- * case QUARTER:
- * return UDATE_RELATIVE_QUARTERS;
- */
+ return UDAT_REL_UNIT_MONTH;
+ case QUARTER:
+ return UDAT_REL_UNIT_QUARTER;
case YEAR:
- return UDAT_RELATIVE_YEARS;
+ return UDAT_REL_UNIT_YEAR;
+ case SUNDAY:
+ return UDAT_REL_UNIT_SUNDAY;
+ case MONDAY:
+ return UDAT_REL_UNIT_MONDAY;
+ case TUESDAY:
+ return UDAT_REL_UNIT_TUESDAY;
+ case WEDNESDAY:
+ return UDAT_REL_UNIT_WEDNESDAY;
+ case THURSDAY:
+ return UDAT_REL_UNIT_THURSDAY;
+ case FRIDAY:
+ return UDAT_REL_UNIT_FRIDAY;
+ case SATURDAY:
+ return UDAT_REL_UNIT_SATURDAY;
default:
return -1;
}
@@ -248,10 +285,8 @@ struct RelDateTimeFmtDataSink : public ResourceSink {
return UDAT_ABSOLUTE_WEEK;
case MONTH:
return UDAT_ABSOLUTE_MONTH;
- /* TODO: Add in QUARTER
- * case QUARTER:
- * return UDAT_ABSOLUTE_QUARTER;
- */
+ case QUARTER:
+ return UDAT_ABSOLUTE_QUARTER;
case YEAR:
return UDAT_ABSOLUTE_YEAR;
case SUNDAY:
@@ -312,7 +347,7 @@ struct RelDateTimeFmtDataSink : public ResourceSink {
// Utility functions
static UDateRelativeDateTimeFormatterStyle styleFromString(const char *s) {
- int32_t len = uprv_strlen(s);
+ int32_t len = static_cast<int32_t>(uprv_strlen(s));
if (len >= 7 && uprv_strcmp(s + len - 7, "-narrow") == 0) {
return UDAT_STYLE_NARROW;
}
@@ -430,7 +465,7 @@ struct RelDateTimeFmtDataSink : public ResourceSink {
}
int32_t relUnitIndex = relUnitFromGeneric(genericUnit);
- if (relUnitIndex == UDAT_RELATIVE_SECONDS && uprv_strcmp(key, "0") == 0 &&
+ if (relUnitIndex == UDAT_REL_UNIT_SECOND && uprv_strcmp(key, "0") == 0 &&
outputData.absoluteUnits[style][UDAT_ABSOLUTE_NOW][UDAT_DIRECTION_PLAIN].isEmpty()) {
// Handle "NOW"
outputData.absoluteUnits[style][UDAT_ABSOLUTE_NOW]
@@ -463,10 +498,10 @@ struct RelDateTimeFmtDataSink : public ResourceSink {
outputData.relativeUnitsFormatters[style][relUnitIndex]
[pastFutureIndex];
// Only set if not already established.
- if (patterns[pluralIndex] == NULL) {
+ if (patterns[pluralIndex] == nullptr) {
patterns[pluralIndex] = new SimpleFormatter(
value.getUnicodeString(errorCode), 0, 1, errorCode);
- if (patterns[pluralIndex] == NULL) {
+ if (patterns[pluralIndex] == nullptr) {
errorCode = U_MEMORY_ALLOCATION_ERROR;
}
}
@@ -546,7 +581,7 @@ struct RelDateTimeFmtDataSink : public ResourceSink {
consumeAlias(key, value, errorCode);
} else {
style = styleFromString(key);
- int32_t unitSize = uprv_strlen(key) - styleSuffixLength(style);
+ int32_t unitSize = static_cast<int32_t>(uprv_strlen(key)) - styleSuffixLength(style);
genericUnit = unitOrNegativeFromString(key, unitSize);
if (style >= 0 && genericUnit != INVALID_UNIT) {
consumeTimeUnit(key, value, errorCode);
@@ -570,8 +605,14 @@ static void loadWeekdayNames(UnicodeString absoluteUnits[UDAT_STYLE_COUNT]
[UDAT_ABSOLUTE_UNIT_COUNT][UDAT_DIRECTION_COUNT],
const char* localeId,
UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
Locale locale(localeId);
DateFormatSymbols dfSym(locale, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
for (int32_t style = 0; style < UDAT_STYLE_COUNT; ++style) {
DateFormatSymbols::DtWidthType dtfmtWidth = styleToDateFormatSymbolWidth[style];
int32_t count;
@@ -595,6 +636,9 @@ static UBool loadUnitData(
RelDateTimeFmtDataSink sink(cacheData);
ures_getAllItemsWithFallback(resource, "fields", sink, status);
+ if (U_FAILURE(status)) {
+ return false;
+ }
// Get the weekday names from DateFormatSymbols.
loadWeekdayNames(cacheData.absoluteUnits, localeId, status);
@@ -619,7 +663,7 @@ static UBool getDateTimePattern(
.append("/DateTimePatterns", status);
LocalUResourceBundlePointer topLevel(
ures_getByKeyWithFallback(
- resource, pathBuffer.data(), NULL, &status));
+ resource, pathBuffer.data(), nullptr, &status));
if (U_FAILURE(status)) {
return FALSE;
}
@@ -636,68 +680,68 @@ static UBool getDateTimePattern(
template<> U_I18N_API
const RelativeDateTimeCacheData *LocaleCacheKey<RelativeDateTimeCacheData>::createObject(const void * /*unused*/, UErrorCode &status) const {
const char *localeId = fLoc.getName();
- LocalUResourceBundlePointer topLevel(ures_open(NULL, localeId, &status));
+ LocalUResourceBundlePointer topLevel(ures_open(nullptr, localeId, &status));
if (U_FAILURE(status)) {
- return NULL;
+ return nullptr;
}
LocalPointer<RelativeDateTimeCacheData> result(
new RelativeDateTimeCacheData());
if (result.isNull()) {
status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
+ return nullptr;
}
if (!loadUnitData(
topLevel.getAlias(),
*result,
localeId,
status)) {
- return NULL;
+ return nullptr;
}
UnicodeString dateTimePattern;
if (!getDateTimePattern(topLevel.getAlias(), dateTimePattern, status)) {
- return NULL;
+ return nullptr;
}
result->adoptCombinedDateAndTime(
new SimpleFormatter(dateTimePattern, 2, 2, status));
if (U_FAILURE(status)) {
- return NULL;
+ return nullptr;
}
result->addRef();
return result.orphan();
}
RelativeDateTimeFormatter::RelativeDateTimeFormatter(UErrorCode& status) :
- fCache(NULL),
- fNumberFormat(NULL),
- fPluralRules(NULL),
+ fCache(nullptr),
+ fNumberFormat(nullptr),
+ fPluralRules(nullptr),
fStyle(UDAT_STYLE_LONG),
fContext(UDISPCTX_CAPITALIZATION_NONE),
- fOptBreakIterator(NULL) {
- init(NULL, NULL, status);
+ fOptBreakIterator(nullptr) {
+ init(nullptr, nullptr, status);
}
RelativeDateTimeFormatter::RelativeDateTimeFormatter(
const Locale& locale, UErrorCode& status) :
- fCache(NULL),
- fNumberFormat(NULL),
- fPluralRules(NULL),
+ fCache(nullptr),
+ fNumberFormat(nullptr),
+ fPluralRules(nullptr),
fStyle(UDAT_STYLE_LONG),
fContext(UDISPCTX_CAPITALIZATION_NONE),
- fOptBreakIterator(NULL),
+ fOptBreakIterator(nullptr),
fLocale(locale) {
- init(NULL, NULL, status);
+ init(nullptr, nullptr, status);
}
RelativeDateTimeFormatter::RelativeDateTimeFormatter(
const Locale& locale, NumberFormat *nfToAdopt, UErrorCode& status) :
- fCache(NULL),
- fNumberFormat(NULL),
- fPluralRules(NULL),
+ fCache(nullptr),
+ fNumberFormat(nullptr),
+ fPluralRules(nullptr),
fStyle(UDAT_STYLE_LONG),
fContext(UDISPCTX_CAPITALIZATION_NONE),
- fOptBreakIterator(NULL),
+ fOptBreakIterator(nullptr),
fLocale(locale) {
- init(nfToAdopt, NULL, status);
+ init(nfToAdopt, nullptr, status);
}
RelativeDateTimeFormatter::RelativeDateTimeFormatter(
@@ -706,12 +750,12 @@ RelativeDateTimeFormatter::RelativeDateTimeFormatter(
UDateRelativeDateTimeFormatterStyle styl,
UDisplayContext capitalizationContext,
UErrorCode& status) :
- fCache(NULL),
- fNumberFormat(NULL),
- fPluralRules(NULL),
+ fCache(nullptr),
+ fNumberFormat(nullptr),
+ fPluralRules(nullptr),
fStyle(styl),
fContext(capitalizationContext),
- fOptBreakIterator(NULL),
+ fOptBreakIterator(nullptr),
fLocale(locale) {
if (U_FAILURE(status)) {
return;
@@ -727,7 +771,7 @@ RelativeDateTimeFormatter::RelativeDateTimeFormatter(
}
init(nfToAdopt, bi, status);
} else {
- init(nfToAdopt, NULL, status);
+ init(nfToAdopt, nullptr, status);
}
}
@@ -744,7 +788,7 @@ RelativeDateTimeFormatter::RelativeDateTimeFormatter(
fCache->addRef();
fNumberFormat->addRef();
fPluralRules->addRef();
- if (fOptBreakIterator != NULL) {
+ if (fOptBreakIterator != nullptr) {
fOptBreakIterator->addRef();
}
}
@@ -764,16 +808,16 @@ RelativeDateTimeFormatter& RelativeDateTimeFormatter::operator=(
}
RelativeDateTimeFormatter::~RelativeDateTimeFormatter() {
- if (fCache != NULL) {
+ if (fCache != nullptr) {
fCache->removeRef();
}
- if (fNumberFormat != NULL) {
+ if (fNumberFormat != nullptr) {
fNumberFormat->removeRef();
}
- if (fPluralRules != NULL) {
+ if (fPluralRules != nullptr) {
fPluralRules->removeRef();
}
- if (fOptBreakIterator != NULL) {
+ if (fOptBreakIterator != nullptr) {
fOptBreakIterator->removeRef();
}
}
@@ -812,7 +856,7 @@ UnicodeString& RelativeDateTimeFormatter::format(
const SimpleFormatter* formatter =
fCache->getRelativeUnitFormatter(fStyle, unit, bFuture, pluralIndex);
- if (formatter == NULL) {
+ if (formatter == nullptr) {
// TODO: WARN - look at quantity formatter's action with an error.
status = U_INVALID_FORMAT_ERROR;
return appendTo;
@@ -828,33 +872,35 @@ UnicodeString& RelativeDateTimeFormatter::formatNumeric(
if (U_FAILURE(status)) {
return appendTo;
}
- // TODO:
- // The full implementation of this depends on CLDR data that is not yet available,
- // see: http://unicode.org/cldr/trac/ticket/9165 Add more relative field data.
- // In the meantime do a quick bring-up by calling the old format method; this
- // leaves some holes (even for data that is currently available, such as quarter).
- // When the new CLDR data is available, update the data storage accordingly,
- // rewrite this to use it directly, and rewrite the old format method to call this
- // new one; that is covered by http://bugs.icu-project.org/trac/ticket/12171.
- UDateRelativeUnit relunit = UDAT_RELATIVE_UNIT_COUNT;
- switch (unit) {
- case UDAT_REL_UNIT_YEAR: relunit = UDAT_RELATIVE_YEARS; break;
- case UDAT_REL_UNIT_MONTH: relunit = UDAT_RELATIVE_MONTHS; break;
- case UDAT_REL_UNIT_WEEK: relunit = UDAT_RELATIVE_WEEKS; break;
- case UDAT_REL_UNIT_DAY: relunit = UDAT_RELATIVE_DAYS; break;
- case UDAT_REL_UNIT_HOUR: relunit = UDAT_RELATIVE_HOURS; break;
- case UDAT_REL_UNIT_MINUTE: relunit = UDAT_RELATIVE_MINUTES; break;
- case UDAT_REL_UNIT_SECOND: relunit = UDAT_RELATIVE_SECONDS; break;
- default: // a unit that the above method does not handle
- status = U_UNSUPPORTED_ERROR;
- return appendTo;
- }
UDateDirection direction = UDAT_DIRECTION_NEXT;
if (std::signbit(offset)) { // needed to handle -0.0
direction = UDAT_DIRECTION_LAST;
offset = -offset;
}
- return format(offset, direction, relunit, appendTo, status);
+ if (direction != UDAT_DIRECTION_LAST && direction != UDAT_DIRECTION_NEXT) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return appendTo;
+ }
+ int32_t bFuture = direction == UDAT_DIRECTION_NEXT ? 1 : 0;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+
+ UnicodeString result;
+ UnicodeString formattedNumber;
+
+ StandardPlural::Form pluralIndex = QuantityFormatter::selectPlural(
+ offset, **fNumberFormat, **fPluralRules, formattedNumber, pos,
+ status);
+
+ const SimpleFormatter* formatter =
+ fCache->getRelativeDateTimeUnitFormatter(fStyle, unit, bFuture, pluralIndex);
+ if (formatter == nullptr) {
+ // TODO: WARN - look at quantity formatter's action with an error.
+ status = U_INVALID_FORMAT_ERROR;
+ return appendTo;
+ }
+ formatter->format(formattedNumber, result, status);
+ adjustForContext(result);
+ return appendTo.append(result);
}
UnicodeString& RelativeDateTimeFormatter::format(
@@ -871,7 +917,7 @@ UnicodeString& RelativeDateTimeFormatter::format(
// Get string using fallback.
UnicodeString result;
result.fastCopyFrom(fCache->getAbsoluteUnitString(fStyle, unit, direction));
- if (fOptBreakIterator != NULL) {
+ if (fOptBreakIterator != nullptr) {
adjustForContext(result);
}
return appendTo.append(result);
@@ -908,6 +954,7 @@ UnicodeString& RelativeDateTimeFormatter::format(
UDateAbsoluteUnit absunit = UDAT_ABSOLUTE_UNIT_COUNT;
switch (unit) {
case UDAT_REL_UNIT_YEAR: absunit = UDAT_ABSOLUTE_YEAR; break;
+ case UDAT_REL_UNIT_QUARTER: absunit = UDAT_ABSOLUTE_QUARTER; break;
case UDAT_REL_UNIT_MONTH: absunit = UDAT_ABSOLUTE_MONTH; break;
case UDAT_REL_UNIT_WEEK: absunit = UDAT_ABSOLUTE_WEEK; break;
case UDAT_REL_UNIT_DAY: absunit = UDAT_ABSOLUTE_DAY; break;
@@ -930,7 +977,7 @@ UnicodeString& RelativeDateTimeFormatter::format(
const UnicodeString &unitFormatString =
fCache->getAbsoluteUnitString(fStyle, absunit, direction);
if (!unitFormatString.isEmpty()) {
- if (fOptBreakIterator != NULL) {
+ if (fOptBreakIterator != nullptr) {
UnicodeString result(unitFormatString);
adjustForContext(result);
return appendTo.append(result);
@@ -951,7 +998,7 @@ UnicodeString& RelativeDateTimeFormatter::combineDateAndTime(
}
void RelativeDateTimeFormatter::adjustForContext(UnicodeString &str) const {
- if (fOptBreakIterator == NULL
+ if (fOptBreakIterator == nullptr
|| str.length() == 0 || !u_islower(str.char32At(0))) {
return;
}
@@ -992,7 +1039,7 @@ void RelativeDateTimeFormatter::init(
shared->removeRef();
} else {
SharedNumberFormat *shared = new SharedNumberFormat(nf.getAlias());
- if (shared == NULL) {
+ if (shared == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
@@ -1003,7 +1050,7 @@ void RelativeDateTimeFormatter::init(
SharedObject::clearPtr(fOptBreakIterator);
} else {
SharedBreakIterator *shared = new SharedBreakIterator(bi.getAlias());
- if (shared == NULL) {
+ if (shared == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
@@ -1026,13 +1073,13 @@ ureldatefmt_open( const char* locale,
UErrorCode* status )
{
if (U_FAILURE(*status)) {
- return NULL;
+ return nullptr;
}
LocalPointer<RelativeDateTimeFormatter> formatter(new RelativeDateTimeFormatter(Locale(locale),
(NumberFormat*)nfToAdopt, width,
capitalizationContext, *status), *status);
if (U_FAILURE(*status)) {
- return NULL;
+ return nullptr;
}
return (URelativeDateTimeFormatter*)formatter.orphan();
}
@@ -1054,13 +1101,13 @@ ureldatefmt_formatNumeric( const URelativeDateTimeFormatter* reldatefmt,
if (U_FAILURE(*status)) {
return 0;
}
- if (result == NULL ? resultCapacity != 0 : resultCapacity < 0) {
+ if (result == nullptr ? resultCapacity != 0 : resultCapacity < 0) {
*status = U_ILLEGAL_ARGUMENT_ERROR;
return 0;
}
UnicodeString res;
- if (result != NULL) {
- // NULL destination for pure preflighting: empty dummy string
+ if (result != nullptr) {
+ // nullptr destination for pure preflighting: empty dummy string
// otherwise, alias the destination buffer (copied from udat_format)
res.setTo(result, 0, resultCapacity);
}
@@ -1082,13 +1129,13 @@ ureldatefmt_format( const URelativeDateTimeFormatter* reldatefmt,
if (U_FAILURE(*status)) {
return 0;
}
- if (result == NULL ? resultCapacity != 0 : resultCapacity < 0) {
+ if (result == nullptr ? resultCapacity != 0 : resultCapacity < 0) {
*status = U_ILLEGAL_ARGUMENT_ERROR;
return 0;
}
UnicodeString res;
- if (result != NULL) {
- // NULL destination for pure preflighting: empty dummy string
+ if (result != nullptr) {
+ // nullptr destination for pure preflighting: empty dummy string
// otherwise, alias the destination buffer (copied from udat_format)
res.setTo(result, 0, resultCapacity);
}
@@ -1112,9 +1159,9 @@ ureldatefmt_combineDateAndTime( const URelativeDateTimeFormatter* reldatefmt,
if (U_FAILURE(*status)) {
return 0;
}
- if (result == NULL ? resultCapacity != 0 : resultCapacity < 0 ||
- (relativeDateString == NULL ? relativeDateStringLen != 0 : relativeDateStringLen < -1) ||
- (timeString == NULL ? timeStringLen != 0 : timeStringLen < -1)) {
+ if (result == nullptr ? resultCapacity != 0 : resultCapacity < 0 ||
+ (relativeDateString == nullptr ? relativeDateStringLen != 0 : relativeDateStringLen < -1) ||
+ (timeString == nullptr ? timeStringLen != 0 : timeStringLen < -1)) {
*status = U_ILLEGAL_ARGUMENT_ERROR;
return 0;
}
diff --git a/deps/icu-small/source/i18n/reldtfmt.cpp b/deps/icu-small/source/i18n/reldtfmt.cpp
index d3ab45dc63..753672d905 100644
--- a/deps/icu-small/source/i18n/reldtfmt.cpp
+++ b/deps/icu-small/source/i18n/reldtfmt.cpp
@@ -430,7 +430,7 @@ RelativeDateFormat::setContext(UDisplayContext value, UErrorCode& status)
if ( fCapitalizationBrkIter == NULL && (value==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
(value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU && fCapitalizationOfRelativeUnitsForUIListMenu) ||
(value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE && fCapitalizationOfRelativeUnitsForStandAlone)) ) {
- UErrorCode status = U_ZERO_ERROR;
+ status = U_ZERO_ERROR;
fCapitalizationBrkIter = BreakIterator::createSentenceInstance(fLocale, status);
if (U_FAILURE(status)) {
delete fCapitalizationBrkIter;
@@ -456,8 +456,8 @@ RelativeDateFormat::initCapitalizationContextInfo(const Locale& thelocale)
const int32_t * intVector = ures_getIntVector(rb.getAlias(),
&len, &status);
if (U_SUCCESS(status) && intVector != NULL && len >= 2) {
- fCapitalizationOfRelativeUnitsForUIListMenu = intVector[0];
- fCapitalizationOfRelativeUnitsForStandAlone = intVector[1];
+ fCapitalizationOfRelativeUnitsForUIListMenu = static_cast<UBool>(intVector[0]);
+ fCapitalizationOfRelativeUnitsForStandAlone = static_cast<UBool>(intVector[1]);
}
}
#endif
diff --git a/deps/icu-small/source/i18n/reldtfmt.h b/deps/icu-small/source/i18n/reldtfmt.h
index 5063a6388f..0403da11ef 100644
--- a/deps/icu-small/source/i18n/reldtfmt.h
+++ b/deps/icu-small/source/i18n/reldtfmt.h
@@ -235,7 +235,6 @@ public:
*/
virtual const DateFormatSymbols* getDateFormatSymbols(void) const;
- /* Cannot use #ifndef U_HIDE_DRAFT_API for the following draft method since it is virtual */
/**
* Set a particular UDisplayContext value in the formatter, such as
* UDISPCTX_CAPITALIZATION_FOR_STANDALONE. Note: For getContext, see
diff --git a/deps/icu-small/source/i18n/rematch.cpp b/deps/icu-small/source/i18n/rematch.cpp
index f252182207..95fd0d2240 100644
--- a/deps/icu-small/source/i18n/rematch.cpp
+++ b/deps/icu-small/source/i18n/rematch.cpp
@@ -801,7 +801,7 @@ UBool RegexMatcher::find(UErrorCode &status) {
case START_LINE:
{
- UChar32 c;
+ UChar32 ch;
if (startPos == fAnchorStart) {
MatchAt(startPos, FALSE, status);
if (U_FAILURE(status)) {
@@ -811,17 +811,17 @@ UBool RegexMatcher::find(UErrorCode &status) {
return TRUE;
}
UTEXT_SETNATIVEINDEX(fInputText, startPos);
- c = UTEXT_NEXT32(fInputText);
+ ch = UTEXT_NEXT32(fInputText);
startPos = UTEXT_GETNATIVEINDEX(fInputText);
} else {
UTEXT_SETNATIVEINDEX(fInputText, startPos);
- c = UTEXT_PREVIOUS32(fInputText);
+ ch = UTEXT_PREVIOUS32(fInputText);
UTEXT_SETNATIVEINDEX(fInputText, startPos);
}
if (fPattern->fFlags & UREGEX_UNIX_LINES) {
for (;;) {
- if (c == 0x0a) {
+ if (ch == 0x0a) {
MatchAt(startPos, FALSE, status);
if (U_FAILURE(status)) {
return FALSE;
@@ -836,7 +836,7 @@ UBool RegexMatcher::find(UErrorCode &status) {
fHitEnd = TRUE;
return FALSE;
}
- c = UTEXT_NEXT32(fInputText);
+ ch = UTEXT_NEXT32(fInputText);
startPos = UTEXT_GETNATIVEINDEX(fInputText);
// Note that it's perfectly OK for a pattern to have a zero-length
// match at the end of a string, so we must make sure that the loop
@@ -846,8 +846,8 @@ UBool RegexMatcher::find(UErrorCode &status) {
}
} else {
for (;;) {
- if (isLineTerminator(c)) {
- if (c == 0x0d && startPos < fActiveLimit && UTEXT_CURRENT32(fInputText) == 0x0a) {
+ if (isLineTerminator(ch)) {
+ if (ch == 0x0d && startPos < fActiveLimit && UTEXT_CURRENT32(fInputText) == 0x0a) {
(void)UTEXT_NEXT32(fInputText);
startPos = UTEXT_GETNATIVEINDEX(fInputText);
}
@@ -865,7 +865,7 @@ UBool RegexMatcher::find(UErrorCode &status) {
fHitEnd = TRUE;
return FALSE;
}
- c = UTEXT_NEXT32(fInputText);
+ ch = UTEXT_NEXT32(fInputText);
startPos = UTEXT_GETNATIVEINDEX(fInputText);
// Note that it's perfectly OK for a pattern to have a zero-length
// match at the end of a string, so we must make sure that the loop
@@ -1034,7 +1034,7 @@ UBool RegexMatcher::findUsingChunk(UErrorCode &status) {
return FALSE;
}
}
- U_ASSERT(FALSE);
+ U_ASSERT(FALSE);
case START_STRING:
case START_CHAR:
@@ -1067,7 +1067,7 @@ UBool RegexMatcher::findUsingChunk(UErrorCode &status) {
case START_LINE:
{
- UChar32 c;
+ UChar32 ch;
if (startPos == fAnchorStart) {
MatchChunkAt(startPos, FALSE, status);
if (U_FAILURE(status)) {
@@ -1081,8 +1081,8 @@ UBool RegexMatcher::findUsingChunk(UErrorCode &status) {
if (fPattern->fFlags & UREGEX_UNIX_LINES) {
for (;;) {
- c = inputBuf[startPos-1];
- if (c == 0x0a) {
+ ch = inputBuf[startPos-1];
+ if (ch == 0x0a) {
MatchChunkAt(startPos, FALSE, status);
if (U_FAILURE(status)) {
return FALSE;
@@ -1105,9 +1105,9 @@ UBool RegexMatcher::findUsingChunk(UErrorCode &status) {
}
} else {
for (;;) {
- c = inputBuf[startPos-1];
- if (isLineTerminator(c)) {
- if (c == 0x0d && startPos < fActiveLimit && inputBuf[startPos] == 0x0a) {
+ ch = inputBuf[startPos-1];
+ if (isLineTerminator(ch)) {
+ if (ch == 0x0d && startPos < fActiveLimit && inputBuf[startPos] == 0x0a) {
startPos++;
}
MatchChunkAt(startPos, FALSE, status);
@@ -2774,7 +2774,7 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) {
int64_t *pat = fPattern->fCompiledPat->getBuffer();
const UChar *litText = fPattern->fLiteralText.getBuffer();
- UVector *sets = fPattern->fSets;
+ UVector *fSets = fPattern->fSets;
fFrameSize = fPattern->fFrameSize;
REStackFrame *fp = resetStack();
@@ -3376,7 +3376,7 @@ GC_Done:
// There is input left. Pick up one char and test it for set membership.
UChar32 c = UTEXT_NEXT32(fInputText);
- U_ASSERT(opValue > 0 && opValue < sets->size());
+ U_ASSERT(opValue > 0 && opValue < fSets->size());
if (c<256) {
Regex8BitSet *s8 = &fPattern->fSets8[opValue];
if (s8->contains(c)) {
@@ -3384,7 +3384,7 @@ GC_Done:
break;
}
} else {
- UnicodeSet *s = (UnicodeSet *)sets->elementAt(opValue);
+ UnicodeSet *s = (UnicodeSet *)fSets->elementAt(opValue);
if (s->contains(c)) {
// The character is in the set. A Match.
fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
@@ -3671,9 +3671,9 @@ GC_Done:
if (newFP == (int64_t *)fp) {
break;
}
- int32_t i;
- for (i=0; i<fFrameSize; i++) {
- newFP[i] = ((int64_t *)fp)[i];
+ int32_t j;
+ for (j=0; j<fFrameSize; j++) {
+ newFP[j] = ((int64_t *)fp)[j];
}
fp = (REStackFrame *)newFP;
fStack->setSize(newStackSize);
@@ -3830,9 +3830,9 @@ GC_Done:
// This makes the capture groups from within the look-ahead
// expression available.
int64_t *newFP = fStack->getBuffer() + newStackSize - fFrameSize;
- int32_t i;
- for (i=0; i<fFrameSize; i++) {
- newFP[i] = ((int64_t *)fp)[i];
+ int32_t j;
+ for (j=0; j<fFrameSize; j++) {
+ newFP[j] = ((int64_t *)fp)[j];
}
fp = (REStackFrame *)newFP;
fStack->setSize(newStackSize);
@@ -4123,9 +4123,9 @@ GC_Done:
// This op scans through all matching input.
// The following LOOP_C op emulates stack unwinding if the following pattern fails.
{
- U_ASSERT(opValue > 0 && opValue < sets->size());
+ U_ASSERT(opValue > 0 && opValue < fSets->size());
Regex8BitSet *s8 = &fPattern->fSets8[opValue];
- UnicodeSet *s = (UnicodeSet *)sets->elementAt(opValue);
+ UnicodeSet *s = (UnicodeSet *)fSets->elementAt(opValue);
// Loop through input, until either the input is exhausted or
// we reach a character that is not a member of the set.
@@ -4350,7 +4350,7 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu
int64_t *pat = fPattern->fCompiledPat->getBuffer();
const UChar *litText = fPattern->fLiteralText.getBuffer();
- UVector *sets = fPattern->fSets;
+ UVector *fSets = fPattern->fSets;
const UChar *inputBuf = fInputText->chunkContents;
@@ -4928,7 +4928,7 @@ GC_Done:
break;
}
- U_ASSERT(opValue > 0 && opValue < sets->size());
+ U_ASSERT(opValue > 0 && opValue < fSets->size());
// There is input left. Pick up one char and test it for set membership.
UChar32 c;
@@ -4940,7 +4940,7 @@ GC_Done:
break;
}
} else {
- UnicodeSet *s = (UnicodeSet *)sets->elementAt(opValue);
+ UnicodeSet *s = (UnicodeSet *)fSets->elementAt(opValue);
if (s->contains(c)) {
// The character is in the set. A Match.
break;
@@ -5214,9 +5214,9 @@ GC_Done:
if (newFP == (int64_t *)fp) {
break;
}
- int32_t i;
- for (i=0; i<fFrameSize; i++) {
- newFP[i] = ((int64_t *)fp)[i];
+ int32_t j;
+ for (j=0; j<fFrameSize; j++) {
+ newFP[j] = ((int64_t *)fp)[j];
}
fp = (REStackFrame *)newFP;
fStack->setSize(newStackSize);
@@ -5361,9 +5361,9 @@ GC_Done:
// This makes the capture groups from within the look-ahead
// expression available.
int64_t *newFP = fStack->getBuffer() + newStackSize - fFrameSize;
- int32_t i;
- for (i=0; i<fFrameSize; i++) {
- newFP[i] = ((int64_t *)fp)[i];
+ int32_t j;
+ for (j=0; j<fFrameSize; j++) {
+ newFP[j] = ((int64_t *)fp)[j];
}
fp = (REStackFrame *)newFP;
fStack->setSize(newStackSize);
@@ -5623,9 +5623,9 @@ GC_Done:
// This op scans through all matching input.
// The following LOOP_C op emulates stack unwinding if the following pattern fails.
{
- U_ASSERT(opValue > 0 && opValue < sets->size());
+ U_ASSERT(opValue > 0 && opValue < fSets->size());
Regex8BitSet *s8 = &fPattern->fSets8[opValue];
- UnicodeSet *s = (UnicodeSet *)sets->elementAt(opValue);
+ UnicodeSet *s = (UnicodeSet *)fSets->elementAt(opValue);
// Loop through input, until either the input is exhausted or
// we reach a character that is not a member of the set.
diff --git a/deps/icu-small/source/i18n/rulebasedcollator.cpp b/deps/icu-small/source/i18n/rulebasedcollator.cpp
index ab65f10a3b..b057b6bbd5 100644
--- a/deps/icu-small/source/i18n/rulebasedcollator.cpp
+++ b/deps/icu-small/source/i18n/rulebasedcollator.cpp
@@ -764,9 +764,9 @@ RuleBasedCollator::internalCompareUTF8(const char *left, int32_t leftLength,
// Make sure both or neither strings have a known length.
// We do not optimize for mixed length/termination.
if(leftLength >= 0) {
- if(rightLength < 0) { rightLength = uprv_strlen(right); }
+ if(rightLength < 0) { rightLength = static_cast<int32_t>(uprv_strlen(right)); }
} else {
- if(rightLength >= 0) { leftLength = uprv_strlen(left); }
+ if(rightLength >= 0) { leftLength = static_cast<int32_t>(uprv_strlen(left)); }
}
return doCompare(reinterpret_cast<const uint8_t *>(left), leftLength,
reinterpret_cast<const uint8_t *>(right), rightLength, errorCode);
@@ -862,9 +862,9 @@ public:
} else {
str.setTo(text, (int32_t)(spanLimit - text));
{
- ReorderingBuffer buffer(nfcImpl, str);
- if(buffer.init(str.length(), errorCode)) {
- nfcImpl.makeFCD(spanLimit, textLimit, &buffer, errorCode);
+ ReorderingBuffer r_buffer(nfcImpl, str);
+ if(r_buffer.init(str.length(), errorCode)) {
+ nfcImpl.makeFCD(spanLimit, textLimit, &r_buffer, errorCode);
}
}
if(U_SUCCESS(errorCode)) {
diff --git a/deps/icu-small/source/i18n/scriptset.cpp b/deps/icu-small/source/i18n/scriptset.cpp
index 9358e63b9e..558d178e2f 100644
--- a/deps/icu-small/source/i18n/scriptset.cpp
+++ b/deps/icu-small/source/i18n/scriptset.cpp
@@ -298,7 +298,7 @@ uhash_compareScriptSet(UElement key0, UElement key1) {
icu::ScriptSet *s0 = static_cast<icu::ScriptSet *>(key0.pointer);
icu::ScriptSet *s1 = static_cast<icu::ScriptSet *>(key1.pointer);
int32_t diff = s0->countMembers() - s1->countMembers();
- if (diff != 0) return diff;
+ if (diff != 0) return static_cast<UBool>(diff);
int32_t i0 = s0->nextSetBit(0);
int32_t i1 = s1->nextSetBit(0);
while ((diff = i0-i1) == 0 && i0 > 0) {
diff --git a/deps/icu-small/source/i18n/shareddateformatsymbols.h b/deps/icu-small/source/i18n/shareddateformatsymbols.h
index ca9a210819..66a06ecae5 100644
--- a/deps/icu-small/source/i18n/shareddateformatsymbols.h
+++ b/deps/icu-small/source/i18n/shareddateformatsymbols.h
@@ -12,6 +12,9 @@
#define __SHARED_DATEFORMATSYMBOLS_H__
#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
#include "sharedobject.h"
#include "unicode/dtfmtsym.h"
@@ -33,4 +36,6 @@ private:
U_NAMESPACE_END
+#endif /* !UCONFIG_NO_FORMATTING */
+
#endif
diff --git a/deps/icu-small/source/i18n/smpdtfmt.cpp b/deps/icu-small/source/i18n/smpdtfmt.cpp
index b1b90882fc..2bc8e49625 100644
--- a/deps/icu-small/source/i18n/smpdtfmt.cpp
+++ b/deps/icu-small/source/i18n/smpdtfmt.cpp
@@ -244,9 +244,9 @@ SimpleDateFormat::NSOverride::~NSOverride() {
void SimpleDateFormat::NSOverride::free() {
NSOverride *cur = this;
while (cur) {
- NSOverride *next = cur->next;
+ NSOverride *next_temp = cur->next;
delete cur;
- cur = next;
+ cur = next_temp;
}
}
@@ -1304,15 +1304,15 @@ SimpleDateFormat::processOverrideString(const Locale &locale, const UnicodeStrin
int32_t nsNameHash = nsName.hashCode();
// See if the numbering system is in the override list, if not, then add it.
- NSOverride *cur = overrideList;
+ NSOverride *curr = overrideList;
const SharedNumberFormat *snf = NULL;
UBool found = FALSE;
- while ( cur && !found ) {
- if ( cur->hash == nsNameHash ) {
- snf = cur->snf;
+ while ( curr && !found ) {
+ if ( curr->hash == nsNameHash ) {
+ snf = curr->snf;
found = TRUE;
}
- cur = cur->next;
+ curr = curr->next;
}
if (!found) {
@@ -1824,14 +1824,14 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
// Stealing am/pm value to use as our array index.
// It works out: am/midnight are both 0, pm/noon are both 1,
// 12 am is 12 midnight, and 12 pm is 12 noon.
- int32_t value = cal.get(UCAL_AM_PM, status);
+ int32_t val = cal.get(UCAL_AM_PM, status);
if (count <= 3) {
- toAppend = &fSymbols->fAbbreviatedDayPeriods[value];
+ toAppend = &fSymbols->fAbbreviatedDayPeriods[val];
} else if (count == 4 || count > 5) {
- toAppend = &fSymbols->fWideDayPeriods[value];
+ toAppend = &fSymbols->fWideDayPeriods[val];
} else { // count == 5
- toAppend = &fSymbols->fNarrowDayPeriods[value];
+ toAppend = &fSymbols->fNarrowDayPeriods[val];
}
}
@@ -2281,10 +2281,10 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
if (i+1 < fPattern.length()) {
// move to next pattern character
- UChar ch = fPattern.charAt(i+1);
+ UChar c = fPattern.charAt(i+1);
// check for whitespace
- if (PatternProps::isWhiteSpace(ch)) {
+ if (PatternProps::isWhiteSpace(c)) {
i++;
// Advance over run in pattern
while ((i+1)<fPattern.length() &&
@@ -3162,8 +3162,8 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
if (!strcmp(cal.getType(),"hebrew")) {
HebrewCalendar *hc = (HebrewCalendar*)&cal;
if (cal.isSet(UCAL_YEAR)) {
- UErrorCode status = U_ZERO_ERROR;
- if (!hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value >= 6) {
+ UErrorCode monthStatus = U_ZERO_ERROR;
+ if (!hc->isLeapYear(hc->get(UCAL_YEAR, monthStatus)) && value >= 6) {
cal.set(UCAL_MONTH, value);
} else {
cal.set(UCAL_MONTH, value - 1);
@@ -3571,21 +3571,21 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
static const UChar alt_sep = DateFormatSymbols::ALTERNATE_TIME_SEPARATOR;
// Try matching a time separator.
- int32_t count = 1;
+ int32_t count_sep = 1;
UnicodeString data[3];
fSymbols->getTimeSeparatorString(data[0]);
// Add the default, if different from the locale.
if (data[0].compare(&def_sep, 1) != 0) {
- data[count++].setTo(def_sep);
+ data[count_sep++].setTo(def_sep);
}
// If lenient, add also the alternate, if different from the locale.
if (isLenient() && data[0].compare(&alt_sep, 1) != 0) {
- data[count++].setTo(alt_sep);
+ data[count_sep++].setTo(alt_sep);
}
- return matchString(text, start, UCAL_FIELD_COUNT /* => nothing to set */, data, count, NULL, cal);
+ return matchString(text, start, UCAL_FIELD_COUNT /* => nothing to set */, data, count_sep, NULL, cal);
}
case UDAT_AM_PM_MIDNIGHT_NOON_FIELD:
@@ -3674,7 +3674,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
}
parseInt(*src, number, pos, allowNegative,currentNumberFormat);
if (pos.getIndex() != parseStart) {
- int32_t value = number.getLong();
+ int32_t val = number.getLong();
// Don't need suffix processing here (as in number processing at the beginning of the function);
// the new fields being handled as numeric values (month, weekdays, quarters) should not have suffixes.
@@ -3682,7 +3682,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status)) {
// Check the range of the value
int32_t bias = gFieldRangeBias[patternCharIndex];
- if (bias >= 0 && (value > cal.getMaximum(field) + bias || value < cal.getMinimum(field) + bias)) {
+ if (bias >= 0 && (val > cal.getMaximum(field) + bias || val < cal.getMinimum(field) + bias)) {
return -start;
}
}
@@ -3696,35 +3696,35 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
if (!strcmp(cal.getType(),"hebrew")) {
HebrewCalendar *hc = (HebrewCalendar*)&cal;
if (cal.isSet(UCAL_YEAR)) {
- UErrorCode status = U_ZERO_ERROR;
- if (!hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value >= 6) {
- cal.set(UCAL_MONTH, value);
+ UErrorCode monthStatus = U_ZERO_ERROR;
+ if (!hc->isLeapYear(hc->get(UCAL_YEAR, monthStatus)) && val >= 6) {
+ cal.set(UCAL_MONTH, val);
} else {
- cal.set(UCAL_MONTH, value - 1);
+ cal.set(UCAL_MONTH, val - 1);
}
} else {
- saveHebrewMonth = value;
+ saveHebrewMonth = val;
}
} else {
- cal.set(UCAL_MONTH, value - 1);
+ cal.set(UCAL_MONTH, val - 1);
}
break;
case UDAT_STANDALONE_MONTH_FIELD:
- cal.set(UCAL_MONTH, value - 1);
+ cal.set(UCAL_MONTH, val - 1);
break;
case UDAT_DOW_LOCAL_FIELD:
case UDAT_STANDALONE_DAY_FIELD:
- cal.set(UCAL_DOW_LOCAL, value);
+ cal.set(UCAL_DOW_LOCAL, val);
break;
case UDAT_QUARTER_FIELD:
case UDAT_STANDALONE_QUARTER_FIELD:
- cal.set(UCAL_MONTH, (value - 1) * 3);
+ cal.set(UCAL_MONTH, (val - 1) * 3);
break;
case UDAT_RELATED_YEAR_FIELD:
- cal.setRelatedYear(value);
+ cal.setRelatedYear(val);
break;
default:
- cal.set(field, value);
+ cal.set(field, val);
break;
}
return pos.getIndex();
@@ -3971,7 +3971,7 @@ SimpleDateFormat::setContext(UDisplayContext value, UErrorCode& status)
if (U_SUCCESS(status)) {
if ( fCapitalizationBrkIter == NULL && (value==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU || value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE) ) {
- UErrorCode status = U_ZERO_ERROR;
+ status = U_ZERO_ERROR;
fCapitalizationBrkIter = BreakIterator::createSentenceInstance(fLocale, status);
if (U_FAILURE(status)) {
delete fCapitalizationBrkIter;
diff --git a/deps/icu-small/source/i18n/timezone.cpp b/deps/icu-small/source/i18n/timezone.cpp
index f7f45c7d3e..dbf614469e 100644
--- a/deps/icu-small/source/i18n/timezone.cpp
+++ b/deps/icu-small/source/i18n/timezone.cpp
@@ -1031,8 +1031,8 @@ TimeZone::getEquivalentID(const UnicodeString& id, int32_t index) {
UResourceBundle *ares = ures_getByKey(top, kNAMES, NULL, &ec); // dereference Zones section
if (U_SUCCESS(ec)) {
int32_t idLen = 0;
- const UChar* id = ures_getStringByIndex(ares, zone, &idLen, &ec);
- result.fastCopyFrom(UnicodeString(TRUE, id, idLen));
+ const UChar* id2 = ures_getStringByIndex(ares, zone, &idLen, &ec);
+ result.fastCopyFrom(UnicodeString(TRUE, id2, idLen));
U_DEBUG_TZ_MSG(("gei(%d) -> %d, len%d, %s\n", index, zone, result.length(), u_errorName(ec)));
}
ures_close(ares);
@@ -1199,7 +1199,7 @@ TimeZone::getDisplayName(UBool daylight, EDisplayType style, const Locale& local
{
UErrorCode status = U_ZERO_ERROR;
UDate date = Calendar::getNow();
- UTimeZoneFormatTimeType timeType;
+ UTimeZoneFormatTimeType timeType = UTZFMT_TIME_TYPE_UNKNOWN;
int32_t offset;
if (style == GENERIC_LOCATION || style == LONG_GENERIC || style == SHORT_GENERIC) {
@@ -1612,7 +1612,7 @@ TimeZone::getWindowsID(const UnicodeString& id, UnicodeString& winid, UErrorCode
end = tzids + len;
hasNext = FALSE;
}
- if (canonicalID.compare(start, end - start) == 0) {
+ if (canonicalID.compare(start, static_cast<int32_t>(end - start)) == 0) {
winid = UnicodeString(ures_getKey(winzone), -1 , US_INV);
found = TRUE;
break;
@@ -1673,7 +1673,7 @@ TimeZone::getIDForWindowsID(const UnicodeString& winid, const char* region, Unic
if (end == NULL) {
id.setTo(tzids, -1);
} else {
- id.setTo(tzids, end - tzids);
+ id.setTo(tzids, static_cast<int32_t>(end - tzids));
}
gotID = TRUE;
}
diff --git a/deps/icu-small/source/i18n/transreg.cpp b/deps/icu-small/source/i18n/transreg.cpp
index 331f4efdeb..4884773faf 100644
--- a/deps/icu-small/source/i18n/transreg.cpp
+++ b/deps/icu-small/source/i18n/transreg.cpp
@@ -1330,12 +1330,12 @@ Transliterator* TransliteratorRegistry::instantiateEntry(const UnicodeString& ID
int32_t passNumber = 1;
for (int32_t i = 0; U_SUCCESS(status) && i < entry->u.dataVector->size(); i++) {
// TODO: Should passNumber be turned into a decimal-string representation (1 -> "1")?
- Transliterator* t = new RuleBasedTransliterator(UnicodeString(CompoundTransliterator::PASS_STRING) + UnicodeString(passNumber++),
+ Transliterator* tl = new RuleBasedTransliterator(UnicodeString(CompoundTransliterator::PASS_STRING) + UnicodeString(passNumber++),
(TransliterationRuleData*)(entry->u.dataVector->elementAt(i)), FALSE);
- if (t == 0)
+ if (tl == 0)
status = U_MEMORY_ALLOCATION_ERROR;
else
- rbts->addElement(t, status);
+ rbts->addElement(tl, status);
}
if (U_FAILURE(status)) {
delete rbts;
diff --git a/deps/icu-small/source/i18n/tzfmt.cpp b/deps/icu-small/source/i18n/tzfmt.cpp
index 69da4667bc..df4dec1feb 100644
--- a/deps/icu-small/source/i18n/tzfmt.cpp
+++ b/deps/icu-small/source/i18n/tzfmt.cpp
@@ -2648,12 +2648,12 @@ TimeZoneFormat::checkAbuttingHoursAndMinutes() {
UVector *items = fGMTOffsetPatternItems[type];
for (int32_t i = 0; i < items->size(); i++) {
const GMTOffsetField* item = (GMTOffsetField*)items->elementAt(i);
- GMTOffsetField::FieldType type = item->getType();
- if (type != GMTOffsetField::TEXT) {
+ GMTOffsetField::FieldType fieldType = item->getType();
+ if (fieldType != GMTOffsetField::TEXT) {
if (afterH) {
fAbuttingOffsetHoursAndMinutes = TRUE;
break;
- } else if (type == GMTOffsetField::HOUR) {
+ } else if (fieldType == GMTOffsetField::HOUR) {
afterH = TRUE;
}
} else if (afterH) {
diff --git a/deps/icu-small/source/i18n/tzgnames.cpp b/deps/icu-small/source/i18n/tzgnames.cpp
index c2e685272e..5f5b7db302 100644
--- a/deps/icu-small/source/i18n/tzgnames.cpp
+++ b/deps/icu-small/source/i18n/tzgnames.cpp
@@ -407,7 +407,7 @@ TZGNCore::initialize(const Locale& locale, UErrorCode& status) {
// target region
const char* region = fLocale.getCountry();
- int32_t regionLen = uprv_strlen(region);
+ int32_t regionLen = static_cast<int32_t>(uprv_strlen(region));
if (regionLen == 0) {
char loc[ULOC_FULLNAME_CAPACITY];
uloc_addLikelySubtags(fLocale.getName(), loc, sizeof(loc), &status);
diff --git a/deps/icu-small/source/i18n/tznames.cpp b/deps/icu-small/source/i18n/tznames.cpp
index 689fdeb091..5a79c22aac 100644
--- a/deps/icu-small/source/i18n/tznames.cpp
+++ b/deps/icu-small/source/i18n/tznames.cpp
@@ -87,7 +87,7 @@ static void sweepCache() {
const UHashElement* elem;
double now = (double)uprv_getUTCtime();
- while ((elem = uhash_nextElement(gTimeZoneNamesCache, &pos))) {
+ while ((elem = uhash_nextElement(gTimeZoneNamesCache, &pos)) != 0) {
TimeZoneNamesCacheEntry *entry = (TimeZoneNamesCacheEntry *)elem->value.pointer;
if (entry->refCount <= 0 && (now - entry->lastAccess) > CACHE_EXPIRATION) {
// delete this entry
diff --git a/deps/icu-small/source/i18n/tznames_impl.cpp b/deps/icu-small/source/i18n/tznames_impl.cpp
index ef04b31c13..6a303ea4a0 100644
--- a/deps/icu-small/source/i18n/tznames_impl.cpp
+++ b/deps/icu-small/source/i18n/tznames_impl.cpp
@@ -1285,7 +1285,7 @@ static void mergeTimeZoneKey(const UnicodeString& mzID, char* result) {
char mzIdChar[ZID_KEY_MAX + 1];
int32_t keyLen;
- int32_t prefixLen = uprv_strlen(gMZPrefix);
+ int32_t prefixLen = static_cast<int32_t>(uprv_strlen(gMZPrefix));
keyLen = mzID.extract(0, mzID.length(), mzIdChar, ZID_KEY_MAX + 1, US_INV);
uprv_memcpy((void *)result, (void *)gMZPrefix, prefixLen);
uprv_memcpy((void *)(result + prefixLen), (void *)mzIdChar, keyLen);
@@ -1453,7 +1453,7 @@ struct TimeZoneNamesImpl::ZoneStringsLoader : public ResourceSink {
virtual ~ZoneStringsLoader();
void* createKey(const char* key, UErrorCode& status) {
- int32_t len = sizeof(char) * (uprv_strlen(key) + 1);
+ int32_t len = sizeof(char) * (static_cast<int32_t>(uprv_strlen(key)) + 1);
char* newKey = (char*) uprv_malloc(len);
if (newKey == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
@@ -1469,7 +1469,7 @@ struct TimeZoneNamesImpl::ZoneStringsLoader : public ResourceSink {
}
UnicodeString mzIDFromKey(const char* key) {
- return UnicodeString(key + MZ_PREFIX_LEN, uprv_strlen(key) - MZ_PREFIX_LEN, US_INV);
+ return UnicodeString(key + MZ_PREFIX_LEN, static_cast<int32_t>(uprv_strlen(key)) - MZ_PREFIX_LEN, US_INV);
}
UnicodeString tzIDFromKey(const char* key) {
@@ -1944,8 +1944,8 @@ TZDBNameSearchHandler::handleMatch(int32_t matchLength, const CharacterNode *nod
// metazone mapping for "CST" is America_Central,
// but if region is one of CN/MO/TW, "CST" is parsed
// as metazone China (China Standard Time).
- for (int32_t i = 0; i < ninfo->nRegions; i++) {
- const char *region = ninfo->parseRegions[i];
+ for (int32_t j = 0; j < ninfo->nRegions; j++) {
+ const char *region = ninfo->parseRegions[j];
if (uprv_strcmp(fRegion, region) == 0) {
match = ninfo;
matchRegion = TRUE;
@@ -2059,7 +2059,7 @@ static void U_CALLCONV prepareFind(UErrorCode &status) {
const UnicodeString *mzID;
StringEnumeration *mzIDs = TimeZoneNamesImpl::_getAvailableMetaZoneIDs(status);
if (U_SUCCESS(status)) {
- while ((mzID = mzIDs->snext(status)) && U_SUCCESS(status)) {
+ while ((mzID = mzIDs->snext(status)) != 0 && U_SUCCESS(status)) {
const TZDBNames *names = TZDBTimeZoneNames::getMetaZoneNames(*mzID, status);
if (U_FAILURE(status)) {
break;
@@ -2128,7 +2128,7 @@ TZDBTimeZoneNames::TZDBTimeZoneNames(const Locale& locale)
: fLocale(locale) {
UBool useWorld = TRUE;
const char* region = fLocale.getCountry();
- int32_t regionLen = uprv_strlen(region);
+ int32_t regionLen = static_cast<int32_t>(uprv_strlen(region));
if (regionLen == 0) {
UErrorCode status = U_ZERO_ERROR;
char loc[ULOC_FULLNAME_CAPACITY];
diff --git a/deps/icu-small/source/i18n/ucln_in.h b/deps/icu-small/source/i18n/ucln_in.h
index 318eafc143..4c13b9ffcb 100644
--- a/deps/icu-small/source/i18n/ucln_in.h
+++ b/deps/icu-small/source/i18n/ucln_in.h
@@ -32,6 +32,7 @@ typedef enum ECleanupI18NType {
UCLN_I18N_SPOOFDATA,
UCLN_I18N_TRANSLITERATOR,
UCLN_I18N_REGEX,
+ UCLN_I18N_JAPANESE_CALENDAR,
UCLN_I18N_ISLAMIC_CALENDAR,
UCLN_I18N_CHINESE_CALENDAR,
UCLN_I18N_HEBREW_CALENDAR,
@@ -58,6 +59,7 @@ typedef enum ECleanupI18NType {
UCLN_I18N_GENDERINFO,
UCLN_I18N_CDFINFO,
UCLN_I18N_REGION,
+ UCLN_I18N_LIST_FORMATTER,
UCLN_I18N_COUNT /* This must be last */
} ECleanupI18NType;
diff --git a/deps/icu-small/source/i18n/ucol_res.cpp b/deps/icu-small/source/i18n/ucol_res.cpp
index 76975ecc01..56ed5b3c19 100644
--- a/deps/icu-small/source/i18n/ucol_res.cpp
+++ b/deps/icu-small/source/i18n/ucol_res.cpp
@@ -400,11 +400,11 @@ CollationLoader::loadFromData(UErrorCode &errorCode) {
// Try to fetch the optional rules string.
{
UErrorCode internalErrorCode = U_ZERO_ERROR;
- int32_t length;
- const UChar *s = ures_getStringByKey(data, "Sequence", &length,
+ int32_t len;
+ const UChar *s = ures_getStringByKey(data, "Sequence", &len,
&internalErrorCode);
if(U_SUCCESS(internalErrorCode)) {
- t->rules.setTo(TRUE, s, length);
+ t->rules.setTo(TRUE, s, len);
}
}
@@ -426,10 +426,10 @@ CollationLoader::loadFromData(UErrorCode &errorCode) {
LocalUResourceBundlePointer def(
ures_getByKeyWithFallback(actualBundle.getAlias(), "collations/default", NULL,
&internalErrorCode));
- int32_t length;
- const UChar *s = ures_getString(def.getAlias(), &length, &internalErrorCode);
- if(U_SUCCESS(internalErrorCode) && length < UPRV_LENGTHOF(defaultType)) {
- u_UCharsToChars(s, defaultType, length + 1);
+ int32_t len;
+ const UChar *s = ures_getString(def.getAlias(), &len, &internalErrorCode);
+ if(U_SUCCESS(internalErrorCode) && len < UPRV_LENGTHOF(defaultType)) {
+ u_UCharsToChars(s, defaultType, len + 1);
} else {
uprv_strcpy(defaultType, "standard");
}
diff --git a/deps/icu-small/source/i18n/udat.cpp b/deps/icu-small/source/i18n/udat.cpp
index d086067c03..b7d85cc179 100644
--- a/deps/icu-small/source/i18n/udat.cpp
+++ b/deps/icu-small/source/i18n/udat.cpp
@@ -603,7 +603,7 @@ udat_getSymbols(const UDateFormat *fmt,
} else {
return -1;
}
- int32_t count;
+ int32_t count = 0;
const UnicodeString *res = NULL;
switch(type) {
diff --git a/deps/icu-small/source/i18n/ulistformatter.cpp b/deps/icu-small/source/i18n/ulistformatter.cpp
new file mode 100644
index 0000000000..c140c784b5
--- /dev/null
+++ b/deps/icu-small/source/i18n/ulistformatter.cpp
@@ -0,0 +1,91 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/*
+*****************************************************************************************
+* Copyright (C) 2015, International Business Machines
+* Corporation and others. All Rights Reserved.
+*****************************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/ulistformatter.h"
+#include "unicode/listformatter.h"
+#include "unicode/localpointer.h"
+#include "cmemory.h"
+
+U_NAMESPACE_USE
+
+U_CAPI UListFormatter* U_EXPORT2
+ulistfmt_open(const char* locale,
+ UErrorCode* status)
+{
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+ LocalPointer<ListFormatter> listfmt(ListFormatter::createInstance(Locale(locale), *status));
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+ return (UListFormatter*)listfmt.orphan();
+}
+
+
+U_CAPI void U_EXPORT2
+ulistfmt_close(UListFormatter *listfmt)
+{
+ delete (ListFormatter*)listfmt;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+ulistfmt_format(const UListFormatter* listfmt,
+ const UChar* const strings[],
+ const int32_t * stringLengths,
+ int32_t stringCount,
+ UChar* result,
+ int32_t resultCapacity,
+ UErrorCode* status)
+{
+ if (U_FAILURE(*status)) {
+ return -1;
+ }
+ if (stringCount < 0 || (strings == NULL && stringCount > 0) || ((result == NULL)? resultCapacity != 0 : resultCapacity < 0)) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return -1;
+ }
+ UnicodeString ustringsStackBuf[4];
+ UnicodeString* ustrings = ustringsStackBuf;
+ if (stringCount > UPRV_LENGTHOF(ustringsStackBuf)) {
+ ustrings = new UnicodeString[stringCount];
+ if (ustrings == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return -1;
+ }
+ }
+ if (stringLengths == NULL) {
+ for (int32_t stringIndex = 0; stringIndex < stringCount; stringIndex++) {
+ ustrings[stringIndex].setTo(TRUE, strings[stringIndex], -1);
+ }
+ } else {
+ for (int32_t stringIndex = 0; stringIndex < stringCount; stringIndex++) {
+ ustrings[stringIndex].setTo(stringLengths[stringIndex] < 0, strings[stringIndex], stringLengths[stringIndex]);
+ }
+ }
+ UnicodeString res;
+ if (result != NULL) {
+ // NULL destination for pure preflighting: empty dummy string
+ // otherwise, alias the destination buffer (copied from udat_format)
+ res.setTo(result, 0, resultCapacity);
+ }
+ ((const ListFormatter*)listfmt)->format( ustrings, stringCount, res, *status );
+ if (ustrings != ustringsStackBuf) {
+ delete[] ustrings;
+ }
+ return res.extract(result, resultCapacity, *status);
+}
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/deps/icu-small/source/i18n/ulocdata.cpp b/deps/icu-small/source/i18n/ulocdata.cpp
index 551f6c64ed..f651fee6fc 100644
--- a/deps/icu-small/source/i18n/ulocdata.cpp
+++ b/deps/icu-small/source/i18n/ulocdata.cpp
@@ -372,7 +372,7 @@ ulocdata_getLocaleSeparator(ULocaleData *uld,
p1=u_strstr(separator, sub1);
if (p0!=NULL && p1!=NULL && p0<=p1) {
separator = (const UChar *)p0 + subLen;
- len = p1 - separator;
+ len = static_cast<int32_t>(p1 - separator);
/* Desired separator is no longer zero-terminated; handle that if necessary */
if (len < resultCapacity) {
u_strncpy(result, separator, len);
diff --git a/deps/icu-small/source/i18n/unicode/alphaindex.h b/deps/icu-small/source/i18n/unicode/alphaindex.h
index 54bd29ff88..4ebdf1cc56 100644
--- a/deps/icu-small/source/i18n/unicode/alphaindex.h
+++ b/deps/icu-small/source/i18n/unicode/alphaindex.h
@@ -266,6 +266,8 @@ public:
* Use getBucket() to get the bucket's properties.
*
* @param name the string to be sorted into an index bucket
+ * @param errorCode Error code, will be set with the reason if the
+ * operation fails.
* @return the bucket number for the name
* @stable ICU 51
*/
@@ -377,9 +379,10 @@ public:
/**
- * Get the default label used for abbreviated buckets <i>between</i> other index characters.
- * For example, consider the labels when Latin and Greek are used:
- * X Y Z ... &#x0391; &#x0392; &#x0393;.
+ * Get the default label used for abbreviated buckets *between* other index characters.
+ * For example, consider the labels when Latin (X Y Z) and Greek (Α Β Γ) are used:
+ *
+ * X Y Z ... Α Β Γ.
*
* @return inflow label
* @stable ICU 4.8
@@ -700,6 +703,7 @@ public:
/**
* A (name, data) pair, to be sorted by name into one of the index buckets.
* The user data is not used by the index implementation.
+ * \cond
* @internal
*/
struct Record: public UMemory {
@@ -708,6 +712,7 @@ public:
Record(const UnicodeString &name, const void *data);
~Record();
};
+ /** \endcond */
#endif /* U_HIDE_INTERNAL_API */
private:
diff --git a/deps/icu-small/source/i18n/unicode/calendar.h b/deps/icu-small/source/i18n/unicode/calendar.h
index 48021534b4..023cf053f2 100644
--- a/deps/icu-small/source/i18n/unicode/calendar.h
+++ b/deps/icu-small/source/i18n/unicode/calendar.h
@@ -52,83 +52,64 @@ typedef int32_t UFieldResolutionTable[12][8];
class BasicTimeZone;
/**
- * <code>Calendar</code> is an abstract base class for converting between
- * a <code>UDate</code> object and a set of integer fields such as
- * <code>YEAR</code>, <code>MONTH</code>, <code>DAY</code>, <code>HOUR</code>,
- * and so on. (A <code>UDate</code> object represents a specific instant in
+ * `Calendar` is an abstract base class for converting between
+ * a `UDate` object and a set of integer fields such as
+ * `YEAR`, `MONTH`, `DAY`, `HOUR`, and so on.
+ * (A `UDate` object represents a specific instant in
* time with millisecond precision. See UDate
- * for information about the <code>UDate</code> class.)
+ * for information about the `UDate` class.)
*
- * <p>
- * Subclasses of <code>Calendar</code> interpret a <code>UDate</code>
+ * Subclasses of `Calendar` interpret a `UDate`
* according to the rules of a specific calendar system.
- * The most commonly used subclass of <code>Calendar</code> is
- * <code>GregorianCalendar</code>. Other subclasses could represent
+ * The most commonly used subclass of `Calendar` is
+ * `GregorianCalendar`. Other subclasses could represent
* the various types of lunar calendars in use in many parts of the world.
*
- * <p>
- * <b>NOTE</b>: (ICU 2.6) The subclass interface should be considered unstable
- * - it WILL change.
+ * **NOTE**: (ICU 2.6) The subclass interface should be considered unstable -
+ * it WILL change.
*
- * <p>
- * Like other locale-sensitive classes, <code>Calendar</code> provides a
- * static method, <code>createInstance</code>, for getting a generally useful
- * object of this type. <code>Calendar</code>'s <code>createInstance</code> method
- * returns the appropriate <code>Calendar</code> subclass whose
+ * Like other locale-sensitive classes, `Calendar` provides a
+ * static method, `createInstance`, for getting a generally useful
+ * object of this type. `Calendar`'s `createInstance` method
+ * returns the appropriate `Calendar` subclass whose
* time fields have been initialized with the current date and time:
- * \htmlonly<blockquote>\endhtmlonly
- * <pre>
- * Calendar *rightNow = Calendar::createInstance(errCode);
- * </pre>
- * \htmlonly</blockquote>\endhtmlonly
*
- * <p>
- * A <code>Calendar</code> object can produce all the time field values
+ * Calendar *rightNow = Calendar::createInstance(errCode);
+ *
+ * A `Calendar` object can produce all the time field values
* needed to implement the date-time formatting for a particular language
* and calendar style (for example, Japanese-Gregorian, Japanese-Traditional).
*
- * <p>
- * When computing a <code>UDate</code> from time fields, some special circumstances
+ * When computing a `UDate` from time fields, some special circumstances
* may arise: there may be insufficient information to compute the
- * <code>UDate</code> (such as only year and month but no day in the month),
+ * `UDate` (such as only year and month but no day in the month),
* there may be inconsistent information (such as "Tuesday, July 15, 1996"
* -- July 15, 1996 is actually a Monday), or the input time might be ambiguous
* because of time zone transition.
*
- * <p>
- * <strong>Insufficient information.</strong> The calendar will use default
+ * **Insufficient information.** The calendar will use default
* information to specify the missing fields. This may vary by calendar; for
* the Gregorian calendar, the default for a field is the same as that of the
* start of the epoch: i.e., YEAR = 1970, MONTH = JANUARY, DATE = 1, etc.
*
- * <p>
- * <strong>Inconsistent information.</strong> If fields conflict, the calendar
+ * **Inconsistent information.** If fields conflict, the calendar
* will give preference to fields set more recently. For example, when
* determining the day, the calendar will look for one of the following
* combinations of fields. The most recent combination, as determined by the
* most recently set single field, will be used.
*
- * \htmlonly<blockquote>\endhtmlonly
- * <pre>
- * MONTH + DAY_OF_MONTH
- * MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
- * MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
- * DAY_OF_YEAR
- * DAY_OF_WEEK + WEEK_OF_YEAR
- * </pre>
- * \htmlonly</blockquote>\endhtmlonly
+ * MONTH + DAY_OF_MONTH
+ * MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
+ * MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
+ * DAY_OF_YEAR
+ * DAY_OF_WEEK + WEEK_OF_YEAR
*
* For the time of day:
*
- * \htmlonly<blockquote>\endhtmlonly
- * <pre>
- * HOUR_OF_DAY
- * AM_PM + HOUR
- * </pre>
- * \htmlonly</blockquote>\endhtmlonly
+ * HOUR_OF_DAY
+ * AM_PM + HOUR
*
- * <p>
- * <strong>Ambiguous Wall Clock Time.</strong> When time offset from UTC has
+ * **Ambiguous Wall Clock Time.** When time offset from UTC has
* changed, it produces an ambiguous time slot around the transition. For example,
* many US locations observe daylight saving time. On the date switching to daylight
* saving time in US, wall clock time jumps from 12:59 AM (standard) to 2:00 AM
@@ -138,64 +119,66 @@ class BasicTimeZone;
* In this example, 1:30 AM is interpreted as 1:30 AM standard time (non-exist),
* so the final result will be 2:30 AM daylight time.
*
- * <p>On the date switching back to standard time, wall clock time is moved back one
+ * On the date switching back to standard time, wall clock time is moved back one
* hour at 2:00 AM. So wall clock time from 1:00 AM to 1:59 AM occur twice. In this
* case, the ICU Calendar resolves the time using the UTC offset after the transition
* by default. For example, 1:30 AM on the date is resolved as 1:30 AM standard time.
*
- * <p>Ambiguous wall clock time resolution behaviors can be customized by Calendar APIs
+ * Ambiguous wall clock time resolution behaviors can be customized by Calendar APIs
* {@link #setRepeatedWallTimeOption} and {@link #setSkippedWallTimeOption}.
* These methods are available in ICU 49 or later versions.
*
- * <p>
- * <strong>Note:</strong> for some non-Gregorian calendars, different
+ * **Note:** for some non-Gregorian calendars, different
* fields may be necessary for complete disambiguation. For example, a full
- * specification of the historial Arabic astronomical calendar requires year,
- * month, day-of-month <em>and</em> day-of-week in some cases.
+ * specification of the historical Arabic astronomical calendar requires year,
+ * month, day-of-month *and* day-of-week in some cases.
*
- * <p>
- * <strong>Note:</strong> There are certain possible ambiguities in
+ * **Note:** There are certain possible ambiguities in
* interpretation of certain singular times, which are resolved in the
* following ways:
- * <ol>
- * <li> 24:00:00 "belongs" to the following day. That is,
- * 23:59 on Dec 31, 1969 &lt; 24:00 on Jan 1, 1970 &lt; 24:01:00 on Jan 1, 1970
*
- * <li> Although historically not precise, midnight also belongs to "am",
- * and noon belongs to "pm", so on the same day,
- * 12:00 am (midnight) &lt; 12:01 am, and 12:00 pm (noon) &lt; 12:01 pm
- * </ol>
+ * 1. 24:00:00 "belongs" to the following day. That is,
+ * 23:59 on Dec 31, 1969 < 24:00 on Jan 1, 1970 < 24:01:00 on Jan 1, 1970
+ * 2. Although historically not precise, midnight also belongs to "am",
+ * and noon belongs to "pm", so on the same day,
+ * 12:00 am (midnight) < 12:01 am, and 12:00 pm (noon) < 12:01 pm
*
- * <p>
* The date or time format strings are not part of the definition of a
* calendar, as those must be modifiable or overridable by the user at
- * runtime. Use {@link DateFormat}
- * to format dates.
+ * runtime. Use `DateFormat` to format dates.
*
- * <p>
- * <code>Calendar</code> provides an API for field "rolling", where fields
+ * `Calendar` provides an API for field "rolling", where fields
* can be incremented or decremented, but wrap around. For example, rolling the
- * month up in the date <code>December 12, <b>1996</b></code> results in
- * <code>January 12, <b>1996</b></code>.
+ * month up in the date December 12, **1996** results in
+ * January 12, **1996**.
*
- * <p>
- * <code>Calendar</code> also provides a date arithmetic function for
+ * `Calendar` also provides a date arithmetic function for
* adding the specified (signed) amount of time to a particular time field.
- * For example, subtracting 5 days from the date <code>September 12, 1996</code>
- * results in <code>September 7, 1996</code>.
+ * For example, subtracting 5 days from the date `September 12, 1996`
+ * results in `September 7, 1996`.
*
- * <p><big><b>Supported range</b></big>
+ * ***Supported range***
*
- * <p>The allowable range of <code>Calendar</code> has been
- * narrowed. <code>GregorianCalendar</code> used to attempt to support
- * the range of dates with millisecond values from
- * <code>Long.MIN_VALUE</code> to <code>Long.MAX_VALUE</code>.
- * The new <code>Calendar</code> protocol specifies the
+ * The allowable range of `Calendar` has been narrowed. `GregorianCalendar` used
+ * to attempt to support the range of dates with millisecond values from
+ * `Long.MIN_VALUE` to `Long.MAX_VALUE`. The new `Calendar` protocol specifies the
* maximum range of supportable dates as those having Julian day numbers
- * of <code>-0x7F000000</code> to <code>+0x7F000000</code>. This
- * corresponds to years from ~5,800,000 BCE to ~5,800,000 CE. Programmers
- * should use the protected constants in <code>Calendar</code> to
- * specify an extremely early or extremely late date.</p>
+ * of `-0x7F000000` to `+0x7F000000`. This corresponds to years from ~5,800,000 BCE
+ * to ~5,800,000 CE. Programmers should use the protected constants in `Calendar` to
+ * specify an extremely early or extremely late date.
+ *
+ * <p>
+ * The Japanese calendar uses a combination of era name and year number.
+ * When an emperor of Japan abdicates and a new emperor ascends the throne,
+ * a new era is declared and year number is reset to 1. Even if the date of
+ * abdication is scheduled ahead of time, the new era name might not be
+ * announced until just before the date. In such case, ICU4C may include
+ * a start date of future era without actual era name, but not enabled
+ * by default. ICU4C users who want to test the behavior of the future era
+ * can enable the tentative era by:
+ * <ul>
+ * <li>Environment variable <code>ICU_ENABLE_TENTATIVE_ERA=true</code>.</li>
+ * </ul>
*
* @stable ICU 2.0
*/
@@ -903,7 +886,7 @@ public:
/**
* Sets the behavior for handling wall time repeating multiple times
* at negative time zone offset transitions. For example, 1:30 AM on
- * November 6, 2011 in US Eastern time (Ameirca/New_York) occurs twice;
+ * November 6, 2011 in US Eastern time (America/New_York) occurs twice;
* 1:30 AM EDT, then 1:30 AM EST one hour later. When <code>UCAL_WALLTIME_FIRST</code>
* is used, the wall time 1:30AM in this example will be interpreted as 1:30 AM EDT
* (first occurrence). When <code>UCAL_WALLTIME_LAST</code> is used, it will be
@@ -1718,9 +1701,7 @@ protected:
/**
* Validate a single field of this calendar. Subclasses should
* override this method to validate any calendar-specific fields.
- * Generic fields can be handled by
- * <code>Calendar::validateField()</code>.
- * @see #validateField(int, int, int, int&)
+ * Generic fields can be handled by `Calendar::validateField()`.
* @internal
*/
virtual void validateField(UCalendarDateFields field, UErrorCode &status);
@@ -2171,7 +2152,7 @@ private:
TimeZone* fZone;
/**
- * Option for rpeated wall time
+ * Option for repeated wall time
* @see #setRepeatedWallTimeOption
*/
UCalendarWallTimeOption fRepeatedWallTime;
@@ -2456,7 +2437,7 @@ private:
BasicTimeZone* getBasicTimeZone() const;
/**
- * Find the previous zone transtion near the given time.
+ * Find the previous zone transition near the given time.
* @param base The base time, inclusive
* @param transitionTime Receives the result time
* @param status The error status
diff --git a/deps/icu-small/source/i18n/unicode/coll.h b/deps/icu-small/source/i18n/unicode/coll.h
index d03570509e..653434f54c 100644
--- a/deps/icu-small/source/i18n/unicode/coll.h
+++ b/deps/icu-small/source/i18n/unicode/coll.h
@@ -235,16 +235,16 @@ public:
* Returns TRUE if "other" is the same as "this".
*
* The base class implementation returns TRUE if "other" has the same type/class as "this":
- * <code>typeid(*this) == typeid(other)</code>.
+ * `typeid(*this) == typeid(other)`.
*
* Subclass implementations should do something like the following:
- * <pre>
- * if (this == &other) { return TRUE; }
- * if (!Collator::operator==(other)) { return FALSE; } // not the same class
*
- * const MyCollator &o = (const MyCollator&)other;
- * (compare this vs. o's subclass fields)
- * </pre>
+ * if (this == &other) { return TRUE; }
+ * if (!Collator::operator==(other)) { return FALSE; } // not the same class
+ *
+ * const MyCollator &o = (const MyCollator&)other;
+ * (compare this vs. o's subclass fields)
+ *
* @param other Collator object to be compared
* @return TRUE if other is the same as this.
* @stable ICU 2.0
diff --git a/deps/icu-small/source/i18n/unicode/compactdecimalformat.h b/deps/icu-small/source/i18n/unicode/compactdecimalformat.h
index 7dc92f6100..9c1e9183f4 100644
--- a/deps/icu-small/source/i18n/unicode/compactdecimalformat.h
+++ b/deps/icu-small/source/i18n/unicode/compactdecimalformat.h
@@ -30,30 +30,31 @@ U_NAMESPACE_BEGIN
class PluralRules;
/**
- * <p><strong>IMPORTANT:</strong> New users are strongly encouraged to see if
+ * **IMPORTANT:** New users are strongly encouraged to see if
* numberformatter.h fits their use case. Although not deprecated, this header
* is provided for backwards compatibility only.
- * <hr/>
+ *
+ * -----------------------------------------------------------------------------
*
* The CompactDecimalFormat produces abbreviated numbers, suitable for display in
* environments will limited real estate. For example, 'Hits: 1.2B' instead of
* 'Hits: 1,200,000,000'. The format will be appropriate for the given language,
* such as "1,2 Mrd." for German.
- * <p>
+ *
* For numbers under 1000 trillion (under 10^15, such as 123,456,789,012,345),
* the result will be short for supported languages. However, the result may
* sometimes exceed 7 characters, such as when there are combining marks or thin
* characters. In such cases, the visual width in fonts should still be short.
- * <p>
+ *
* By default, there are 3 significant digits. After creation, if more than
* three significant digits are set (with setMaximumSignificantDigits), or if a
* fixed number of digits are set (with setMaximumIntegerDigits or
* setMaximumFractionDigits), then result may be wider.
- * <p>
+ *
* At this time, parsing is not supported, and will produce a U_UNSUPPORTED_ERROR.
* Resetting the pattern prefixes or suffixes is not supported; the method calls
* are ignored.
- * <p>
+ *
* @stable ICU 51
*/
class U_I18N_API CompactDecimalFormat : public DecimalFormat {
@@ -61,9 +62,9 @@ public:
/**
* Returns a compact decimal instance for specified locale.
- * <p>
- * <strong>NOTE:</strong> New users are strongly encouraged to use
- * {@link NumberFormatter} instead of NumberFormat.
+ *
+ * **NOTE:** New users are strongly encouraged to use
+ * `number::NumberFormatter` instead of NumberFormat.
* @param inLocale the given locale.
* @param style whether to use short or long style.
* @param status error code returned here.
diff --git a/deps/icu-small/source/i18n/unicode/currpinf.h b/deps/icu-small/source/i18n/unicode/currpinf.h
index 1a327c5bae..80b0462513 100644
--- a/deps/icu-small/source/i18n/unicode/currpinf.h
+++ b/deps/icu-small/source/i18n/unicode/currpinf.h
@@ -2,7 +2,7 @@
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
- * Copyright (C) 2009-2015, International Business Machines Corporation and *
+ * Copyright (C) 2009-2015, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@@ -240,18 +240,27 @@ private:
/*
* The plural rule is used to format currency plural name,
* for example: "3.00 US Dollars".
- * If there are 3 currency signs in the currency patttern,
+ * If there are 3 currency signs in the currency pattern,
* the 3 currency signs will be replaced by currency plural name.
*/
PluralRules* fPluralRules;
// locale
Locale* fLocale;
+
+private:
+ /**
+ * An internal status variable used to indicate that the object is in an 'invalid' state.
+ * Used by copy constructor, the assignment operator and the clone method.
+ */
+ UErrorCode fInternalStatus;
};
inline UBool
-CurrencyPluralInfo::operator!=(const CurrencyPluralInfo& info) const { return !operator==(info); }
+CurrencyPluralInfo::operator!=(const CurrencyPluralInfo& info) const {
+ return !operator==(info);
+}
U_NAMESPACE_END
diff --git a/deps/icu-small/source/i18n/unicode/currunit.h b/deps/icu-small/source/i18n/unicode/currunit.h
index d5bc4aa6d6..48cadc10b7 100644
--- a/deps/icu-small/source/i18n/unicode/currunit.h
+++ b/deps/icu-small/source/i18n/unicode/currunit.h
@@ -38,7 +38,7 @@ class U_I18N_API CurrencyUnit: public MeasureUnit {
public:
/**
* Default constructor. Initializes currency code to "XXX" (no currency).
- * @draft ICU 60
+ * @stable ICU 60
*/
CurrencyUnit();
@@ -59,17 +59,15 @@ class U_I18N_API CurrencyUnit: public MeasureUnit {
*/
CurrencyUnit(const CurrencyUnit& other);
-#ifndef U_HIDE_DRAFT_API
/**
* Copy constructor from MeasureUnit. This constructor allows you to
* restore a CurrencyUnit that was sliced to MeasureUnit.
*
* @param measureUnit The MeasureUnit to copy from.
* @param ec Set to a failing value if the MeasureUnit is not a currency.
- * @draft ICU 60
+ * @stable ICU 60
*/
CurrencyUnit(const MeasureUnit& measureUnit, UErrorCode &ec);
-#endif /* U_HIDE_DRAFT_API */
/**
* Assignment operator
diff --git a/deps/icu-small/source/i18n/unicode/datefmt.h b/deps/icu-small/source/i18n/unicode/datefmt.h
index c895183931..13c63d9376 100644
--- a/deps/icu-small/source/i18n/unicode/datefmt.h
+++ b/deps/icu-small/source/i18n/unicode/datefmt.h
@@ -43,13 +43,17 @@ U_NAMESPACE_BEGIN
class TimeZone;
class DateTimePatternGenerator;
-// explicit template instantiation. see digitlst.h
-// (When building DLLs for Windows this is required.)
-#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
+/**
+ * \cond
+ * Export an explicit template instantiation. (See digitlst.h, datefmt.h, and others.)
+ * (When building DLLs for Windows this is required.)
+ */
+#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN && !defined(U_IN_DOXYGEN)
template class U_I18N_API EnumSet<UDateFormatBooleanAttribute,
0,
UDAT_BOOLEAN_ATTRIBUTE_COUNT>;
#endif
+/** \endcond */
/**
* DateFormat is an abstract class for a family of classes that convert dates and
diff --git a/deps/icu-small/source/i18n/unicode/dcfmtsym.h b/deps/icu-small/source/i18n/unicode/dcfmtsym.h
index 2f824cec30..55e3d8a6b3 100644
--- a/deps/icu-small/source/i18n/unicode/dcfmtsym.h
+++ b/deps/icu-small/source/i18n/unicode/dcfmtsym.h
@@ -181,7 +181,6 @@ public:
*/
DecimalFormatSymbols(const Locale& locale, UErrorCode& status);
-#ifndef U_HIDE_DRAFT_API
/**
* Creates a DecimalFormatSymbols instance for the given locale with digits and symbols
* corresponding to the given NumberingSystem.
@@ -196,10 +195,9 @@ public:
* @param ns The numbering system.
* @param status Input/output parameter, set to success or
* failure code upon return.
- * @draft ICU 60
+ * @stable ICU 60
*/
DecimalFormatSymbols(const Locale& locale, const NumberingSystem& ns, UErrorCode& status);
-#endif /* U_HIDE_DRAFT_API */
/**
* Create a DecimalFormatSymbols object for the default locale.
@@ -406,7 +404,7 @@ public:
* returning a const reference to one of the symbol strings.
* The returned reference becomes invalid when the symbol is changed
* or when the DecimalFormatSymbols are destroyed.
- * Note: moved #ifndef U_HIDE_INTERNAL_API after this, since this is needed for inline in DecimalFormat
+ * Note: moved \#ifndef U_HIDE_INTERNAL_API after this, since this is needed for inline in DecimalFormat
*
* This is not currently stable API, but if you think it should be stable,
* post a comment on the following ticket and the ICU team will take a look:
@@ -531,7 +529,7 @@ inline const UnicodeString& DecimalFormatSymbols::getConstDigitSymbol(int32_t di
ENumberFormatSymbol key = static_cast<ENumberFormatSymbol>(kOneDigitSymbol + digit - 1);
return fSymbols[key];
}
-#endif
+#endif /* U_HIDE_INTERNAL_API */
// -------------------------------------
diff --git a/deps/icu-small/source/i18n/unicode/decimfmt.h b/deps/icu-small/source/i18n/unicode/decimfmt.h
index 3747f510f7..b3a5cc0495 100644
--- a/deps/icu-small/source/i18n/unicode/decimfmt.h
+++ b/deps/icu-small/source/i18n/unicode/decimfmt.h
@@ -63,19 +63,22 @@ class NumberParserImpl;
}
}
-// explicit template instantiation. see digitlst.h
-// (When building DLLs for Windows this is required.)
-#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
+/**
+ * \cond
+ * explicit template instantiation. see digitlst.h
+ * (When building DLLs for Windows this is required.)
+ */
+#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN && !defined(U_IN_DOXYGEN)
template class U_I18N_API EnumSet<UNumberFormatAttribute,
UNUM_MAX_NONBOOLEAN_ATTRIBUTE+1,
UNUM_LIMIT_BOOLEAN_ATTRIBUTE>;
#endif
+/** \endcond */
/**
- * <p><strong>IMPORTANT:</strong> New users are strongly encouraged to see if
+ * **IMPORTANT:** New users are strongly encouraged to see if
* numberformatter.h fits their use case. Although not deprecated, this header
* is provided for backwards compatibility only.
- * <hr/>
*
* DecimalFormat is a concrete subclass of NumberFormat that formats decimal
* numbers. It has a variety of features designed to make it possible to parse
@@ -85,13 +88,13 @@ template class U_I18N_API EnumSet<UNumberFormatAttribute,
* ("1.23E4"), percentages ("12%"), and currency amounts ("$123", "USD123",
* "123 US dollars"). All of these flavors can be easily localized.
*
- * <p>To obtain a NumberFormat for a specific locale (including the default
+ * To obtain a NumberFormat for a specific locale (including the default
* locale) call one of NumberFormat's factory methods such as
* createInstance(). Do not call the DecimalFormat constructors directly, unless
* you know what you are doing, since the NumberFormat factory methods may
* return subclasses other than DecimalFormat.
*
- * <p><strong>Example Usage</strong>
+ * **Example Usage**
*
* \code
* // Normally we would have a GUI with a menu for this
@@ -135,11 +138,11 @@ template class U_I18N_API EnumSet<UNumberFormatAttribute,
* }
* }
* \endcode
- * <P>
- * Another example use createInstance(style)
- * <P>
- * <pre>
- * <strong>// Print out a number using the localized number, currency,
+ *
+ * **Another example use createInstance(style)**
+ *
+ * \code
+ * // Print out a number using the localized number, currency,
* // percent, scientific, integer, iso currency, and plural currency
* // format for each locale</strong>
* Locale* locale = new Locale("en", "US");
@@ -150,11 +153,13 @@ template class U_I18N_API EnumSet<UNumberFormatAttribute,
* for (int j=NumberFormat::kNumberStyle;
* j<=NumberFormat::kPluralCurrencyStyle;
* ++j) {
- * NumberFormat* format = NumberFormat::createInstance(locale, j, success);
+ * NumberFormat* form = NumberFormat::createInstance(locale, j, success);
* str.remove();
* cout << "format result " << form->format(myNumber, str) << endl;
* format->parse(form->format(myNumber, str), fmtable, success);
- * }</pre>
+ * delete form;
+ * }
+ * \endcode
*
*
* <p><strong>Patterns</strong>
@@ -690,7 +695,7 @@ class U_I18N_API DecimalFormat : public NumberFormat {
* locale.
* <p>
* <strong>NOTE:</strong> New users are strongly encouraged to use
- * {@link NumberFormatter} instead of DecimalFormat.
+ * #icu::number::NumberFormatter instead of DecimalFormat.
* @param status Output param set to success/failure code. If the
* pattern is invalid this will be set to a failure code.
* @stable ICU 2.0
@@ -708,7 +713,7 @@ class U_I18N_API DecimalFormat : public NumberFormat {
* locale.
* <p>
* <strong>NOTE:</strong> New users are strongly encouraged to use
- * {@link NumberFormatter} instead of DecimalFormat.
+ * #icu::number::NumberFormatter instead of DecimalFormat.
* @param pattern A non-localized pattern string.
* @param status Output param set to success/failure code. If the
* pattern is invalid this will be set to a failure code.
@@ -728,7 +733,7 @@ class U_I18N_API DecimalFormat : public NumberFormat {
* a NumberFormat factory method.
* <p>
* <strong>NOTE:</strong> New users are strongly encouraged to use
- * {@link NumberFormatter} instead of DecimalFormat.
+ * #icu::number::NumberFormatter instead of DecimalFormat.
*
* @param pattern a non-localized pattern string
* @param symbolsToAdopt the set of symbols to be used. The caller should not
@@ -782,7 +787,7 @@ class U_I18N_API DecimalFormat : public NumberFormat {
* May return U_UNSUPPORTED_ERROR if this instance does not support
* the specified attribute.
* @param attr the attribute to set
- * @param newvalue new value
+ * @param newValue new value
* @param status the error type
* @return *this - for chaining (example: format.setAttribute(...).setAttribute(...) )
* @stable ICU 51
@@ -839,7 +844,7 @@ class U_I18N_API DecimalFormat : public NumberFormat {
* a NumberFormat factory method.
* <p>
* <strong>NOTE:</strong> New users are strongly encouraged to use
- * {@link NumberFormatter} instead of DecimalFormat.
+ * #icu::number::NumberFormatter instead of DecimalFormat.
*
* @param pattern a non-localized pattern string
* @param symbolsToAdopt the set of symbols to be used. The caller should not
@@ -864,7 +869,7 @@ class U_I18N_API DecimalFormat : public NumberFormat {
* a NumberFormat factory method.
* <p>
* <strong>NOTE:</strong> New users are strongly encouraged to use
- * {@link NumberFormatter} instead of DecimalFormat.
+ * #icu::number::NumberFormatter instead of DecimalFormat.
*
* @param pattern a non-localized pattern string
* @param symbols the set of symbols to be used
@@ -986,6 +991,7 @@ class U_I18N_API DecimalFormat : public NumberFormat {
* Result is appended to existing contents.
* @param pos On input: an alignment field, if desired.
* On output: the offsets of the alignment field.
+ * @param status Output param filled with success/failure status.
* @return Reference to 'appendTo' parameter.
* @internal
*/
@@ -1031,6 +1037,7 @@ class U_I18N_API DecimalFormat : public NumberFormat {
* Result is appended to existing contents.
* @param pos On input: an alignment field, if desired.
* On output: the offsets of the alignment field.
+ * @param status Output param filled with success/failure status.
* @return Reference to 'appendTo' parameter.
* @internal
*/
@@ -1726,7 +1733,7 @@ class U_I18N_API DecimalFormat : public NumberFormat {
virtual void setDecimalPatternMatchRequired(UBool newValue);
/**
- * {@icu} Returns whether to ignore exponents when parsing.
+ * Returns whether to ignore exponents when parsing.
*
* @see #setParseNoExponent
* @internal This API is a technical preview. It may change in an upcoming release.
@@ -1734,7 +1741,7 @@ class U_I18N_API DecimalFormat : public NumberFormat {
virtual UBool isParseNoExponent() const;
/**
- * {@icu} Specifies whether to stop parsing when an exponent separator is encountered. For
+ * Specifies whether to stop parsing when an exponent separator is encountered. For
* example, parses "123E4" to 123 (with parse position 3) instead of 1230000 (with parse position
* 5).
*
@@ -1744,7 +1751,7 @@ class U_I18N_API DecimalFormat : public NumberFormat {
virtual void setParseNoExponent(UBool value);
/**
- * {@icu} Returns whether parsing is sensitive to case (lowercase/uppercase).
+ * Returns whether parsing is sensitive to case (lowercase/uppercase).
*
* @see #setParseCaseSensitive
* @internal This API is a technical preview. It may change in an upcoming release.
@@ -1752,7 +1759,7 @@ class U_I18N_API DecimalFormat : public NumberFormat {
virtual UBool isParseCaseSensitive() const;
/**
- * {@icu} Whether to pay attention to case when parsing; default is to ignore case (perform
+ * Whether to pay attention to case when parsing; default is to ignore case (perform
* case-folding). For example, "A" == "a" in case-insensitive but not case-sensitive mode.
*
* Currency symbols are never case-folded. For example, "us$1.00" will not parse in case-insensitive
@@ -1763,7 +1770,7 @@ class U_I18N_API DecimalFormat : public NumberFormat {
virtual void setParseCaseSensitive(UBool value);
/**
- * {@icu} Returns whether truncation of high-order integer digits should result in an error.
+ * Returns whether truncation of high-order integer digits should result in an error.
* By default, setMaximumIntegerDigits truncates high-order digits silently.
*
* @see setFormatFailIfMoreThanMaxDigits
@@ -1772,7 +1779,7 @@ class U_I18N_API DecimalFormat : public NumberFormat {
virtual UBool isFormatFailIfMoreThanMaxDigits() const;
/**
- * {@icu} Sets whether truncation of high-order integer digits should result in an error.
+ * Sets whether truncation of high-order integer digits should result in an error.
* By default, setMaximumIntegerDigits truncates high-order digits silently.
*
* @internal This API is a technical preview. It may change in an upcoming release.
@@ -2017,16 +2024,17 @@ class U_I18N_API DecimalFormat : public NumberFormat {
virtual void setCurrency(const char16_t* theCurrency);
/**
- * Sets the <tt>Currency Context</tt> object used to display currency.
+ * Sets the `Currency Usage` object used to display currency.
* This takes effect immediately, if this format is a
* currency format.
- * @param currencyContext new currency context object to use.
+ * @param newUsage new currency usage object to use.
+ * @param ec input-output error code
* @stable ICU 54
*/
void setCurrencyUsage(UCurrencyUsage newUsage, UErrorCode* ec);
/**
- * Returns the <tt>Currency Context</tt> object used to display currency
+ * Returns the `Currency Usage` object used to display currency
* @stable ICU 54
*/
UCurrencyUsage getCurrencyUsage() const;
@@ -2050,7 +2058,7 @@ class U_I18N_API DecimalFormat : public NumberFormat {
void formatToDecimalQuantity(const Formattable& number, number::impl::DecimalQuantity& output,
UErrorCode& status) const;
-#endif
+#endif /* U_HIDE_INTERNAL_API */
#ifndef U_HIDE_DRAFT_API
/**
@@ -2072,7 +2080,6 @@ class U_I18N_API DecimalFormat : public NumberFormat {
* FormattedNumber result = df->toNumberFormatter().formatDouble(123, status);
* </pre>
*
- * @param output The variable into which to store the LocalizedNumberFormatter.
* @return The output variable, for chaining.
* @draft ICU 62
*/
diff --git a/deps/icu-small/source/i18n/unicode/dtptngen.h b/deps/icu-small/source/i18n/unicode/dtptngen.h
index feb465e799..26ccc64060 100644
--- a/deps/icu-small/source/i18n/unicode/dtptngen.h
+++ b/deps/icu-small/source/i18n/unicode/dtptngen.h
@@ -498,27 +498,23 @@ public:
private:
/**
* Constructor.
- * @stable ICU 3.8
*/
DateTimePatternGenerator(UErrorCode & status);
/**
* Constructor.
- * @stable ICU 3.8
*/
DateTimePatternGenerator(const Locale& locale, UErrorCode & status);
/**
* Copy constructor.
* @param other DateTimePatternGenerator to copy
- * @stable ICU 3.8
*/
DateTimePatternGenerator(const DateTimePatternGenerator& other);
/**
* Default assignment operator.
* @param other DateTimePatternGenerator to copy
- * @stable ICU 3.8
*/
DateTimePatternGenerator& operator=(const DateTimePatternGenerator& other);
@@ -542,6 +538,11 @@ private:
int32_t fAllowedHourFormats[7]; // Actually an array of AllowedHourFormat enum type, ending with UNKNOWN.
+ // Internal error code used for recording/reporting errors that occur during methods that do not
+ // have a UErrorCode parameter. For example: the Copy Constructor, or the ::clone() method.
+ // When this is set to an error the object is in an invalid state.
+ UErrorCode internalErrorCode;
+
/* internal flags masks for adjustFieldTypes etc. */
enum {
kDTPGNoFlags = 0,
@@ -569,11 +570,10 @@ private:
#endif // U_HIDE_DRAFT_API
void getAppendName(UDateTimePatternField field, UnicodeString& value);
UnicodeString mapSkeletonMetacharacters(const UnicodeString& patternForm, int32_t* flags, UErrorCode& status);
- int32_t getCanonicalIndex(const UnicodeString& field);
- const UnicodeString* getBestRaw(DateTimeMatcher& source, int32_t includeMask, DistanceInfo* missingFields, const PtnSkeleton** specifiedSkeletonPtr = 0);
+ const UnicodeString* getBestRaw(DateTimeMatcher& source, int32_t includeMask, DistanceInfo* missingFields, UErrorCode& status, const PtnSkeleton** specifiedSkeletonPtr = 0);
UnicodeString adjustFieldTypes(const UnicodeString& pattern, const PtnSkeleton* specifiedSkeleton, int32_t flags, UDateTimePatternMatchOptions options = UDATPG_MATCH_NO_OPTIONS);
- UnicodeString getBestAppending(int32_t missingFields, int32_t flags, UDateTimePatternMatchOptions options = UDATPG_MATCH_NO_OPTIONS);
- int32_t getTopBitNumber(int32_t foundMask);
+ UnicodeString getBestAppending(int32_t missingFields, int32_t flags, UErrorCode& status, UDateTimePatternMatchOptions options = UDATPG_MATCH_NO_OPTIONS);
+ int32_t getTopBitNumber(int32_t foundMask) const;
void setAvailableFormat(const UnicodeString &key, UErrorCode& status);
UBool isAvailableFormatSet(const UnicodeString &key) const;
void copyHashtable(Hashtable *other, UErrorCode &status);
diff --git a/deps/icu-small/source/i18n/unicode/fmtable.h b/deps/icu-small/source/i18n/unicode/fmtable.h
index 2359b61d46..a06c23dc3b 100644
--- a/deps/icu-small/source/i18n/unicode/fmtable.h
+++ b/deps/icu-small/source/i18n/unicode/fmtable.h
@@ -658,7 +658,7 @@ public:
/**
* Adopt, and set value from, a DecimalQuantity
* Internal Function, do not use.
- * @param dl the DecimalQuantity to be adopted
+ * @param dq the DecimalQuantity to be adopted
* @internal
*/
void adoptDecimalQuantity(number::impl::DecimalQuantity *dq);
diff --git a/deps/icu-small/source/i18n/unicode/gender.h b/deps/icu-small/source/i18n/unicode/gender.h
index 467b64ec5e..b7c31cb554 100644
--- a/deps/icu-small/source/i18n/unicode/gender.h
+++ b/deps/icu-small/source/i18n/unicode/gender.h
@@ -18,6 +18,11 @@
#ifndef _GENDER
#define _GENDER
+/**
+ * \file
+ * \brief C++ API: GenderInfo computes the gender of a list.
+ */
+
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
@@ -30,7 +35,7 @@ class GenderInfoTest;
U_NAMESPACE_BEGIN
-// Forward Declaration
+/** \internal Forward Declaration */
void U_CALLCONV GenderInfo_initCache(UErrorCode &status);
/**
diff --git a/deps/icu-small/source/i18n/unicode/listformatter.h b/deps/icu-small/source/i18n/unicode/listformatter.h
new file mode 100644
index 0000000000..5e36cf71cc
--- /dev/null
+++ b/deps/icu-small/source/i18n/unicode/listformatter.h
@@ -0,0 +1,203 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/*
+*******************************************************************************
+*
+* Copyright (C) 2012-2016, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+*******************************************************************************
+* file name: listformatter.h
+* encoding: UTF-8
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 20120426
+* created by: Umesh P. Nair
+*/
+
+#ifndef __LISTFORMATTER_H__
+#define __LISTFORMATTER_H__
+
+#include "unicode/utypes.h"
+
+#include "unicode/unistr.h"
+#include "unicode/locid.h"
+
+U_NAMESPACE_BEGIN
+
+class FieldPositionIterator;
+class FieldPositionHandler;
+
+/** @internal */
+class Hashtable;
+
+/** @internal */
+struct ListFormatInternal;
+
+/* The following can't be #ifndef U_HIDE_INTERNAL_API, needed for other .h file declarations */
+/**
+ * @internal
+ * \cond
+ */
+struct ListFormatData : public UMemory {
+ UnicodeString twoPattern;
+ UnicodeString startPattern;
+ UnicodeString middlePattern;
+ UnicodeString endPattern;
+
+ ListFormatData(const UnicodeString& two, const UnicodeString& start, const UnicodeString& middle, const UnicodeString& end) :
+ twoPattern(two), startPattern(start), middlePattern(middle), endPattern(end) {}
+};
+/** \endcond */
+
+
+/**
+ * \file
+ * \brief C++ API: API for formatting a list.
+ */
+
+
+/**
+ * An immutable class for formatting a list, using data from CLDR (or supplied
+ * separately).
+ *
+ * Example: Input data ["Alice", "Bob", "Charlie", "Delta"] will be formatted
+ * as "Alice, Bob, Charlie and Delta" in English.
+ *
+ * The ListFormatter class is not intended for public subclassing.
+ * @stable ICU 50
+ */
+class U_I18N_API ListFormatter : public UObject{
+
+ public:
+
+ /**
+ * Copy constructor.
+ * @stable ICU 52
+ */
+ ListFormatter(const ListFormatter&);
+
+ /**
+ * Assignment operator.
+ * @stable ICU 52
+ */
+ ListFormatter& operator=(const ListFormatter& other);
+
+ /**
+ * Creates a ListFormatter appropriate for the default locale.
+ *
+ * @param errorCode ICU error code, set if no data available for default locale.
+ * @return Pointer to a ListFormatter object for the default locale,
+ * created from internal data derived from CLDR data.
+ * @stable ICU 50
+ */
+ static ListFormatter* createInstance(UErrorCode& errorCode);
+
+ /**
+ * Creates a ListFormatter appropriate for a locale.
+ *
+ * @param locale The locale.
+ * @param errorCode ICU error code, set if no data available for the given locale.
+ * @return A ListFormatter object created from internal data derived from
+ * CLDR data.
+ * @stable ICU 50
+ */
+ static ListFormatter* createInstance(const Locale& locale, UErrorCode& errorCode);
+
+#ifndef U_HIDE_INTERNAL_API
+ /**
+ * Creates a ListFormatter appropriate for a locale and style.
+ *
+ * @param locale The locale.
+ * @param style the style, either "standard", "duration", or "duration-short"
+ * @param errorCode ICU error code, set if no data available for the given locale.
+ * @return A ListFormatter object created from internal data derived from
+ * CLDR data.
+ * @internal
+ */
+ static ListFormatter* createInstance(const Locale& locale, const char* style, UErrorCode& errorCode);
+#endif /* U_HIDE_INTERNAL_API */
+
+ /**
+ * Destructor.
+ *
+ * @stable ICU 50
+ */
+ virtual ~ListFormatter();
+
+
+ /**
+ * Formats a list of strings.
+ *
+ * @param items An array of strings to be combined and formatted.
+ * @param n_items Length of the array items.
+ * @param appendTo The string to which the result should be appended to.
+ * @param errorCode ICU error code, set if there is an error.
+ * @return Formatted string combining the elements of items, appended to appendTo.
+ * @stable ICU 50
+ */
+ UnicodeString& format(const UnicodeString items[], int32_t n_items,
+ UnicodeString& appendTo, UErrorCode& errorCode) const;
+
+#ifndef U_HIDE_DRAFT_API
+ /**
+ * Format a list of strings.
+ *
+ * @param items An array of strings to be combined and formatted.
+ * @param n_items Length of the array items.
+ * @param appendTo The string to which the formatted result will be
+ * appended.
+ * @param posIter On return, can be used to iterate over positions of
+ * fields generated by this format call. Field values are
+ * defined in UListFormatterField. Can be NULL.
+ * @param errorCode ICU error code returned here.
+ * @return Formatted string combining the elements of items,
+ * appended to appendTo.
+ * @draft ICU 63
+ */
+ UnicodeString& format(const UnicodeString items[], int32_t n_items,
+ UnicodeString & appendTo, FieldPositionIterator* posIter,
+ UErrorCode& errorCode) const;
+#endif /* U_HIDE_DRAFT_API */
+
+#ifndef U_HIDE_INTERNAL_API
+ /**
+ @internal for MeasureFormat
+ */
+ UnicodeString& format(
+ const UnicodeString items[],
+ int32_t n_items,
+ UnicodeString& appendTo,
+ int32_t index,
+ int32_t &offset,
+ UErrorCode& errorCode) const;
+ /**
+ * @internal constructor made public for testing.
+ */
+ ListFormatter(const ListFormatData &data, UErrorCode &errorCode);
+ /**
+ * @internal constructor made public for testing.
+ */
+ ListFormatter(const ListFormatInternal* listFormatterInternal);
+#endif /* U_HIDE_INTERNAL_API */
+
+ private:
+ static void initializeHash(UErrorCode& errorCode);
+ static const ListFormatInternal* getListFormatInternal(const Locale& locale, const char *style, UErrorCode& errorCode);
+ struct ListPatternsSink;
+ static ListFormatInternal* loadListFormatInternal(const Locale& locale, const char* style, UErrorCode& errorCode);
+
+ UnicodeString& format_(
+ const UnicodeString items[], int32_t n_items, UnicodeString& appendTo,
+ int32_t index, int32_t &offset, FieldPositionHandler* handler, UErrorCode& errorCode) const;
+
+ ListFormatter();
+
+ ListFormatInternal* owned;
+ const ListFormatInternal* data;
+};
+
+U_NAMESPACE_END
+
+#endif
diff --git a/deps/icu-small/source/i18n/unicode/measfmt.h b/deps/icu-small/source/i18n/unicode/measfmt.h
index 14399dd59a..bbdd2364bd 100644
--- a/deps/icu-small/source/i18n/unicode/measfmt.h
+++ b/deps/icu-small/source/i18n/unicode/measfmt.h
@@ -104,7 +104,7 @@ class U_I18N_API MeasureFormat : public Format {
* Constructor.
* <p>
* <strong>NOTE:</strong> New users are strongly encouraged to use
- * {@link NumberFormatter} instead of NumberFormat.
+ * {@link icu::number::NumberFormatter} instead of NumberFormat.
* @stable ICU 53
*/
MeasureFormat(
@@ -114,7 +114,7 @@ class U_I18N_API MeasureFormat : public Format {
* Constructor.
* <p>
* <strong>NOTE:</strong> New users are strongly encouraged to use
- * {@link NumberFormatter} instead of NumberFormat.
+ * {@link icu::number::NumberFormatter} instead of NumberFormat.
* @stable ICU 53
*/
MeasureFormat(
@@ -202,7 +202,7 @@ class U_I18N_API MeasureFormat : public Format {
* 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).
+ * `*%MeasureUnit::createSecond(status)`.
* @param appendTo formatted string appended here.
* @param pos the field position.
* @param status the error.
@@ -223,7 +223,7 @@ class U_I18N_API MeasureFormat : public Format {
* @param unit The unit for which to get a display name.
* @param status the error.
* @return The display name in the locale and width specified in
- * {@link MeasureFormat#getInstance}, or null if there is no display name available
+ * the MeasureFormat constructor, or null if there is no display name available
* for the specified unit.
*
* @stable ICU 58
@@ -236,7 +236,7 @@ class U_I18N_API MeasureFormat : public Format {
* locale.
* <p>
* <strong>NOTE:</strong> New users are strongly encouraged to use
- * {@link NumberFormatter} instead of NumberFormat.
+ * {@link icu::number::NumberFormatter} instead of NumberFormat.
* @param locale desired locale
* @param ec input-output error code
* @return a formatter object, or NULL upon error
@@ -250,7 +250,7 @@ class U_I18N_API MeasureFormat : public Format {
* locale.
* <p>
* <strong>NOTE:</strong> New users are strongly encouraged to use
- * {@link NumberFormatter} instead of NumberFormat.
+ * {@link icu::number::NumberFormatter} instead of NumberFormat.
* @param ec input-output error code
* @return a formatter object, or NULL upon error
* @stable ICU 3.0
@@ -348,7 +348,7 @@ class U_I18N_API MeasureFormat : public Format {
const MeasureFormatCacheData *cache;
const SharedNumberFormat *numberFormat;
const SharedPluralRules *pluralRules;
- UMeasureFormatWidth width;
+ UMeasureFormatWidth fWidth;
// Declared outside of MeasureFormatSharedData because ListFormatter
// objects are relatively cheap to copy; therefore, they don't need to be
diff --git a/deps/icu-small/source/i18n/unicode/measunit.h b/deps/icu-small/source/i18n/unicode/measunit.h
index f552253544..676fdeb9c8 100644
--- a/deps/icu-small/source/i18n/unicode/measunit.h
+++ b/deps/icu-small/source/i18n/unicode/measunit.h
@@ -368,6 +368,26 @@ class U_I18N_API MeasureUnit: public UObject {
*/
static MeasureUnit *createPartPerMillion(UErrorCode &status);
+#ifndef U_HIDE_DRAFT_API
+ /**
+ * Returns unit of concentr: percent.
+ * Caller owns returned value and must free it.
+ * @param status ICU error code.
+ * @draft ICU 63
+ */
+ static MeasureUnit *createPercent(UErrorCode &status);
+#endif /* U_HIDE_DRAFT_API */
+
+#ifndef U_HIDE_DRAFT_API
+ /**
+ * Returns unit of concentr: permille.
+ * Caller owns returned value and must free it.
+ * @param status ICU error code.
+ * @draft ICU 63
+ */
+ static MeasureUnit *createPermille(UErrorCode &status);
+#endif /* U_HIDE_DRAFT_API */
+
/**
* Returns unit of consumption: liter-per-100kilometers.
* Caller owns returned value and must free it.
@@ -464,6 +484,16 @@ class U_I18N_API MeasureUnit: public UObject {
*/
static MeasureUnit *createMegabyte(UErrorCode &status);
+#ifndef U_HIDE_DRAFT_API
+ /**
+ * Returns unit of digital: petabyte.
+ * Caller owns returned value and must free it.
+ * @param status ICU error code.
+ * @draft ICU 63
+ */
+ static MeasureUnit *createPetabyte(UErrorCode &status);
+#endif /* U_HIDE_DRAFT_API */
+
/**
* Returns unit of digital: terabit.
* Caller owns returned value and must free it.
@@ -984,6 +1014,16 @@ class U_I18N_API MeasureUnit: public UObject {
*/
static MeasureUnit *createWatt(UErrorCode &status);
+#ifndef U_HIDE_DRAFT_API
+ /**
+ * Returns unit of pressure: atmosphere.
+ * Caller owns returned value and must free it.
+ * @param status ICU error code.
+ * @draft ICU 63
+ */
+ static MeasureUnit *createAtmosphere(UErrorCode &status);
+#endif /* U_HIDE_DRAFT_API */
+
/**
* Returns unit of pressure: hectopascal.
* Caller owns returned value and must free it.
diff --git a/deps/icu-small/source/i18n/unicode/msgfmt.h b/deps/icu-small/source/i18n/unicode/msgfmt.h
index fef8010774..074d933540 100644
--- a/deps/icu-small/source/i18n/unicode/msgfmt.h
+++ b/deps/icu-small/source/i18n/unicode/msgfmt.h
@@ -124,7 +124,7 @@ class NumberFormat;
* argNumber = '0' | ('1'..'9' ('0'..'9')*)
*
* argType = "number" | "date" | "time" | "spellout" | "ordinal" | "duration"
- * argStyle = "short" | "medium" | "long" | "full" | "integer" | "currency" | "percent" | argStyleText
+ * argStyle = "short" | "medium" | "long" | "full" | "integer" | "currency" | "percent" | argStyleText | "::" argSkeletonText
* </pre>
*
* <ul>
@@ -166,7 +166,7 @@ class NumberFormat;
* <td colspan=2><i>(none)</i>
* <td><code>null</code>
* <tr>
- * <td rowspan=5><code>number</code>
+ * <td rowspan=6><code>number</code>
* <td><i>(none)</i>
* <td><code>NumberFormat.createInstance(getLocale(), status)</code>
* <tr>
@@ -182,6 +182,9 @@ class NumberFormat;
* <td><i>argStyleText</i>
* <td><code>new DecimalFormat(argStyleText, new DecimalFormatSymbols(getLocale(), status), status)</code>
* <tr>
+ * <td><i>argSkeletonText</i>
+ * <td><code>NumberFormatter::forSkeleton(argSkeletonText, status).locale(getLocale()).toFormat(status)</code>
+ * <tr>
* <td rowspan=6><code>date</code>
* <td><i>(none)</i>
* <td><code>DateFormat.createDateInstance(kDefault, getLocale(), status)</code>
@@ -199,7 +202,7 @@ class NumberFormat;
* <td><code>DateFormat.createDateInstance(kFull, getLocale(), status)</code>
* <tr>
* <td><i>argStyleText</i>
- * <td><code>new SimpleDateFormat(argStyleText, getLocale(), status)
+ * <td><code>new SimpleDateFormat(argStyleText, getLocale(), status)</code>
* <tr>
* <td rowspan=6><code>time</code>
* <td><i>(none)</i>
@@ -218,7 +221,7 @@ class NumberFormat;
* <td><code>DateFormat.createTimeInstance(kFull, getLocale(), status)</code>
* <tr>
* <td><i>argStyleText</i>
- * <td><code>new SimpleDateFormat(argStyleText, getLocale(), status)
+ * <td><code>new SimpleDateFormat(argStyleText, getLocale(), status)</code>
* <tr>
* <td><code>spellout</code>
* <td><i>argStyleText (optional)</i>
diff --git a/deps/icu-small/source/i18n/unicode/numberformatter.h b/deps/icu-small/source/i18n/unicode/numberformatter.h
index 3ab08319f7..469949a287 100644
--- a/deps/icu-small/source/i18n/unicode/numberformatter.h
+++ b/deps/icu-small/source/i18n/unicode/numberformatter.h
@@ -144,11 +144,31 @@ class MultiplierFormatHandler;
class CurrencySymbols;
class GeneratorHelpers;
class DecNum;
+class NumberRangeFormatterImpl;
+struct RangeMacroProps;
+
+/**
+ * Used for NumberRangeFormatter and implemented in numrange_fluent.cpp.
+ * Declared here so it can be friended.
+ *
+ * @internal
+ */
+void touchRangeLocales(impl::RangeMacroProps& macros);
} // namespace impl
-// Reserve extra names in case they are added as classes in the future:
+/**
+ * Extra name reserved in case it is needed in the future.
+ *
+ * @draft ICU 63
+ */
typedef Notation CompactNotation;
+
+/**
+ * Extra name reserved in case it is needed in the future.
+ *
+ * @draft ICU 63
+ */
typedef Notation SimpleNotation;
/**
@@ -308,10 +328,15 @@ class U_I18N_API Notation : public UMemory {
union NotationUnion {
// For NTN_SCIENTIFIC
+ /** @internal */
struct ScientificSettings {
+ /** @internal */
int8_t fEngineeringInterval;
+ /** @internal */
bool fRequireMinInt;
+ /** @internal */
impl::digits_t fMinExponentDigits;
+ /** @internal */
UNumberSignDisplay fExponentSignDisplay;
} scientific;
@@ -407,15 +432,39 @@ class U_I18N_API ScientificNotation : public Notation {
friend class impl::NumberPropertyMapper;
};
-// Reserve extra names in case they are added as classes in the future:
+/**
+ * Extra name reserved in case it is needed in the future.
+ *
+ * @draft ICU 63
+ */
typedef Precision SignificantDigitsPrecision;
// Typedefs for ICU 60/61 compatibility.
// These will be removed in ICU 64.
// See http://bugs.icu-project.org/trac/ticket/13746
+
+/**
+ * This will be removed in ICU 64. See ICU-13746.
+ * @deprecated ICU 63
+ */
typedef Precision Rounder;
+
+/**
+ * This will be removed in ICU 64. See ICU-13746.
+ * @deprecated ICU 63
+ */
typedef FractionPrecision FractionRounder;
+
+/**
+ * This will be removed in ICU 64. See ICU-13746.
+ * @deprecated ICU 63
+ */
typedef IncrementPrecision IncrementRounder;
+
+/**
+ * This will be removed in ICU 64. See ICU-13746.
+ * @deprecated ICU 63
+ */
typedef CurrencyPrecision CurrencyRounder;
/**
@@ -672,16 +721,25 @@ class U_I18N_API Precision : public UMemory {
} fType;
union PrecisionUnion {
+ /** @internal */
struct FractionSignificantSettings {
// For RND_FRACTION, RND_SIGNIFICANT, and RND_FRACTION_SIGNIFICANT
+ /** @internal */
impl::digits_t fMinFrac;
+ /** @internal */
impl::digits_t fMaxFrac;
+ /** @internal */
impl::digits_t fMinSig;
+ /** @internal */
impl::digits_t fMaxSig;
} fracSig;
+ /** @internal */
struct IncrementSettings {
+ /** @internal */
double fIncrement;
+ /** @internal */
impl::digits_t fMinFrac;
+ /** @internal */
impl::digits_t fMaxFrac;
} increment; // For RND_INCREMENT
UCurrencyUsage currencyUsage; // For RND_CURRENCY
@@ -1205,7 +1263,7 @@ class U_I18N_API Grouper : public UMemory {
public:
#ifndef U_HIDE_INTERNAL_API
/** @internal */
- static Grouper forStrategy(UGroupingStrategy grouping);
+ static Grouper forStrategy(UNumberGroupingStrategy grouping);
/**
* Resolve the values in Properties to a Grouper object.
@@ -1216,7 +1274,7 @@ class U_I18N_API Grouper : public UMemory {
// Future: static Grouper forProperties(DecimalFormatProperties& properties);
/** @internal */
- Grouper(int16_t grouping1, int16_t grouping2, int16_t minGrouping, UGroupingStrategy strategy)
+ Grouper(int16_t grouping1, int16_t grouping2, int16_t minGrouping, UNumberGroupingStrategy strategy)
: fGrouping1(grouping1),
fGrouping2(grouping2),
fMinGrouping(minGrouping),
@@ -1251,10 +1309,10 @@ class U_I18N_API Grouper : public UMemory {
int16_t fMinGrouping;
/**
- * The UGroupingStrategy that was used to create this Grouper, or UNUM_GROUPING_COUNT if this
- * was not created from a UGroupingStrategy.
+ * The UNumberGroupingStrategy that was used to create this Grouper, or UNUM_GROUPING_COUNT if this
+ * was not created from a UNumberGroupingStrategy.
*/
- UGroupingStrategy fStrategy;
+ UNumberGroupingStrategy fStrategy;
Grouper() : fGrouping1(-3) {};
@@ -1423,7 +1481,8 @@ struct U_I18N_API MacroProps : public UMemory {
/**
* An abstract base class for specifying settings related to number formatting. This class is implemented by
- * {@link UnlocalizedNumberFormatter} and {@link LocalizedNumberFormatter}.
+ * {@link UnlocalizedNumberFormatter} and {@link LocalizedNumberFormatter}. This class is not intended for
+ * public subclassing.
*/
template<typename Derived>
class U_I18N_API NumberFormatterSettings {
@@ -1710,7 +1769,7 @@ class U_I18N_API NumberFormatterSettings {
* The exact grouping widths will be chosen based on the locale.
*
* <p>
- * Pass this method an element from the {@link UGroupingStrategy} enum. For example:
+ * Pass this method an element from the {@link UNumberGroupingStrategy} enum. For example:
*
* <pre>
* NumberFormatter::with().grouping(UNUM_GROUPING_MIN2)
@@ -1724,7 +1783,7 @@ class U_I18N_API NumberFormatterSettings {
* @return The fluent chain.
* @draft ICU 61
*/
- Derived grouping(UGroupingStrategy strategy) const &;
+ Derived grouping(UNumberGroupingStrategy strategy) const &;
/**
* Overload of grouping() for use on an rvalue reference.
@@ -1733,10 +1792,9 @@ class U_I18N_API NumberFormatterSettings {
* The grouping strategy to use.
* @return The fluent chain.
* @see #grouping
- * @provisional This API might change or be removed in a future release.
* @draft ICU 62
*/
- Derived grouping(UGroupingStrategy strategy) &&;
+ Derived grouping(UNumberGroupingStrategy strategy) &&;
/**
* Specifies the minimum and maximum number of digits to render before the decimal mark.
@@ -1748,7 +1806,7 @@ class U_I18N_API NumberFormatterSettings {
* </ul>
*
* <p>
- * Pass this method the return value of {@link IntegerWidth#zeroFillTo(int)}. For example:
+ * Pass this method the return value of {@link IntegerWidth#zeroFillTo}. For example:
*
* <pre>
* NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(2))
@@ -2099,15 +2157,18 @@ class U_I18N_API NumberFormatterSettings {
// NOTE: Uses default copy and move constructors.
- protected:
+ private:
impl::MacroProps fMacros;
- private:
// Don't construct me directly! Use (Un)LocalizedNumberFormatter.
NumberFormatterSettings() = default;
friend class LocalizedNumberFormatter;
friend class UnlocalizedNumberFormatter;
+
+ // Give NumberRangeFormatter access to the MacroProps
+ friend void impl::touchRangeLocales(impl::RangeMacroProps& macros);
+ friend class impl::NumberRangeFormatterImpl;
};
/**
@@ -2124,13 +2185,6 @@ class U_I18N_API UnlocalizedNumberFormatter
* Associate the given locale with the number formatter. The locale is used for picking the appropriate symbols,
* formats, and other data for number display.
*
- * <p>
- * To use the Java default locale, call Locale::getDefault():
- *
- * <pre>
- * NumberFormatter::with(). ... .locale(Locale::getDefault())
- * </pre>
- *
* @param locale
* The locale to use when loading data for number formatting.
* @return The fluent chain.
@@ -2156,7 +2210,6 @@ class U_I18N_API UnlocalizedNumberFormatter
*/
UnlocalizedNumberFormatter() = default;
- // Make default copy constructor call the NumberFormatterSettings copy constructor.
/**
* Returns a copy of this UnlocalizedNumberFormatter.
* @draft ICU 60
@@ -2271,7 +2324,7 @@ class U_I18N_API LocalizedNumberFormatter
*/
int32_t getCallCount() const;
-#endif
+#endif /* U_HIDE_INTERNAL_API */
/**
* Creates a representation of this LocalizedNumberFormat as an icu::Format, enabling the use
@@ -2295,7 +2348,6 @@ class U_I18N_API LocalizedNumberFormatter
*/
LocalizedNumberFormatter() = default;
- // Make default copy constructor call the NumberFormatterSettings copy constructor.
/**
* Returns a copy of this LocalizedNumberFormatter.
* @draft ICU 60
@@ -2333,11 +2385,12 @@ class U_I18N_API LocalizedNumberFormatter
*
* @param results
* The results object. This method will mutate it to save the results.
+ * @param status
* @internal
*/
void formatImpl(impl::UFormattedNumberData *results, UErrorCode &status) const;
-#endif
+#endif /* U_HIDE_INTERNAL_API */
/**
* Destruct this LocalizedNumberFormatter, cleaning up any memory it might own.
@@ -2359,6 +2412,8 @@ class U_I18N_API LocalizedNumberFormatter
LocalizedNumberFormatter(impl::MacroProps &&macros, const Locale &locale);
+ void clear();
+
void lnfMoveHelper(LocalizedNumberFormatter&& src);
/**
@@ -2430,7 +2485,7 @@ class U_I18N_API FormattedNumber : public UMemory {
* @draft ICU 62
* @see Appendable
*/
- Appendable &appendTo(Appendable &appendable, UErrorCode& status);
+ Appendable &appendTo(Appendable &appendable, UErrorCode& status) const;
#ifndef U_HIDE_DEPRECATED_API
/**
@@ -2457,9 +2512,9 @@ class U_I18N_API FormattedNumber : public UMemory {
#endif /* U_HIDE_DEPRECATED_API */
/**
- * Determines the start and end indices of the next occurrence of the given <em>field</em> in the
- * output string. This allows you to determine the locations of, for example, the integer part,
- * fraction part, or symbols.
+ * Determines the start (inclusive) and end (exclusive) indices of the next occurrence of the given
+ * <em>field</em> in the output string. This allows you to determine the locations of, for example,
+ * the integer part, fraction part, or symbols.
*
* If a field occurs just once, calling this method will find that occurrence and return it. If a
* field occurs multiple times, this method may be called repeatedly with the following pattern:
@@ -2478,7 +2533,7 @@ class U_I18N_API FormattedNumber : public UMemory {
* Input+output variable. On input, the "field" property determines which field to look
* up, and the "beginIndex" and "endIndex" properties determine where to begin the search.
* On output, the "beginIndex" is set to the beginning of the first occurrence of the
- * field with either begin or end indices after the input indices, "endIndex" is set to
+ * field with either begin or end indices after the input indices; "endIndex" is set to
* the end of that occurrence of the field (exclusive index). If a field position is not
* found, the method returns FALSE and the FieldPosition may or may not be changed.
* @param status
@@ -2537,7 +2592,7 @@ class U_I18N_API FormattedNumber : public UMemory {
*/
void getAllFieldPositionsImpl(FieldPositionIteratorHandler& fpih, UErrorCode& status) const;
-#endif
+#endif /* U_HIDE_INTERNAL_API */
/**
* Copying not supported; use move constructor instead.
diff --git a/deps/icu-small/source/i18n/unicode/numberrangeformatter.h b/deps/icu-small/source/i18n/unicode/numberrangeformatter.h
new file mode 100644
index 0000000000..3e6248d934
--- /dev/null
+++ b/deps/icu-small/source/i18n/unicode/numberrangeformatter.h
@@ -0,0 +1,866 @@
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#if !UCONFIG_NO_FORMATTING
+#ifndef __NUMBERRANGEFORMATTER_H__
+#define __NUMBERRANGEFORMATTER_H__
+
+#include <atomic>
+#include "unicode/appendable.h"
+#include "unicode/fieldpos.h"
+#include "unicode/fpositer.h"
+#include "unicode/numberformatter.h"
+
+#ifndef U_HIDE_DRAFT_API
+
+/**
+ * \file
+ * \brief C++ API: Library for localized formatting of number, currency, and unit ranges.
+ *
+ * The main entrypoint to the formatting of ranges of numbers, including currencies and other units of measurement.
+ * <p>
+ * Usage example:
+ * <p>
+ * <pre>
+ * NumberRangeFormatter::with()
+ * .identityFallback(UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE)
+ * .numberFormatterFirst(NumberFormatter::with().adoptUnit(MeasureUnit::createMeter()))
+ * .numberFormatterSecond(NumberFormatter::with().adoptUnit(MeasureUnit::createKilometer()))
+ * .locale("en-GB")
+ * .formatRange(750, 1.2, status)
+ * .toString(status);
+ * // => "750 m - 1.2 km"
+ * </pre>
+ * <p>
+ * Like NumberFormatter, NumberRangeFormatter instances are immutable and thread-safe. This API is based on the
+ * <em>fluent</em> design pattern popularized by libraries such as Google's Guava.
+ *
+ * @author Shane Carr
+ */
+
+
+/**
+ * Defines how to merge fields that are identical across the range sign.
+ *
+ * @draft ICU 63
+ */
+typedef enum UNumberRangeCollapse {
+ /**
+ * Use locale data and heuristics to determine how much of the string to collapse. Could end up collapsing none,
+ * some, or all repeated pieces in a locale-sensitive way.
+ *
+ * The heuristics used for this option are subject to change over time.
+ *
+ * @draft ICU 63
+ */
+ UNUM_RANGE_COLLAPSE_AUTO,
+
+ /**
+ * Do not collapse any part of the number. Example: "3.2 thousand kilograms – 5.3 thousand kilograms"
+ *
+ * @draft ICU 63
+ */
+ UNUM_RANGE_COLLAPSE_NONE,
+
+ /**
+ * Collapse the unit part of the number, but not the notation, if present. Example: "3.2 thousand – 5.3 thousand
+ * kilograms"
+ *
+ * @draft ICU 63
+ */
+ UNUM_RANGE_COLLAPSE_UNIT,
+
+ /**
+ * Collapse any field that is equal across the range sign. May introduce ambiguity on the magnitude of the
+ * number. Example: "3.2 – 5.3 thousand kilograms"
+ *
+ * @draft ICU 63
+ */
+ UNUM_RANGE_COLLAPSE_ALL
+} UNumberRangeCollapse;
+
+/**
+ * Defines the behavior when the two numbers in the range are identical after rounding. To programmatically detect
+ * when the identity fallback is used, compare the lower and upper BigDecimals via FormattedNumber.
+ *
+ * @draft ICU 63
+ * @see NumberRangeFormatter
+ */
+typedef enum UNumberRangeIdentityFallback {
+ /**
+ * Show the number as a single value rather than a range. Example: "$5"
+ *
+ * @draft ICU 63
+ */
+ UNUM_IDENTITY_FALLBACK_SINGLE_VALUE,
+
+ /**
+ * Show the number using a locale-sensitive approximation pattern. If the numbers were the same before rounding,
+ * show the single value. Example: "~$5" or "$5"
+ *
+ * @draft ICU 63
+ */
+ UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE,
+
+ /**
+ * Show the number using a locale-sensitive approximation pattern. Use the range pattern always, even if the
+ * inputs are the same. Example: "~$5"
+ *
+ * @draft ICU 63
+ */
+ UNUM_IDENTITY_FALLBACK_APPROXIMATELY,
+
+ /**
+ * Show the number as the range of two equal values. Use the range pattern always, even if the inputs are the
+ * same. Example (with RangeCollapse.NONE): "$5 – $5"
+ *
+ * @draft ICU 63
+ */
+ UNUM_IDENTITY_FALLBACK_RANGE
+} UNumberRangeIdentityFallback;
+
+/**
+ * Used in the result class FormattedNumberRange to indicate to the user whether the numbers formatted in the range
+ * were equal or not, and whether or not the identity fallback was applied.
+ *
+ * @draft ICU 63
+ * @see NumberRangeFormatter
+ */
+typedef enum UNumberRangeIdentityResult {
+ /**
+ * Used to indicate that the two numbers in the range were equal, even before any rounding rules were applied.
+ *
+ * @draft ICU 63
+ * @see NumberRangeFormatter
+ */
+ UNUM_IDENTITY_RESULT_EQUAL_BEFORE_ROUNDING,
+
+ /**
+ * Used to indicate that the two numbers in the range were equal, but only after rounding rules were applied.
+ *
+ * @draft ICU 63
+ * @see NumberRangeFormatter
+ */
+ UNUM_IDENTITY_RESULT_EQUAL_AFTER_ROUNDING,
+
+ /**
+ * Used to indicate that the two numbers in the range were not equal, even after rounding rules were applied.
+ *
+ * @draft ICU 63
+ * @see NumberRangeFormatter
+ */
+ UNUM_IDENTITY_RESULT_NOT_EQUAL,
+
+#ifndef U_HIDE_INTERNAL_API
+ /**
+ * The number of entries in this enum.
+ * @internal
+ */
+ UNUM_IDENTITY_RESULT_COUNT
+#endif
+
+} UNumberRangeIdentityResult;
+
+U_NAMESPACE_BEGIN
+
+namespace number { // icu::number
+
+// Forward declarations:
+class UnlocalizedNumberRangeFormatter;
+class LocalizedNumberRangeFormatter;
+class FormattedNumberRange;
+
+namespace impl {
+
+// Forward declarations:
+struct RangeMacroProps;
+class DecimalQuantity;
+struct UFormattedNumberRangeData;
+class NumberRangeFormatterImpl;
+
+} // namespace impl
+
+/**
+ * \cond
+ * Export an explicit template instantiation. See datefmt.h
+ * (When building DLLs for Windows this is required.)
+ */
+#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN && !defined(U_IN_DOXYGEN)
+template struct U_I18N_API std::atomic<impl::NumberRangeFormatterImpl*>;
+#endif
+/** \endcond */
+
+// Other helper classes would go here, but there are none.
+
+namespace impl { // icu::number::impl
+
+// Do not enclose entire MacroProps with #ifndef U_HIDE_INTERNAL_API, needed for a protected field
+/** @internal */
+struct U_I18N_API RangeMacroProps : public UMemory {
+ /** @internal */
+ UnlocalizedNumberFormatter formatter1; // = NumberFormatter::with();
+
+ /** @internal */
+ UnlocalizedNumberFormatter formatter2; // = NumberFormatter::with();
+
+ /** @internal */
+ bool singleFormatter = true;
+
+ /** @internal */
+ UNumberRangeCollapse collapse = UNUM_RANGE_COLLAPSE_AUTO;
+
+ /** @internal */
+ UNumberRangeIdentityFallback identityFallback = UNUM_IDENTITY_FALLBACK_APPROXIMATELY;
+
+ /** @internal */
+ Locale locale;
+
+ // NOTE: Uses default copy and move constructors.
+
+ /**
+ * Check all members for errors.
+ * @internal
+ */
+ bool copyErrorTo(UErrorCode &status) const {
+ return formatter1.copyErrorTo(status) || formatter2.copyErrorTo(status);
+ }
+};
+
+} // namespace impl
+
+/**
+ * An abstract base class for specifying settings related to number formatting. This class is implemented by
+ * {@link UnlocalizedNumberRangeFormatter} and {@link LocalizedNumberRangeFormatter}. This class is not intended for
+ * public subclassing.
+ */
+template<typename Derived>
+class U_I18N_API NumberRangeFormatterSettings {
+ public:
+ /**
+ * Sets the NumberFormatter instance to use for the numbers in the range. The same formatter is applied to both
+ * sides of the range.
+ * <p>
+ * The NumberFormatter instances must not have a locale applied yet; the locale specified on the
+ * NumberRangeFormatter will be used.
+ *
+ * @param formatter
+ * The formatter to use for both numbers in the range.
+ * @return The fluent chain.
+ * @draft ICU 63
+ */
+ Derived numberFormatterBoth(const UnlocalizedNumberFormatter &formatter) const &;
+
+ /**
+ * Overload of numberFormatterBoth() for use on an rvalue reference.
+ *
+ * @param formatter
+ * The formatter to use for both numbers in the range.
+ * @return The fluent chain.
+ * @see #numberFormatterBoth
+ * @draft ICU 63
+ */
+ Derived numberFormatterBoth(const UnlocalizedNumberFormatter &formatter) &&;
+
+ /**
+ * Overload of numberFormatterBoth() for use on an rvalue reference.
+ *
+ * @param formatter
+ * The formatter to use for both numbers in the range.
+ * @return The fluent chain.
+ * @see #numberFormatterBoth
+ * @draft ICU 63
+ */
+ Derived numberFormatterBoth(UnlocalizedNumberFormatter &&formatter) const &;
+
+ /**
+ * Overload of numberFormatterBoth() for use on an rvalue reference.
+ *
+ * @param formatter
+ * The formatter to use for both numbers in the range.
+ * @return The fluent chain.
+ * @see #numberFormatterBoth
+ * @draft ICU 63
+ */
+ Derived numberFormatterBoth(UnlocalizedNumberFormatter &&formatter) &&;
+
+ /**
+ * Sets the NumberFormatter instance to use for the first number in the range.
+ * <p>
+ * The NumberFormatter instances must not have a locale applied yet; the locale specified on the
+ * NumberRangeFormatter will be used.
+ *
+ * @param formatterFirst
+ * The formatter to use for the first number in the range.
+ * @return The fluent chain.
+ * @draft ICU 63
+ */
+ Derived numberFormatterFirst(const UnlocalizedNumberFormatter &formatterFirst) const &;
+
+ /**
+ * Overload of numberFormatterFirst() for use on an rvalue reference.
+ *
+ * @param formatterFirst
+ * The formatter to use for the first number in the range.
+ * @return The fluent chain.
+ * @see #numberFormatterFirst
+ * @draft ICU 63
+ */
+ Derived numberFormatterFirst(const UnlocalizedNumberFormatter &formatterFirst) &&;
+
+ /**
+ * Overload of numberFormatterFirst() for use on an rvalue reference.
+ *
+ * @param formatterFirst
+ * The formatter to use for the first number in the range.
+ * @return The fluent chain.
+ * @see #numberFormatterFirst
+ * @draft ICU 63
+ */
+ Derived numberFormatterFirst(UnlocalizedNumberFormatter &&formatterFirst) const &;
+
+ /**
+ * Overload of numberFormatterFirst() for use on an rvalue reference.
+ *
+ * @param formatterFirst
+ * The formatter to use for the first number in the range.
+ * @return The fluent chain.
+ * @see #numberFormatterFirst
+ * @draft ICU 63
+ */
+ Derived numberFormatterFirst(UnlocalizedNumberFormatter &&formatterFirst) &&;
+
+ /**
+ * Sets the NumberFormatter instance to use for the second number in the range.
+ * <p>
+ * The NumberFormatter instances must not have a locale applied yet; the locale specified on the
+ * NumberRangeFormatter will be used.
+ *
+ * @param formatterSecond
+ * The formatter to use for the second number in the range.
+ * @return The fluent chain.
+ * @draft ICU 63
+ */
+ Derived numberFormatterSecond(const UnlocalizedNumberFormatter &formatterSecond) const &;
+
+ /**
+ * Overload of numberFormatterSecond() for use on an rvalue reference.
+ *
+ * @param formatterSecond
+ * The formatter to use for the second number in the range.
+ * @return The fluent chain.
+ * @see #numberFormatterSecond
+ * @draft ICU 63
+ */
+ Derived numberFormatterSecond(const UnlocalizedNumberFormatter &formatterSecond) &&;
+
+ /**
+ * Overload of numberFormatterSecond() for use on an rvalue reference.
+ *
+ * @param formatterSecond
+ * The formatter to use for the second number in the range.
+ * @return The fluent chain.
+ * @see #numberFormatterSecond
+ * @draft ICU 63
+ */
+ Derived numberFormatterSecond(UnlocalizedNumberFormatter &&formatterSecond) const &;
+
+ /**
+ * Overload of numberFormatterSecond() for use on an rvalue reference.
+ *
+ * @param formatterSecond
+ * The formatter to use for the second number in the range.
+ * @return The fluent chain.
+ * @see #numberFormatterSecond
+ * @draft ICU 63
+ */
+ Derived numberFormatterSecond(UnlocalizedNumberFormatter &&formatterSecond) &&;
+
+ /**
+ * Sets the aggressiveness of "collapsing" fields across the range separator. Possible values:
+ * <p>
+ * <ul>
+ * <li>ALL: "3-5K miles"</li>
+ * <li>UNIT: "3K - 5K miles"</li>
+ * <li>NONE: "3K miles - 5K miles"</li>
+ * <li>AUTO: usually UNIT or NONE, depending on the locale and formatter settings</li>
+ * </ul>
+ * <p>
+ * The default value is AUTO.
+ *
+ * @param collapse
+ * The collapsing strategy to use for this range.
+ * @return The fluent chain.
+ * @draft ICU 63
+ */
+ Derived collapse(UNumberRangeCollapse collapse) const &;
+
+ /**
+ * Overload of collapse() for use on an rvalue reference.
+ *
+ * @param collapse
+ * The collapsing strategy to use for this range.
+ * @return The fluent chain.
+ * @see #collapse
+ * @draft ICU 63
+ */
+ Derived collapse(UNumberRangeCollapse collapse) &&;
+
+ /**
+ * Sets the behavior when the two sides of the range are the same. This could happen if the same two numbers are
+ * passed to the formatRange function, or if different numbers are passed to the function but they become the same
+ * after rounding rules are applied. Possible values:
+ * <p>
+ * <ul>
+ * <li>SINGLE_VALUE: "5 miles"</li>
+ * <li>APPROXIMATELY_OR_SINGLE_VALUE: "~5 miles" or "5 miles", depending on whether the number was the same before
+ * rounding was applied</li>
+ * <li>APPROXIMATELY: "~5 miles"</li>
+ * <li>RANGE: "5-5 miles" (with collapse=UNIT)</li>
+ * </ul>
+ * <p>
+ * The default value is APPROXIMATELY.
+ *
+ * @param identityFallback
+ * The strategy to use when formatting two numbers that end up being the same.
+ * @return The fluent chain.
+ * @draft ICU 63
+ */
+ Derived identityFallback(UNumberRangeIdentityFallback identityFallback) const &;
+
+ /**
+ * Overload of identityFallback() for use on an rvalue reference.
+ *
+ * @param identityFallback
+ * The strategy to use when formatting two numbers that end up being the same.
+ * @return The fluent chain.
+ * @see #identityFallback
+ * @draft ICU 63
+ */
+ Derived identityFallback(UNumberRangeIdentityFallback identityFallback) &&;
+
+ /**
+ * Sets the UErrorCode if an error occurred in the fluent chain.
+ * Preserves older error codes in the outErrorCode.
+ * @return TRUE if U_FAILURE(outErrorCode)
+ * @draft ICU 63
+ */
+ UBool copyErrorTo(UErrorCode &outErrorCode) const {
+ if (U_FAILURE(outErrorCode)) {
+ // Do not overwrite the older error code
+ return TRUE;
+ }
+ fMacros.copyErrorTo(outErrorCode);
+ return U_FAILURE(outErrorCode);
+ };
+
+ // NOTE: Uses default copy and move constructors.
+
+ private:
+ impl::RangeMacroProps fMacros;
+
+ // Don't construct me directly! Use (Un)LocalizedNumberFormatter.
+ NumberRangeFormatterSettings() = default;
+
+ friend class LocalizedNumberRangeFormatter;
+ friend class UnlocalizedNumberRangeFormatter;
+};
+
+/**
+ * A NumberRangeFormatter that does not yet have a locale. In order to format, a locale must be specified.
+ *
+ * @see NumberRangeFormatter
+ * @draft ICU 63
+ */
+class U_I18N_API UnlocalizedNumberRangeFormatter
+ : public NumberRangeFormatterSettings<UnlocalizedNumberRangeFormatter>, public UMemory {
+
+ public:
+ /**
+ * Associate the given locale with the number range formatter. The locale is used for picking the
+ * appropriate symbols, formats, and other data for number display.
+ *
+ * @param locale
+ * The locale to use when loading data for number formatting.
+ * @return The fluent chain.
+ * @draft ICU 63
+ */
+ LocalizedNumberRangeFormatter locale(const icu::Locale &locale) const &;
+
+ /**
+ * Overload of locale() for use on an rvalue reference.
+ *
+ * @param locale
+ * The locale to use when loading data for number formatting.
+ * @return The fluent chain.
+ * @see #locale
+ * @draft ICU 63
+ */
+ LocalizedNumberRangeFormatter locale(const icu::Locale &locale) &&;
+
+ /**
+ * Default constructor: puts the formatter into a valid but undefined state.
+ *
+ * @draft ICU 63
+ */
+ UnlocalizedNumberRangeFormatter() = default;
+
+ /**
+ * Returns a copy of this UnlocalizedNumberRangeFormatter.
+ * @draft ICU 63
+ */
+ UnlocalizedNumberRangeFormatter(const UnlocalizedNumberRangeFormatter &other);
+
+ /**
+ * Move constructor:
+ * The source UnlocalizedNumberRangeFormatter will be left in a valid but undefined state.
+ * @draft ICU 63
+ */
+ UnlocalizedNumberRangeFormatter(UnlocalizedNumberRangeFormatter&& src) U_NOEXCEPT;
+
+ /**
+ * Copy assignment operator.
+ * @draft ICU 63
+ */
+ UnlocalizedNumberRangeFormatter& operator=(const UnlocalizedNumberRangeFormatter& other);
+
+ /**
+ * Move assignment operator:
+ * The source UnlocalizedNumberRangeFormatter will be left in a valid but undefined state.
+ * @draft ICU 63
+ */
+ UnlocalizedNumberRangeFormatter& operator=(UnlocalizedNumberRangeFormatter&& src) U_NOEXCEPT;
+
+ private:
+ explicit UnlocalizedNumberRangeFormatter(
+ const NumberRangeFormatterSettings<UnlocalizedNumberRangeFormatter>& other);
+
+ explicit UnlocalizedNumberRangeFormatter(
+ NumberRangeFormatterSettings<UnlocalizedNumberRangeFormatter>&& src) U_NOEXCEPT;
+
+ // To give the fluent setters access to this class's constructor:
+ friend class NumberRangeFormatterSettings<UnlocalizedNumberRangeFormatter>;
+
+ // To give NumberRangeFormatter::with() access to this class's constructor:
+ friend class NumberRangeFormatter;
+};
+
+/**
+ * A NumberRangeFormatter that has a locale associated with it; this means .formatRange() methods are available.
+ *
+ * @see NumberFormatter
+ * @draft ICU 63
+ */
+class U_I18N_API LocalizedNumberRangeFormatter
+ : public NumberRangeFormatterSettings<LocalizedNumberRangeFormatter>, public UMemory {
+ public:
+ /**
+ * Format the given Formattables to a string using the settings specified in the NumberRangeFormatter fluent setting
+ * chain.
+ *
+ * @param first
+ * The first number in the range, usually to the left in LTR locales.
+ * @param second
+ * The second number in the range, usually to the right in LTR locales.
+ * @param status
+ * Set if an error occurs while formatting.
+ * @return A FormattedNumberRange object; call .toString() to get the string.
+ * @draft ICU 63
+ */
+ FormattedNumberRange formatFormattableRange(
+ const Formattable& first, const Formattable& second, UErrorCode& status) const;
+
+ /**
+ * Default constructor: puts the formatter into a valid but undefined state.
+ *
+ * @draft ICU 63
+ */
+ LocalizedNumberRangeFormatter() = default;
+
+ /**
+ * Returns a copy of this LocalizedNumberRangeFormatter.
+ * @draft ICU 63
+ */
+ LocalizedNumberRangeFormatter(const LocalizedNumberRangeFormatter &other);
+
+ /**
+ * Move constructor:
+ * The source LocalizedNumberRangeFormatter will be left in a valid but undefined state.
+ * @draft ICU 63
+ */
+ LocalizedNumberRangeFormatter(LocalizedNumberRangeFormatter&& src) U_NOEXCEPT;
+
+ /**
+ * Copy assignment operator.
+ * @draft ICU 63
+ */
+ LocalizedNumberRangeFormatter& operator=(const LocalizedNumberRangeFormatter& other);
+
+ /**
+ * Move assignment operator:
+ * The source LocalizedNumberRangeFormatter will be left in a valid but undefined state.
+ * @draft ICU 63
+ */
+ LocalizedNumberRangeFormatter& operator=(LocalizedNumberRangeFormatter&& src) U_NOEXCEPT;
+
+#ifndef U_HIDE_INTERNAL_API
+
+ /**
+ * @param results
+ * The results object. This method will mutate it to save the results.
+ * @param equalBeforeRounding
+ * Whether the number was equal before copying it into a DecimalQuantity.
+ * Used for determining the identity fallback behavior.
+ * @param status
+ * Set if an error occurs while formatting.
+ * @internal
+ */
+ void formatImpl(impl::UFormattedNumberRangeData& results, bool equalBeforeRounding,
+ UErrorCode& status) const;
+
+#endif
+
+ /**
+ * Destruct this LocalizedNumberRangeFormatter, cleaning up any memory it might own.
+ * @draft ICU 63
+ */
+ ~LocalizedNumberRangeFormatter();
+
+ private:
+ std::atomic<impl::NumberRangeFormatterImpl*> fAtomicFormatter = {};
+
+ const impl::NumberRangeFormatterImpl* getFormatter(UErrorCode& stauts) const;
+
+ explicit LocalizedNumberRangeFormatter(
+ const NumberRangeFormatterSettings<LocalizedNumberRangeFormatter>& other);
+
+ explicit LocalizedNumberRangeFormatter(
+ NumberRangeFormatterSettings<LocalizedNumberRangeFormatter>&& src) U_NOEXCEPT;
+
+ LocalizedNumberRangeFormatter(const impl::RangeMacroProps &macros, const Locale &locale);
+
+ LocalizedNumberRangeFormatter(impl::RangeMacroProps &&macros, const Locale &locale);
+
+ void clear();
+
+ // To give the fluent setters access to this class's constructor:
+ friend class NumberRangeFormatterSettings<UnlocalizedNumberRangeFormatter>;
+ friend class NumberRangeFormatterSettings<LocalizedNumberRangeFormatter>;
+
+ // To give UnlocalizedNumberRangeFormatter::locale() access to this class's constructor:
+ friend class UnlocalizedNumberRangeFormatter;
+};
+
+/**
+ * The result of a number range formatting operation. This class allows the result to be exported in several data types,
+ * including a UnicodeString and a FieldPositionIterator.
+ *
+ * @draft ICU 63
+ */
+class U_I18N_API FormattedNumberRange : public UMemory {
+ public:
+ /**
+ * Returns a UnicodeString representation of the formatted number range.
+ *
+ * @param status
+ * Set if an error occurs while formatting the number to the UnicodeString.
+ * @return a UnicodeString containing the localized number range.
+ * @draft ICU 63
+ */
+ UnicodeString toString(UErrorCode& status) const;
+
+ /**
+ * Appends the formatted number range to an Appendable.
+ *
+ * @param appendable
+ * The Appendable to which to append the formatted number range string.
+ * @param status
+ * Set if an error occurs while formatting the number range to the Appendable.
+ * @return The same Appendable, for chaining.
+ * @draft ICU 63
+ * @see Appendable
+ */
+ Appendable &appendTo(Appendable &appendable, UErrorCode& status) const;
+
+ /**
+ * Determines the start (inclusive) and end (exclusive) indices of the next occurrence of the given
+ * <em>field</em> in the output string. This allows you to determine the locations of, for example,
+ * the integer part, fraction part, or symbols.
+ *
+ * If both sides of the range have the same field, the field will occur twice, once before the
+ * range separator and once after the range separator, if applicable.
+ *
+ * If a field occurs just once, calling this method will find that occurrence and return it. If a
+ * field occurs multiple times, this method may be called repeatedly with the following pattern:
+ *
+ * <pre>
+ * FieldPosition fpos(UNUM_INTEGER_FIELD);
+ * while (formattedNumberRange.nextFieldPosition(fpos, status)) {
+ * // do something with fpos.
+ * }
+ * </pre>
+ *
+ * This method is useful if you know which field to query. If you want all available field position
+ * information, use #getAllFieldPositions().
+ *
+ * @param fieldPosition
+ * Input+output variable. See {@link FormattedNumber#nextFieldPosition}.
+ * @param status
+ * Set if an error occurs while populating the FieldPosition.
+ * @return TRUE if a new occurrence of the field was found; FALSE otherwise.
+ * @draft ICU 63
+ * @see UNumberFormatFields
+ */
+ UBool nextFieldPosition(FieldPosition& fieldPosition, UErrorCode& status) const;
+
+ /**
+ * Export the formatted number range to a FieldPositionIterator. This allows you to determine which characters in
+ * the output string correspond to which <em>fields</em>, such as the integer part, fraction part, and sign.
+ *
+ * If information on only one field is needed, use #nextFieldPosition() instead.
+ *
+ * @param iterator
+ * The FieldPositionIterator to populate with all of the fields present in the formatted number.
+ * @param status
+ * Set if an error occurs while populating the FieldPositionIterator.
+ * @draft ICU 63
+ * @see UNumberFormatFields
+ */
+ void getAllFieldPositions(FieldPositionIterator &iterator, UErrorCode &status) const;
+
+ /**
+ * Export the first formatted number as a decimal number. This endpoint
+ * is useful for obtaining the exact number being printed after scaling
+ * and rounding have been applied by the number range formatting pipeline.
+ *
+ * The syntax of the unformatted number is a "numeric string"
+ * as defined in the Decimal Arithmetic Specification, available at
+ * http://speleotrove.com/decimal
+ *
+ * @return A decimal representation of the first formatted number.
+ * @draft ICU 63
+ * @see NumberRangeFormatter
+ * @see #getSecondDecimal
+ */
+ UnicodeString getFirstDecimal(UErrorCode& status) const;
+
+ /**
+ * Export the second formatted number as a decimal number. This endpoint
+ * is useful for obtaining the exact number being printed after scaling
+ * and rounding have been applied by the number range formatting pipeline.
+ *
+ * The syntax of the unformatted number is a "numeric string"
+ * as defined in the Decimal Arithmetic Specification, available at
+ * http://speleotrove.com/decimal
+ *
+ * @return A decimal representation of the second formatted number.
+ * @draft ICU 63
+ * @see NumberRangeFormatter
+ * @see #getFirstDecimal
+ */
+ UnicodeString getSecondDecimal(UErrorCode& status) const;
+
+ /**
+ * Returns whether the pair of numbers was successfully formatted as a range or whether an identity fallback was
+ * used. For example, if the first and second number were the same either before or after rounding occurred, an
+ * identity fallback was used.
+ *
+ * @return An indication the resulting identity situation in the formatted number range.
+ * @draft ICU 63
+ * @see UNumberRangeIdentityFallback
+ */
+ UNumberRangeIdentityResult getIdentityResult(UErrorCode& status) const;
+
+ /**
+ * Copying not supported; use move constructor instead.
+ */
+ FormattedNumberRange(const FormattedNumberRange&) = delete;
+
+ /**
+ * Copying not supported; use move assignment instead.
+ */
+ FormattedNumberRange& operator=(const FormattedNumberRange&) = delete;
+
+ /**
+ * Move constructor:
+ * Leaves the source FormattedNumberRange in an undefined state.
+ * @draft ICU 63
+ */
+ FormattedNumberRange(FormattedNumberRange&& src) U_NOEXCEPT;
+
+ /**
+ * Move assignment:
+ * Leaves the source FormattedNumberRange in an undefined state.
+ * @draft ICU 63
+ */
+ FormattedNumberRange& operator=(FormattedNumberRange&& src) U_NOEXCEPT;
+
+ /**
+ * Destruct an instance of FormattedNumberRange, cleaning up any memory it might own.
+ * @draft ICU 63
+ */
+ ~FormattedNumberRange();
+
+ private:
+ // Can't use LocalPointer because UFormattedNumberRangeData is forward-declared
+ const impl::UFormattedNumberRangeData *fResults;
+
+ // Error code for the terminal methods
+ UErrorCode fErrorCode;
+
+ /**
+ * Internal constructor from data type. Adopts the data pointer.
+ * @internal
+ */
+ explicit FormattedNumberRange(impl::UFormattedNumberRangeData *results)
+ : fResults(results), fErrorCode(U_ZERO_ERROR) {};
+
+ explicit FormattedNumberRange(UErrorCode errorCode)
+ : fResults(nullptr), fErrorCode(errorCode) {};
+
+ void getAllFieldPositionsImpl(FieldPositionIteratorHandler& fpih, UErrorCode& status) const;
+
+ // To give LocalizedNumberRangeFormatter format methods access to this class's constructor:
+ friend class LocalizedNumberRangeFormatter;
+};
+
+/**
+ * See the main description in numberrangeformatter.h for documentation and examples.
+ *
+ * @draft ICU 63
+ */
+class U_I18N_API NumberRangeFormatter final {
+ public:
+ /**
+ * Call this method at the beginning of a NumberRangeFormatter fluent chain in which the locale is not currently
+ * known at the call site.
+ *
+ * @return An {@link UnlocalizedNumberRangeFormatter}, to be used for chaining.
+ * @draft ICU 63
+ */
+ static UnlocalizedNumberRangeFormatter with();
+
+ /**
+ * Call this method at the beginning of a NumberRangeFormatter fluent chain in which the locale is known at the call
+ * site.
+ *
+ * @param locale
+ * The locale from which to load formats and symbols for number range formatting.
+ * @return A {@link LocalizedNumberRangeFormatter}, to be used for chaining.
+ * @draft ICU 63
+ */
+ static LocalizedNumberRangeFormatter withLocale(const Locale &locale);
+
+ /**
+ * Use factory methods instead of the constructor to create a NumberFormatter.
+ */
+ NumberRangeFormatter() = delete;
+};
+
+} // namespace number
+U_NAMESPACE_END
+
+#endif // U_HIDE_DRAFT_API
+
+#endif // __NUMBERRANGEFORMATTER_H__
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/deps/icu-small/source/i18n/unicode/numfmt.h b/deps/icu-small/source/i18n/unicode/numfmt.h
index 572e6afc71..871fbd93e1 100644
--- a/deps/icu-small/source/i18n/unicode/numfmt.h
+++ b/deps/icu-small/source/i18n/unicode/numfmt.h
@@ -56,7 +56,6 @@ class StringEnumeration;
* <p><strong>IMPORTANT:</strong> New users are strongly encouraged to see if
* numberformatter.h fits their use case. Although not deprecated, this header
* is provided for backwards compatibility only.
- * <hr/>
*
* Abstract base class for all number formats. Provides interface for
* formatting and parsing a number. Also provides methods for
@@ -710,7 +709,7 @@ public:
* The default formatting style is locale dependent.
* <p>
* <strong>NOTE:</strong> New users are strongly encouraged to use
- * {@link NumberFormatter} instead of NumberFormat.
+ * {@link icu::number::NumberFormatter} instead of NumberFormat.
* @stable ICU 2.0
*/
static NumberFormat* U_EXPORT2 createInstance(UErrorCode&);
@@ -721,7 +720,7 @@ public:
* @param inLocale the given locale.
* <p>
* <strong>NOTE:</strong> New users are strongly encouraged to use
- * {@link NumberFormatter} instead of NumberFormat.
+ * {@link icu::number::NumberFormatter} instead of NumberFormat.
* @stable ICU 2.0
*/
static NumberFormat* U_EXPORT2 createInstance(const Locale& inLocale,
@@ -731,7 +730,7 @@ public:
* Create a specific style NumberFormat for the specified locale.
* <p>
* <strong>NOTE:</strong> New users are strongly encouraged to use
- * {@link NumberFormatter} instead of NumberFormat.
+ * {@link icu::number::NumberFormatter} instead of NumberFormat.
* @param desiredLocale the given locale.
* @param style the given style.
* @param errorCode Output param filled with success/failure status.
@@ -770,7 +769,7 @@ public:
* Returns a currency format for the current default locale.
* <p>
* <strong>NOTE:</strong> New users are strongly encouraged to use
- * {@link NumberFormatter} instead of NumberFormat.
+ * {@link icu::number::NumberFormatter} instead of NumberFormat.
* @stable ICU 2.0
*/
static NumberFormat* U_EXPORT2 createCurrencyInstance(UErrorCode&);
@@ -779,7 +778,7 @@ public:
* Returns a currency format for the specified locale.
* <p>
* <strong>NOTE:</strong> New users are strongly encouraged to use
- * {@link NumberFormatter} instead of NumberFormat.
+ * {@link icu::number::NumberFormatter} instead of NumberFormat.
* @param inLocale the given locale.
* @stable ICU 2.0
*/
@@ -790,7 +789,7 @@ public:
* Returns a percentage format for the current default locale.
* <p>
* <strong>NOTE:</strong> New users are strongly encouraged to use
- * {@link NumberFormatter} instead of NumberFormat.
+ * {@link icu::number::NumberFormatter} instead of NumberFormat.
* @stable ICU 2.0
*/
static NumberFormat* U_EXPORT2 createPercentInstance(UErrorCode&);
@@ -799,7 +798,7 @@ public:
* Returns a percentage format for the specified locale.
* <p>
* <strong>NOTE:</strong> New users are strongly encouraged to use
- * {@link NumberFormatter} instead of NumberFormat.
+ * {@link icu::number::NumberFormatter} instead of NumberFormat.
* @param inLocale the given locale.
* @stable ICU 2.0
*/
@@ -810,7 +809,7 @@ public:
* Returns a scientific format for the current default locale.
* <p>
* <strong>NOTE:</strong> New users are strongly encouraged to use
- * {@link NumberFormatter} instead of NumberFormat.
+ * {@link icu::number::NumberFormatter} instead of NumberFormat.
* @stable ICU 2.0
*/
static NumberFormat* U_EXPORT2 createScientificInstance(UErrorCode&);
@@ -819,7 +818,7 @@ public:
* Returns a scientific format for the specified locale.
* <p>
* <strong>NOTE:</strong> New users are strongly encouraged to use
- * {@link NumberFormatter} instead of NumberFormat.
+ * {@link icu::number::NumberFormatter} instead of NumberFormat.
* @param inLocale the given locale.
* @stable ICU 2.0
*/
@@ -1028,14 +1027,14 @@ public:
* Get the rounding mode. This will always return NumberFormat::ERoundingMode::kRoundUnnecessary
* if the subclass does not support rounding.
* @return A rounding mode
- * @draft ICU 60
+ * @stable ICU 60
*/
virtual ERoundingMode getRoundingMode(void) const;
/**
* Set the rounding mode. If a subclass does not support rounding, this will do nothing.
* @param roundingMode A rounding mode
- * @draft ICU 60
+ * @stable ICU 60
*/
virtual void setRoundingMode(ERoundingMode roundingMode);
diff --git a/deps/icu-small/source/i18n/unicode/plurfmt.h b/deps/icu-small/source/i18n/unicode/plurfmt.h
index 9a83e52550..6b757c8841 100644
--- a/deps/icu-small/source/i18n/unicode/plurfmt.h
+++ b/deps/icu-small/source/i18n/unicode/plurfmt.h
@@ -520,15 +520,7 @@ public:
*/
virtual UClassID getDynamicClassID() const;
-#if (defined(__xlC__) && (__xlC__ < 0x0C00)) || (U_PLATFORM == U_PF_OS390) || (U_PLATFORM ==U_PF_OS400)
-// Work around a compiler bug on xlC 11.1 on AIX 7.1 that would
-// prevent PluralSelectorAdapter from implementing private PluralSelector.
-// xlC error message:
-// 1540-0300 (S) The "private" member "class icu_49::PluralFormat::PluralSelector" cannot be accessed.
-public:
-#else
private:
-#endif
/**
* @internal
*/
@@ -564,10 +556,6 @@ private:
PluralRules* pluralRules;
};
-#if defined(__xlC__)
-// End of xlC bug workaround, keep remaining definitions private.
-private:
-#endif
Locale locale;
MessagePattern msgPattern;
NumberFormat* numberFormat;
diff --git a/deps/icu-small/source/i18n/unicode/plurrule.h b/deps/icu-small/source/i18n/unicode/plurrule.h
index 03dea3f1b9..daeed52bee 100644
--- a/deps/icu-small/source/i18n/unicode/plurrule.h
+++ b/deps/icu-small/source/i18n/unicode/plurrule.h
@@ -118,7 +118,6 @@ class SharedPluralRules;
* Examples are in the following table:
* </p>
* <table border='1' style="border-collapse:collapse">
- * <tbody>
* <tr>
* <th>n</th>
* <th>i</th>
@@ -155,7 +154,6 @@ class SharedPluralRules;
* <td align="right">23</td>
* <td>2</td>
* </tr>
- * </tbody>
* </table>
* <p>
* The difference between 'in' and 'within' is that 'in' only includes integers in the specified range, while 'within'
@@ -499,6 +497,12 @@ private:
UnicodeString getRuleFromResource(const Locale& locale, UPluralType type, UErrorCode& status);
RuleChain *rulesForKeyword(const UnicodeString &keyword) const;
+ /**
+ * An internal status variable used to indicate that the object is in an 'invalid' state.
+ * Used by copy constructor, the assignment operator and the clone method.
+ */
+ UErrorCode mInternalStatus;
+
friend class PluralRuleParser;
};
diff --git a/deps/icu-small/source/i18n/unicode/rbnf.h b/deps/icu-small/source/i18n/unicode/rbnf.h
index 2d284909f8..f7cd85a322 100644
--- a/deps/icu-small/source/i18n/unicode/rbnf.h
+++ b/deps/icu-small/source/i18n/unicode/rbnf.h
@@ -313,7 +313,6 @@ enum URBNFRuleSetTag {
* <td>The rule for an IEEE 754 NaN (not a number).</td>
* </tr>
* <tr>
- * <tr>
* <td><em>nothing</em></td>
* <td>If the rule's rule descriptor is left out, the base value is one plus the
* preceding rule's base value (or zero if this is the first rule in the list) in a normal
@@ -1013,14 +1012,14 @@ public:
/**
* Get the rounding mode.
* @return A rounding mode
- * @draft ICU 60
+ * @stable ICU 60
*/
virtual ERoundingMode getRoundingMode(void) const;
/**
* Set the rounding mode.
* @param roundingMode A rounding mode
- * @draft ICU 60
+ * @stable ICU 60
*/
virtual void setRoundingMode(ERoundingMode roundingMode);
@@ -1095,7 +1094,7 @@ private:
void format(double number, NFRuleSet& rs, UnicodeString& toAppendTo, UErrorCode& status) const;
private:
- NFRuleSet **ruleSets;
+ NFRuleSet **fRuleSets;
UnicodeString* ruleSetDescriptions;
int32_t numRuleSets;
NFRuleSet *defaultRuleSet;
@@ -1104,7 +1103,7 @@ private:
DecimalFormatSymbols* decimalFormatSymbols;
NFRule *defaultInfinityRule;
NFRule *defaultNaNRule;
- ERoundingMode roundingMode;
+ ERoundingMode fRoundingMode;
UBool lenient;
UnicodeString* lenientParseRules;
LocalizationInfo* localizations;
diff --git a/deps/icu-small/source/i18n/unicode/region.h b/deps/icu-small/source/i18n/unicode/region.h
index 667c4051f0..ccd63901a5 100644
--- a/deps/icu-small/source/i18n/unicode/region.h
+++ b/deps/icu-small/source/i18n/unicode/region.h
@@ -192,7 +192,7 @@ private:
char id[4];
UnicodeString idStr;
int32_t code;
- URegionType type;
+ URegionType fType;
Region *containingRegion;
UVector *containedRegions;
UVector *preferredValues;
diff --git a/deps/icu-small/source/i18n/unicode/reldatefmt.h b/deps/icu-small/source/i18n/unicode/reldatefmt.h
index abd43522c3..dd8bc53d55 100644
--- a/deps/icu-small/source/i18n/unicode/reldatefmt.h
+++ b/deps/icu-small/source/i18n/unicode/reldatefmt.h
@@ -165,12 +165,20 @@ typedef enum UDateAbsoluteUnit {
*/
UDAT_ABSOLUTE_NOW,
+#ifndef U_HIDE_DRAFT_API
+ /**
+ * Quarter
+ * @draft ICU 63
+ */
+ UDAT_ABSOLUTE_QUARTER,
+#endif // U_HIDE_DRAFT_API
+
#ifndef U_HIDE_DEPRECATED_API
/**
* One more than the highest normal UDateAbsoluteUnit value.
* @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420.
*/
- UDAT_ABSOLUTE_UNIT_COUNT
+ UDAT_ABSOLUTE_UNIT_COUNT = UDAT_ABSOLUTE_NOW + 2
#endif // U_HIDE_DEPRECATED_API
} UDateAbsoluteUnit;
@@ -328,7 +336,7 @@ public:
* @param nfToAdopt Constructed object takes ownership of this pointer.
* It is an error for caller to delete this pointer or change its
* contents after calling this constructor.
- * @status Any error is returned here.
+ * @param status Any error is returned here.
* @stable ICU 53
*/
RelativeDateTimeFormatter(
@@ -346,7 +354,7 @@ public:
* @param style the format style. The UDAT_RELATIVE bit field has no effect.
* @param capitalizationContext A value from UDisplayContext that pertains to
* capitalization.
- * @status Any error is returned here.
+ * @param status Any error is returned here.
* @stable ICU 54
*/
RelativeDateTimeFormatter(
diff --git a/deps/icu-small/source/i18n/unicode/smpdtfmt.h b/deps/icu-small/source/i18n/unicode/smpdtfmt.h
index 305412b8d1..929c1b4675 100644
--- a/deps/icu-small/source/i18n/unicode/smpdtfmt.h
+++ b/deps/icu-small/source/i18n/unicode/smpdtfmt.h
@@ -1147,7 +1147,7 @@ public:
* Overrides base class method and
* This method clears per field NumberFormat instances
* previously set by {@see adoptNumberFormat(const UnicodeString&, NumberFormat*, UErrorCode)}
- * @param adoptNF the NumbeferFormat used
+ * @param formatToAdopt the NumbeferFormat used
* @stable ICU 54
*/
void adoptNumberFormat(NumberFormat *formatToAdopt);
@@ -1162,7 +1162,7 @@ public:
* Per field NumberFormat can also be cleared in {@see DateFormat::setNumberFormat(const NumberFormat& newNumberFormat)}
*
* @param fields the fields to override(like y)
- * @param adoptNF the NumbeferFormat used
+ * @param formatToAdopt the NumbeferFormat used
* @param status Receives a status code, which will be U_ZERO_ERROR
* if the operation succeeds.
* @stable ICU 54
diff --git a/deps/icu-small/source/i18n/unicode/translit.h b/deps/icu-small/source/i18n/unicode/translit.h
index dc31d97bc6..6b4888145f 100644
--- a/deps/icu-small/source/i18n/unicode/translit.h
+++ b/deps/icu-small/source/i18n/unicode/translit.h
@@ -31,7 +31,6 @@ U_NAMESPACE_BEGIN
class UnicodeFilter;
class UnicodeSet;
-class CompoundTransliterator;
class TransliteratorParser;
class NormalizationTransliterator;
class TransliteratorIDParser;
@@ -77,8 +76,7 @@ class TransliteratorIDParser;
* transliteration. For example, given a string <code>input</code>
* and a transliterator <code>t</code>, the call
*
- * \htmlonly<blockquote>\endhtmlonly<code>String result = t.transliterate(input);
- * </code>\htmlonly</blockquote>\endhtmlonly
+ * String result = t.transliterate(input);
*
* will transliterate it and return the result. Other methods allow
* the client to specify a substring to be transliterated and to use
@@ -98,22 +96,20 @@ class TransliteratorIDParser;
* contents of the buffer may show text being modified as each new
* character arrives.
*
- * <p>Consider the simple <code>RuleBasedTransliterator</code>:
- *
- * \htmlonly<blockquote>\endhtmlonly<code>
- * th&gt;{theta}<br>
- * t&gt;{tau}
- * </code>\htmlonly</blockquote>\endhtmlonly
+ * <p>Consider the simple rule-based Transliterator:
+ * <pre>
+ * th>{theta}
+ * t>{tau}
+ * </pre>
*
* When the user types 't', nothing will happen, since the
* transliterator is waiting to see if the next character is 'h'. To
* remedy this, we introduce the notion of a cursor, marked by a '|'
* in the output string:
- *
- * \htmlonly<blockquote>\endhtmlonly<code>
- * t&gt;|{tau}<br>
- * {tau}h&gt;{theta}
- * </code>\htmlonly</blockquote>\endhtmlonly
+ * <pre>
+ * t>|{tau}
+ * {tau}h>{theta}
+ * </pre>
*
* Now when the user types 't', tau appears, and if the next character
* is 'h', the tau changes to a theta. This is accomplished by
@@ -135,7 +131,7 @@ class TransliteratorIDParser;
* which the transliterator last stopped, either because it reached
* the end, or because it required more characters to disambiguate
* between possible inputs. The <code>CURSOR</code> can also be
- * explicitly set by rules in a <code>RuleBasedTransliterator</code>.
+ * explicitly set by rules in a rule-based Transliterator.
* Any characters before the <code>CURSOR</code> index are frozen;
* future keyboard transliteration calls within this input sequence
* will not change them. New text is inserted at the
@@ -237,6 +233,255 @@ class TransliteratorIDParser;
* if the performance of these methods can be improved over the
* performance obtained by the default implementations in this class.
*
+ * <p><b>Rule syntax</b>
+ *
+ * <p>A set of rules determines how to perform translations.
+ * Rules within a rule set are separated by semicolons (';').
+ * To include a literal semicolon, prefix it with a backslash ('\').
+ * Unicode Pattern_White_Space is ignored.
+ * If the first non-blank character on a line is '#',
+ * the entire line is ignored as a comment.
+ *
+ * <p>Each set of rules consists of two groups, one forward, and one
+ * reverse. This is a convention that is not enforced; rules for one
+ * direction may be omitted, with the result that translations in
+ * that direction will not modify the source text. In addition,
+ * bidirectional forward-reverse rules may be specified for
+ * symmetrical transformations.
+ *
+ * <p>Note: Another description of the Transliterator rule syntax is available in
+ * <a href="https://www.unicode.org/reports/tr35/tr35-general.html#Transform_Rules_Syntax">section
+ * Transform Rules Syntax of UTS #35: Unicode LDML</a>.
+ * The rules are shown there using arrow symbols ← and → and ↔.
+ * ICU supports both those and the equivalent ASCII symbols &lt; and &gt; and &lt;&gt;.
+ *
+ * <p>Rule statements take one of the following forms:
+ *
+ * <dl>
+ * <dt><code>$alefmadda=\\u0622;</code></dt>
+ * <dd><strong>Variable definition.</strong> The name on the
+ * left is assigned the text on the right. In this example,
+ * after this statement, instances of the left hand name,
+ * &quot;<code>$alefmadda</code>&quot;, will be replaced by
+ * the Unicode character U+0622. Variable names must begin
+ * with a letter and consist only of letters, digits, and
+ * underscores. Case is significant. Duplicate names cause
+ * an exception to be thrown, that is, variables cannot be
+ * redefined. The right hand side may contain well-formed
+ * text of any length, including no text at all (&quot;<code>$empty=;</code>&quot;).
+ * The right hand side may contain embedded <code>UnicodeSet</code>
+ * patterns, for example, &quot;<code>$softvowel=[eiyEIY]</code>&quot;.</dd>
+ * <dt><code>ai&gt;$alefmadda;</code></dt>
+ * <dd><strong>Forward translation rule.</strong> This rule
+ * states that the string on the left will be changed to the
+ * string on the right when performing forward
+ * transliteration.</dd>
+ * <dt><code>ai&lt;$alefmadda;</code></dt>
+ * <dd><strong>Reverse translation rule.</strong> This rule
+ * states that the string on the right will be changed to
+ * the string on the left when performing reverse
+ * transliteration.</dd>
+ * </dl>
+ *
+ * <dl>
+ * <dt><code>ai&lt;&gt;$alefmadda;</code></dt>
+ * <dd><strong>Bidirectional translation rule.</strong> This
+ * rule states that the string on the right will be changed
+ * to the string on the left when performing forward
+ * transliteration, and vice versa when performing reverse
+ * transliteration.</dd>
+ * </dl>
+ *
+ * <p>Translation rules consist of a <em>match pattern</em> and an <em>output
+ * string</em>. The match pattern consists of literal characters,
+ * optionally preceded by context, and optionally followed by
+ * context. Context characters, like literal pattern characters,
+ * must be matched in the text being transliterated. However, unlike
+ * literal pattern characters, they are not replaced by the output
+ * text. For example, the pattern &quot;<code>abc{def}</code>&quot;
+ * indicates the characters &quot;<code>def</code>&quot; must be
+ * preceded by &quot;<code>abc</code>&quot; for a successful match.
+ * If there is a successful match, &quot;<code>def</code>&quot; will
+ * be replaced, but not &quot;<code>abc</code>&quot;. The final '<code>}</code>'
+ * is optional, so &quot;<code>abc{def</code>&quot; is equivalent to
+ * &quot;<code>abc{def}</code>&quot;. Another example is &quot;<code>{123}456</code>&quot;
+ * (or &quot;<code>123}456</code>&quot;) in which the literal
+ * pattern &quot;<code>123</code>&quot; must be followed by &quot;<code>456</code>&quot;.
+ *
+ * <p>The output string of a forward or reverse rule consists of
+ * characters to replace the literal pattern characters. If the
+ * output string contains the character '<code>|</code>', this is
+ * taken to indicate the location of the <em>cursor</em> after
+ * replacement. The cursor is the point in the text at which the
+ * next replacement, if any, will be applied. The cursor is usually
+ * placed within the replacement text; however, it can actually be
+ * placed into the precending or following context by using the
+ * special character '@'. Examples:
+ *
+ * <pre>
+ * a {foo} z &gt; | @ bar; # foo -&gt; bar, move cursor before a
+ * {foo} xyz &gt; bar @@|; #&nbsp;foo -&gt; bar, cursor between y and z
+ * </pre>
+ *
+ * <p><b>UnicodeSet</b>
+ *
+ * <p><code>UnicodeSet</code> patterns may appear anywhere that
+ * makes sense. They may appear in variable definitions.
+ * Contrariwise, <code>UnicodeSet</code> patterns may themselves
+ * contain variable references, such as &quot;<code>$a=[a-z];$not_a=[^$a]</code>&quot;,
+ * or &quot;<code>$range=a-z;$ll=[$range]</code>&quot;.
+ *
+ * <p><code>UnicodeSet</code> patterns may also be embedded directly
+ * into rule strings. Thus, the following two rules are equivalent:
+ *
+ * <pre>
+ * $vowel=[aeiou]; $vowel&gt;'*'; # One way to do this
+ * [aeiou]&gt;'*'; # Another way
+ * </pre>
+ *
+ * <p>See {@link UnicodeSet} for more documentation and examples.
+ *
+ * <p><b>Segments</b>
+ *
+ * <p>Segments of the input string can be matched and copied to the
+ * output string. This makes certain sets of rules simpler and more
+ * general, and makes reordering possible. For example:
+ *
+ * <pre>
+ * ([a-z]) &gt; $1 $1; # double lowercase letters
+ * ([:Lu:]) ([:Ll:]) &gt; $2 $1; # reverse order of Lu-Ll pairs
+ * </pre>
+ *
+ * <p>The segment of the input string to be copied is delimited by
+ * &quot;<code>(</code>&quot; and &quot;<code>)</code>&quot;. Up to
+ * nine segments may be defined. Segments may not overlap. In the
+ * output string, &quot;<code>$1</code>&quot; through &quot;<code>$9</code>&quot;
+ * represent the input string segments, in left-to-right order of
+ * definition.
+ *
+ * <p><b>Anchors</b>
+ *
+ * <p>Patterns can be anchored to the beginning or the end of the text. This is done with the
+ * special characters '<code>^</code>' and '<code>$</code>'. For example:
+ *
+ * <pre>
+ * ^ a&nbsp;&nbsp; &gt; 'BEG_A'; &nbsp;&nbsp;# match 'a' at start of text
+ * &nbsp; a&nbsp;&nbsp; &gt; 'A'; # match other instances of 'a'
+ * &nbsp; z $ &gt; 'END_Z'; &nbsp;&nbsp;# match 'z' at end of text
+ * &nbsp; z&nbsp;&nbsp; &gt; 'Z';&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # match other instances of 'z'
+ * </pre>
+ *
+ * <p>It is also possible to match the beginning or the end of the text using a <code>UnicodeSet</code>.
+ * This is done by including a virtual anchor character '<code>$</code>' at the end of the
+ * set pattern. Although this is usually the match chafacter for the end anchor, the set will
+ * match either the beginning or the end of the text, depending on its placement. For
+ * example:
+ *
+ * <pre>
+ * $x = [a-z$]; &nbsp;&nbsp;# match 'a' through 'z' OR anchor
+ * $x 1&nbsp;&nbsp;&nbsp; &gt; 2;&nbsp;&nbsp; # match '1' after a-z or at the start
+ * &nbsp;&nbsp; 3 $x &gt; 4; &nbsp;&nbsp;# match '3' before a-z or at the end
+ * </pre>
+ *
+ * <p><b>Example</b>
+ *
+ * <p>The following example rules illustrate many of the features of
+ * the rule language.
+ *
+ * <table border="0" cellpadding="4">
+ * <tr>
+ * <td style="vertical-align: top;">Rule 1.</td>
+ * <td style="vertical-align: top; write-space: nowrap;"><code>abc{def}&gt;x|y</code></td>
+ * </tr>
+ * <tr>
+ * <td style="vertical-align: top;">Rule 2.</td>
+ * <td style="vertical-align: top; write-space: nowrap;"><code>xyz&gt;r</code></td>
+ * </tr>
+ * <tr>
+ * <td style="vertical-align: top;">Rule 3.</td>
+ * <td style="vertical-align: top; write-space: nowrap;"><code>yz&gt;q</code></td>
+ * </tr>
+ * </table>
+ *
+ * <p>Applying these rules to the string &quot;<code>adefabcdefz</code>&quot;
+ * yields the following results:
+ *
+ * <table border="0" cellpadding="4">
+ * <tr>
+ * <td style="vertical-align: top; write-space: nowrap;"><code>|adefabcdefz</code></td>
+ * <td style="vertical-align: top;">Initial state, no rules match. Advance
+ * cursor.</td>
+ * </tr>
+ * <tr>
+ * <td style="vertical-align: top; write-space: nowrap;"><code>a|defabcdefz</code></td>
+ * <td style="vertical-align: top;">Still no match. Rule 1 does not match
+ * because the preceding context is not present.</td>
+ * </tr>
+ * <tr>
+ * <td style="vertical-align: top; write-space: nowrap;"><code>ad|efabcdefz</code></td>
+ * <td style="vertical-align: top;">Still no match. Keep advancing until
+ * there is a match...</td>
+ * </tr>
+ * <tr>
+ * <td style="vertical-align: top; write-space: nowrap;"><code>ade|fabcdefz</code></td>
+ * <td style="vertical-align: top;">...</td>
+ * </tr>
+ * <tr>
+ * <td style="vertical-align: top; write-space: nowrap;"><code>adef|abcdefz</code></td>
+ * <td style="vertical-align: top;">...</td>
+ * </tr>
+ * <tr>
+ * <td style="vertical-align: top; write-space: nowrap;"><code>adefa|bcdefz</code></td>
+ * <td style="vertical-align: top;">...</td>
+ * </tr>
+ * <tr>
+ * <td style="vertical-align: top; write-space: nowrap;"><code>adefab|cdefz</code></td>
+ * <td style="vertical-align: top;">...</td>
+ * </tr>
+ * <tr>
+ * <td style="vertical-align: top; write-space: nowrap;"><code>adefabc|defz</code></td>
+ * <td style="vertical-align: top;">Rule 1 matches; replace &quot;<code>def</code>&quot;
+ * with &quot;<code>xy</code>&quot; and back up the cursor
+ * to before the '<code>y</code>'.</td>
+ * </tr>
+ * <tr>
+ * <td style="vertical-align: top; write-space: nowrap;"><code>adefabcx|yz</code></td>
+ * <td style="vertical-align: top;">Although &quot;<code>xyz</code>&quot; is
+ * present, rule 2 does not match because the cursor is
+ * before the '<code>y</code>', not before the '<code>x</code>'.
+ * Rule 3 does match. Replace &quot;<code>yz</code>&quot;
+ * with &quot;<code>q</code>&quot;.</td>
+ * </tr>
+ * <tr>
+ * <td style="vertical-align: top; write-space: nowrap;"><code>adefabcxq|</code></td>
+ * <td style="vertical-align: top;">The cursor is at the end;
+ * transliteration is complete.</td>
+ * </tr>
+ * </table>
+ *
+ * <p>The order of rules is significant. If multiple rules may match
+ * at some point, the first matching rule is applied.
+ *
+ * <p>Forward and reverse rules may have an empty output string.
+ * Otherwise, an empty left or right hand side of any statement is a
+ * syntax error.
+ *
+ * <p>Single quotes are used to quote any character other than a
+ * digit or letter. To specify a single quote itself, inside or
+ * outside of quotes, use two single quotes in a row. For example,
+ * the rule &quot;<code>'&gt;'&gt;o''clock</code>&quot; changes the
+ * string &quot;<code>&gt;</code>&quot; to the string &quot;<code>o'clock</code>&quot;.
+ *
+ * <p><b>Notes</b>
+ *
+ * <p>While a Transliterator is being built from rules, it checks that
+ * the rules are added in proper order. For example, if the rule
+ * &quot;a&gt;x&quot; is followed by the rule &quot;ab&gt;y&quot;,
+ * then the second rule will throw an exception. The reason is that
+ * the second rule can never be triggered, since the first rule
+ * always matches anything it matches. In other words, the first
+ * rule <em>masks</em> the second rule.
+ *
* @author Alan Liu
* @stable ICU 2.0
*/
@@ -499,9 +744,9 @@ public:
* for details.
* @param text the buffer holding transliterated and
* untransliterated text
- * @param index an array of three integers. See {@link #transliterate(Replaceable&, UTransPosition&, const UnicodeString*, UErrorCode&) const }.
+ * @param index an array of three integers.
* @param status Output param to filled in with a success or an error.
- * @see #transliterate(Replaceable, int[], String)
+ * @see #transliterate(Replaceable&, UTransPosition&, const UnicodeString&, UErrorCode &) const
* @stable ICU 2.0
*/
virtual void transliterate(Replaceable& text, UTransPosition& index,
@@ -632,7 +877,7 @@ public:
/**
* Transliterate a substring of text, as specified by index, taking filters
* into account. This method is for subclasses that need to delegate to
- * another transliterator, such as CompoundTransliterator.
+ * another transliterator.
* @param text the text to be transliterated
* @param index the position indices
* @param incremental if TRUE, then assume more characters may be inserted
@@ -846,17 +1091,19 @@ public:
/**
* Returns a <code>Transliterator</code> object constructed from
- * the given rule string. This will be a RuleBasedTransliterator,
+ * the given rule string. This will be a rule-based Transliterator,
* if the rule string contains only rules, or a
- * CompoundTransliterator, if it contains ID blocks, or a
- * NullTransliterator, if it contains ID blocks which parse as
+ * compound Transliterator, if it contains ID blocks, or a
+ * null Transliterator, if it contains ID blocks which parse as
* empty for the given direction.
+ *
* @param ID the id for the transliterator.
* @param rules rules, separated by ';'
* @param dir either FORWARD or REVERSE.
- * @param parseError Struct to recieve information on position
+ * @param parseError Struct to receive information on position
* of error if an error is encountered
* @param status Output param set to success/failure code.
+ * @return a newly created Transliterator
* @stable ICU 2.0
*/
static Transliterator* U_EXPORT2 createFromRules(const UnicodeString& ID,
diff --git a/deps/icu-small/source/i18n/unicode/tzfmt.h b/deps/icu-small/source/i18n/unicode/tzfmt.h
index 633cd8dc69..d2aa768b8c 100644
--- a/deps/icu-small/source/i18n/unicode/tzfmt.h
+++ b/deps/icu-small/source/i18n/unicode/tzfmt.h
@@ -237,10 +237,10 @@ typedef enum UTimeZoneFormatParseOption {
*/
UTZFMT_PARSE_OPTION_ALL_STYLES = 0x01,
/**
- * When parsing a time zone display name in UTZFMT_STYLE_SPECIFIC_SHORT,
+ * When parsing a time zone display name in \link UTZFMT_STYLE_SPECIFIC_SHORT \endlink,
* look for the IANA tz database compatible zone abbreviations in addition
- * to the localized names coming from the {@link TimeZoneNames} currently
- * used by the {@link TimeZoneFormat}.
+ * to the localized names coming from the icu::TimeZoneNames currently
+ * used by the icu::TimeZoneFormat.
* @stable ICU 54
*/
UTZFMT_PARSE_OPTION_TZ_DATABASE_ABBREVIATIONS = 0x02
diff --git a/deps/icu-small/source/i18n/unicode/ucal.h b/deps/icu-small/source/i18n/unicode/ucal.h
index 10d8bc5274..889a1ec51d 100644
--- a/deps/icu-small/source/i18n/unicode/ucal.h
+++ b/deps/icu-small/source/i18n/unicode/ucal.h
@@ -139,6 +139,19 @@
* For example, subtracting 5 days from the date <code>September 12, 1996</code>
* results in <code>September 7, 1996</code>.
*
+ * <p>
+ * The Japanese calendar uses a combination of era name and year number.
+ * When an emperor of Japan abdicates and a new emperor ascends the throne,
+ * a new era is declared and year number is reset to 1. Even if the date of
+ * abdication is scheduled ahead of time, the new era name might not be
+ * announced until just before the date. In such case, ICU4C may include
+ * a start date of future era without actual era name, but not enabled
+ * by default. ICU4C users who want to test the behavior of the future era
+ * can enable the tentative era by:
+ * <ul>
+ * <li>Environment variable <code>ICU_ENABLE_TENTATIVE_ERA=true</code>.</li>
+ * </ul>
+ *
* @stable ICU 2.0
*/
diff --git a/deps/icu-small/source/i18n/unicode/ucol.h b/deps/icu-small/source/i18n/unicode/ucol.h
index b5bacbfcb4..f084ac61e6 100644
--- a/deps/icu-small/source/i18n/unicode/ucol.h
+++ b/deps/icu-small/source/i18n/unicode/ucol.h
@@ -1149,7 +1149,7 @@ ucol_getUCAVersion(const UCollator* coll, UVersionInfo info);
* The recommended way to achieve "merged" sorting is by
* concatenating strings with U+FFFE between them.
* The concatenation has the same sort order as the merged sort keys,
- * but merge(getSortKey(str1), getSortKey(str2)) may differ from getSortKey(str1 + '\uFFFE' + str2).
+ * but merge(getSortKey(str1), getSortKey(str2)) may differ from getSortKey(str1 + '\\uFFFE' + str2).
* Using strings with U+FFFE may yield shorter sort keys.
*
* For details about Sort Key Features see
@@ -1294,6 +1294,7 @@ U_STABLE uint32_t U_EXPORT2 ucol_getVariableTop(const UCollator *coll, UErrorCod
* the top of one of the supported reordering groups,
* and it must not be beyond the last of those groups.
* See ucol_setMaxVariable().
+ * @param coll collator to be set
* @param varTop primary weight, as returned by ucol_setVariableTop or ucol_getVariableTop
* @param status error code
* @see ucol_getVariableTop
diff --git a/deps/icu-small/source/i18n/unicode/ugender.h b/deps/icu-small/source/i18n/unicode/ugender.h
index d015a2300c..903f3dd5de 100644
--- a/deps/icu-small/source/i18n/unicode/ugender.h
+++ b/deps/icu-small/source/i18n/unicode/ugender.h
@@ -49,11 +49,11 @@ enum UGender {
*/
typedef enum UGender UGender;
+struct UGenderInfo;
/**
* Opaque UGenderInfo object for use in C programs.
* @stable ICU 50
*/
-struct UGenderInfo;
typedef struct UGenderInfo UGenderInfo;
/**
@@ -77,7 +77,7 @@ ugender_getInstance(const char *locale, UErrorCode *status);
* @stable ICU 50
*/
U_STABLE UGender U_EXPORT2
-ugender_getListGender(const UGenderInfo* genderinfo, const UGender *genders, int32_t size, UErrorCode *status);
+ugender_getListGender(const UGenderInfo* genderInfo, const UGender *genders, int32_t size, UErrorCode *status);
#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/deps/icu-small/source/i18n/unicode/ulistformatter.h b/deps/icu-small/source/i18n/unicode/ulistformatter.h
new file mode 100644
index 0000000000..242d7d2164
--- /dev/null
+++ b/deps/icu-small/source/i18n/unicode/ulistformatter.h
@@ -0,0 +1,150 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/*
+*****************************************************************************************
+* Copyright (C) 2015-2016, International Business Machines
+* Corporation and others. All Rights Reserved.
+*****************************************************************************************
+*/
+
+#ifndef ULISTFORMATTER_H
+#define ULISTFORMATTER_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/localpointer.h"
+
+/**
+ * \file
+ * \brief C API: Format a list in a locale-appropriate way.
+ *
+ * A UListFormatter is used to format a list of items in a locale-appropriate way,
+ * using data from CLDR.
+ * Example: Input data ["Alice", "Bob", "Charlie", "Delta"] will be formatted
+ * as "Alice, Bob, Charlie, and Delta" in English.
+ */
+
+/**
+ * Opaque UListFormatter object for use in C
+ * @stable ICU 55
+ */
+struct UListFormatter;
+typedef struct UListFormatter UListFormatter; /**< C typedef for struct UListFormatter. @stable ICU 55 */
+
+#ifndef U_HIDE_DRAFT_API
+/**
+ * FieldPosition and UFieldPosition selectors for format fields
+ * defined by ListFormatter.
+ * @draft ICU 63
+ */
+typedef enum UListFormatterField {
+ /**
+ * The literal text in the result which came from the resources.
+ * @draft ICU 63
+ */
+ ULISTFMT_LITERAL_FIELD,
+ /**
+ * The element text in the result which came from the input strings.
+ * @draft ICU 63
+ */
+ ULISTFMT_ELEMENT_FIELD
+} UListFormatterField;
+#endif // U_HIDE_DRAFT_API
+
+/**
+ * Open a new UListFormatter object using the rules for a given locale.
+ * @param locale
+ * The locale whose rules should be used; may be NULL for
+ * default locale.
+ * @param status
+ * A pointer to a standard ICU UErrorCode (input/output parameter).
+ * Its input value must pass the U_SUCCESS() test, or else the
+ * function returns immediately. The caller should check its output
+ * value with U_FAILURE(), or use with function chaining (see User
+ * Guide for details).
+ * @return
+ * A pointer to a UListFormatter object for the specified locale,
+ * or NULL if an error occurred.
+ * @stable ICU 55
+ */
+U_CAPI UListFormatter* U_EXPORT2
+ulistfmt_open(const char* locale,
+ UErrorCode* status);
+
+/**
+ * Close a UListFormatter object. Once closed it may no longer be used.
+ * @param listfmt
+ * The UListFormatter object to close.
+ * @stable ICU 55
+ */
+U_CAPI void U_EXPORT2
+ulistfmt_close(UListFormatter *listfmt);
+
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUListFormatterPointer
+ * "Smart pointer" class, closes a UListFormatter via ulistfmt_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 55
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUListFormatterPointer, UListFormatter, ulistfmt_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * Formats a list of strings using the conventions established for the
+ * UListFormatter object.
+ * @param listfmt
+ * The UListFormatter object specifying the list conventions.
+ * @param strings
+ * An array of pointers to UChar strings; the array length is
+ * specified by stringCount. Must be non-NULL if stringCount > 0.
+ * @param stringLengths
+ * An array of string lengths corresponding to the strings[]
+ * parameter; any individual length value may be negative to indicate
+ * that the corresponding strings[] entry is 0-terminated, or
+ * stringLengths itself may be NULL if all of the strings are
+ * 0-terminated. If non-NULL, the stringLengths array must have
+ * stringCount entries.
+ * @param stringCount
+ * the number of entries in strings[], and the number of entries
+ * in the stringLengths array if it is not NULL. Must be >= 0.
+ * @param result
+ * A pointer to a buffer to receive the formatted list.
+ * @param resultCapacity
+ * The maximum size of result.
+ * @param status
+ * A pointer to a standard ICU UErrorCode (input/output parameter).
+ * Its input value must pass the U_SUCCESS() test, or else the
+ * function returns immediately. The caller should check its output
+ * value with U_FAILURE(), or use with function chaining (see User
+ * Guide for details).
+ * @return
+ * The total buffer size needed; if greater than resultLength, the
+ * output was truncated. May be <=0 if unable to determine the
+ * total buffer size needed (e.g. for illegal arguments).
+ * @stable ICU 55
+ */
+U_CAPI int32_t U_EXPORT2
+ulistfmt_format(const UListFormatter* listfmt,
+ const UChar* const strings[],
+ const int32_t * stringLengths,
+ int32_t stringCount,
+ UChar* result,
+ int32_t resultCapacity,
+ UErrorCode* status);
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
diff --git a/deps/icu-small/source/i18n/unicode/unumberformatter.h b/deps/icu-small/source/i18n/unicode/unumberformatter.h
index b37f80c503..d05b15cdec 100644
--- a/deps/icu-small/source/i18n/unicode/unumberformatter.h
+++ b/deps/icu-small/source/i18n/unicode/unumberformatter.h
@@ -91,7 +91,7 @@
* </ul>
*
* <p>
- * This enum is similar to {@link com.ibm.icu.text.MeasureFormat.FormatWidth}.
+ * This enum is similar to {@link UMeasureFormatWidth}.
*
* @draft ICU 60
*/
@@ -190,10 +190,9 @@ typedef enum UNumberUnitWidth {
* Note: This enum specifies the strategy for grouping sizes. To set which character to use as the
* grouping separator, use the "symbols" setter.
*
- * @draft ICU 61 -- TODO: This should be renamed to UNumberGroupingStrategy before promoting to stable,
- * for consistency with the other enums.
+ * @draft ICU 63
*/
-typedef enum UGroupingStrategy {
+typedef enum UNumberGroupingStrategy {
/**
* Do not display grouping separators in any locale.
*
@@ -254,16 +253,28 @@ typedef enum UGroupingStrategy {
*
* @draft ICU 61
*/
- UNUM_GROUPING_THOUSANDS,
+ UNUM_GROUPING_THOUSANDS
+#ifndef U_HIDE_INTERNAL_API
+ ,
/**
- * One more than the highest UGroupingStrategy value.
+ * One more than the highest UNumberGroupingStrategy value.
*
* @internal ICU 62: The numeric value may change over time; see ICU ticket #12420.
*/
UNUM_GROUPING_COUNT
+#endif /* U_HIDE_INTERNAL_API */
+
+} UNumberGroupingStrategy;
+
+#ifndef U_HIDE_DEPRECATED_API
+/**
+ * Old name for compatibility: will be removed in ICU 64.
+ * @deprecated ICU 63
+ */
+typedef UNumberGroupingStrategy UGroupingStrategy;
+#endif /* U_HIDE_DEPRECATED_API */
-} UGroupingStrategy;
#endif /* U_HIDE_DRAFT_API */
#ifndef U_HIDE_DRAFT_API
@@ -398,6 +409,8 @@ typedef enum UNumberDecimalSeparatorDisplay {
#endif /* U_HIDE_DRAFT_API */
#ifndef U_HIDE_DRAFT_API
+
+struct UNumberFormatter;
/**
* C-compatible version of icu::number::LocalizedNumberFormatter.
*
@@ -405,10 +418,9 @@ typedef enum UNumberDecimalSeparatorDisplay {
*
* @draft ICU 62
*/
-struct UNumberFormatter;
typedef struct UNumberFormatter UNumberFormatter;
-
+struct UFormattedNumber;
/**
* C-compatible version of icu::number::FormattedNumber.
*
@@ -416,7 +428,6 @@ typedef struct UNumberFormatter UNumberFormatter;
*
* @draft ICU 62
*/
-struct UFormattedNumber;
typedef struct UFormattedNumber UFormattedNumber;
@@ -559,7 +570,8 @@ unumf_resultToString(const UFormattedNumber* uresult, UChar* buffer, int32_t buf
*
* NOTE: All fields of the UFieldPosition must be initialized before calling this method.
*
- * @param fieldPosition
+ * @param uresult The object containing the formatted number.
+ * @param ufpos
* Input+output variable. On input, the "field" property determines which field to look up,
* and the "endIndex" property determines where to begin the search. On output, the
* "beginIndex" field is set to the beginning of the first occurrence of the field after the
@@ -580,7 +592,7 @@ unumf_resultNextFieldPosition(const UFormattedNumber* uresult, UFieldPosition* u
* If you need information on only one field, use unumf_resultNextFieldPosition().
*
* @param uresult The object containing the formatted number.
- * @param fpositer
+ * @param ufpositer
* A pointer to a UFieldPositionIterator created by {@link #ufieldpositer_open}. Iteration
* information already present in the UFieldPositionIterator is deleted, and the iterator is reset
* to apply to the fields in the formatted string created by this function call. The field values
diff --git a/deps/icu-small/source/i18n/unicode/usearch.h b/deps/icu-small/source/i18n/unicode/usearch.h
index 600f9142b4..6b495ef001 100644
--- a/deps/icu-small/source/i18n/unicode/usearch.h
+++ b/deps/icu-small/source/i18n/unicode/usearch.h
@@ -257,10 +257,9 @@ typedef enum {
* match an e with the same diacritic or a plain e in the searched text.
*
* This option is similar to "asymmetric search" as described in
- * <a href="http://www.unicode.org/reports/tr10/#Asymmetric_Search">
- * UTS #10 Unicode Collation Algorithm</a, but also allows unmarked
- * characters in the searched text to match marked or unmarked versions of
- * that character in the pattern.
+ * [UTS #10 Unicode Collation Algorithm](http://www.unicode.org/reports/tr10/#Asymmetric_Search),
+ * but also allows unmarked characters in the searched text to match
+ * marked or unmarked versions of that character in the pattern.
*
* @stable ICU 4.4
*/
diff --git a/deps/icu-small/source/i18n/unicode/uspoof.h b/deps/icu-small/source/i18n/unicode/uspoof.h
index 781a88247f..d15ba4b242 100644
--- a/deps/icu-small/source/i18n/unicode/uspoof.h
+++ b/deps/icu-small/source/i18n/unicode/uspoof.h
@@ -94,7 +94,6 @@
* // ...
* \endcode
*
- * <p>
* UTS 39 defines two strings to be <em>confusable</em> if they map to the same <em>skeleton string</em>. A skeleton can
* be thought of as a "hash code". {@link uspoof_getSkeleton} computes the skeleton for a particular string, so
* the following snippet is equivalent to the example above:
@@ -128,7 +127,6 @@
* free(skel2);
* \endcode
*
- * <p>
* If you need to check if a string is confusable with any string in a dictionary of many strings, rather than calling
* {@link uspoof_areConfusable} many times in a loop, {@link uspoof_getSkeleton} can be used instead, as shown below:
*
@@ -172,14 +170,12 @@
* uspoof_close(sc);
* \endcode
*
- * <p>
* <b>Note:</b> Since the Unicode confusables mapping table is frequently updated, confusable skeletons are <em>not</em>
* guaranteed to be the same between ICU releases. We therefore recommend that you always compute confusable skeletons
* at runtime and do not rely on creating a permanent, or difficult to update, database of skeletons.
*
* <h2>Spoof Detection</h2>
*
- * <p>
* The following snippet shows a minimal example of using <code>USpoofChecker</code> to perform spoof detection on a
* string:
*
@@ -204,16 +200,13 @@
* uset_close(allowed);
* \endcode
*
- * <p>
* As in the case for confusability checking, it is good practice to create one <code>USpoofChecker</code> instance at
* startup, and call the cheaper {@link uspoof_check} online. We specify the set of
* allowed characters to be those with type RECOMMENDED or INCLUSION, according to the recommendation in UTS 39.
*
- * <p>
* In addition to {@link uspoof_check}, the function {@link uspoof_checkUTF8} is exposed for UTF8-encoded char* strings,
* and {@link uspoof_checkUnicodeString} is exposed for C++ programmers.
*
- * <p>
* If the {@link USPOOF_AUX_INFO} check is enabled, a limited amount of information on why a string failed the checks
* is available in the returned bitmask. For complete information, use the {@link uspoof_check2} class of functions
* with a {@link USpoofCheckResult} parameter:
@@ -274,7 +267,6 @@
* // Explicit cleanup not necessary.
* \endcode
*
- * <p>
* The return value is a bitmask of the checks that failed. In this case, there was one check that failed:
* {@link USPOOF_RESTRICTION_LEVEL}, corresponding to the fifth bit (16). The possible checks are:
*
@@ -307,7 +299,6 @@
* uspoof_close(sc);
* \endcode
*
- * <p>
* Here is an example in C++ showing how to compute the restriction level of a string:
*
* \code{.cpp}
@@ -334,11 +325,9 @@
* printf("Restriction level: %#010x (status: %s)\n", restrictionLevel, u_errorName(status));
* \endcode
*
- * <p>
* The code '0x50000000' corresponds to the restriction level USPOOF_MINIMALLY_RESTRICTIVE. Since
* USPOOF_MINIMALLY_RESTRICTIVE is weaker than USPOOF_MODERATELY_RESTRICTIVE, the string fails the check.
*
- * <p>
* <b>Note:</b> The Restriction Level is the most powerful of the checks. The full logic is documented in
* <a href="http://unicode.org/reports/tr39/#Restriction_Level_Detection">UTS 39</a>, but the basic idea is that strings
* are restricted to contain characters from only a single script, <em>except</em> that most scripts are allowed to have
@@ -352,15 +341,12 @@
*
* <h2>Additional Information</h2>
*
- * <p>
* A <code>USpoofChecker</code> instance may be used repeatedly to perform checks on any number of identifiers.
*
- * <p>
* <b>Thread Safety:</b> The test functions for checking a single identifier, or for testing whether
* two identifiers are possible confusable, are thread safe. They may called concurrently, from multiple threads,
* using the same USpoofChecker instance.
*
- * <p>
* More generally, the standard ICU thread safety rules apply: functions that take a const USpoofChecker parameter are
* thread safe. Those that take a non-const USpoofChecker are not thread safe..
*
@@ -1219,14 +1205,21 @@ U_NAMESPACE_BEGIN
/**
* \class LocalUSpoofCheckResultPointer
- * "Smart pointer" class, closes a USpoofCheckResult via {@link uspoof_closeCheckResult}.
+ * "Smart pointer" class, closes a USpoofCheckResult via `uspoof_closeCheckResult()`.
* For most methods see the LocalPointerBase base class.
*
* @see LocalPointerBase
* @see LocalPointer
* @stable ICU 58
*/
+
+/**
+ * \cond
+ * Note: Doxygen is giving a bogus warning on this U_DEFINE_LOCAL_OPEN_POINTER.
+ * For now, suppress with a Doxygen cond
+ */
U_DEFINE_LOCAL_OPEN_POINTER(LocalUSpoofCheckResultPointer, USpoofCheckResult, uspoof_closeCheckResult);
+/** \endcond */
U_NAMESPACE_END
diff --git a/deps/icu-small/source/i18n/uregex.cpp b/deps/icu-small/source/i18n/uregex.cpp
index 3703843634..f504aec91b 100644
--- a/deps/icu-small/source/i18n/uregex.cpp
+++ b/deps/icu-small/source/i18n/uregex.cpp
@@ -1654,8 +1654,8 @@ int32_t RegexCImpl::appendTail(RegularExpression *regexp,
} else if (UTEXT_USES_U16(m->fInputText)) {
srcIdx = (int32_t)nativeIdx;
} else {
- UErrorCode status = U_ZERO_ERROR;
- srcIdx = utext_extract(m->fInputText, 0, nativeIdx, NULL, 0, &status);
+ UErrorCode newStatus = U_ZERO_ERROR;
+ srcIdx = utext_extract(m->fInputText, 0, nativeIdx, NULL, 0, &newStatus);
}
for (;;) {
diff --git a/deps/icu-small/source/i18n/usearch.cpp b/deps/icu-small/source/i18n/usearch.cpp
index e1e6c28e2b..0e4cca77a1 100644
--- a/deps/icu-small/source/i18n/usearch.cpp
+++ b/deps/icu-small/source/i18n/usearch.cpp
@@ -498,7 +498,7 @@ inline void setShiftTable(int16_t shift[], int16_t backshift[],
for (count = 0; count < cesize; count ++) {
// number of ces from right of array to the count
int temp = defaultforward - count - 1;
- shift[hashFromCE32(cetable[count])] = temp > 1 ? temp : 1;
+ shift[hashFromCE32(cetable[count])] = temp > 1 ? static_cast<int16_t>(temp) : 1;
}
shift[hashFromCE32(cetable[cesize])] = 1;
// for ignorables we just shift by one. see test examples.
diff --git a/deps/icu-small/source/i18n/uspoof_impl.h b/deps/icu-small/source/i18n/uspoof_impl.h
index 470a31f2c9..7d6d0f76e3 100644
--- a/deps/icu-small/source/i18n/uspoof_impl.h
+++ b/deps/icu-small/source/i18n/uspoof_impl.h
@@ -20,7 +20,7 @@
#include "unicode/uspoof.h"
#include "unicode/uscript.h"
#include "unicode/udata.h"
-
+#include "udataswp.h"
#include "utrie2.h"
#if !UCONFIG_NO_NORMALIZATION
diff --git a/deps/icu-small/source/i18n/vtzone.cpp b/deps/icu-small/source/i18n/vtzone.cpp
index 0c76c9b6c9..e39eada51b 100644
--- a/deps/icu-small/source/i18n/vtzone.cpp
+++ b/deps/icu-small/source/i18n/vtzone.cpp
@@ -135,7 +135,7 @@ static UnicodeString& appendAsciiDigits(int32_t number, uint8_t length, UnicodeS
digits[i++] = number % 10;
number /= 10;
} while (number != 0);
- length = i;
+ length = static_cast<uint8_t>(i);
} else {
// fixed digits
for (i = 0; i < length; i++) {
diff --git a/deps/icu-small/source/i18n/zonemeta.cpp b/deps/icu-small/source/i18n/zonemeta.cpp
index 02562048a5..b7139a807b 100644
--- a/deps/icu-small/source/i18n/zonemeta.cpp
+++ b/deps/icu-small/source/i18n/zonemeta.cpp
@@ -319,10 +319,10 @@ ZoneMeta::getCanonicalCLDRID(const UnicodeString &tzid, UErrorCode& status) {
id[len] = (char) 0; // Make sure it is null terminated.
// replace '/' with ':'
- char *p = id;
- while (*p++) {
- if (*p == '/') {
- *p = ':';
+ char *q = id;
+ while (*q++) {
+ if (*q == '/') {
+ *q = ':';
}
}
@@ -850,13 +850,13 @@ ZoneMeta::createCustomTimeZone(int32_t offset) {
negative = TRUE;
tmp = -offset;
}
- int32_t hour, min, sec;
+ uint8_t hour, min, sec;
tmp /= 1000;
- sec = tmp % 60;
+ sec = static_cast<uint8_t>(tmp % 60);
tmp /= 60;
- min = tmp % 60;
- hour = tmp / 60;
+ min = static_cast<uint8_t>(tmp % 60);
+ hour = static_cast<uint8_t>(tmp / 60);
UnicodeString zid;
formatCustomID(hour, min, sec, negative, zid);