ICU-21578 Merging maint/maint-69 into main (conflict: icudata.jar)
diff --git a/icu4c/source/common/charstr.cpp b/icu4c/source/common/charstr.cpp
index c4710d6..c356228 100644
--- a/icu4c/source/common/charstr.cpp
+++ b/icu4c/source/common/charstr.cpp
@@ -14,6 +14,8 @@
* created by: Markus W. Scherer
*/
+#include <cstdlib>
+
#include "unicode/utypes.h"
#include "unicode/putil.h"
#include "charstr.h"
diff --git a/icu4c/source/common/edits.cpp b/icu4c/source/common/edits.cpp
index 95f0c19..92ca36f 100644
--- a/icu4c/source/common/edits.cpp
+++ b/icu4c/source/common/edits.cpp
@@ -86,6 +86,7 @@ Edits &Edits::moveArray(Edits &src) U_NOEXCEPT {
}
Edits &Edits::operator=(const Edits &other) {
+ if (this == &other) { return *this; } // self-assignment: no-op
length = other.length;
delta = other.delta;
numChanges = other.numChanges;
diff --git a/icu4c/source/common/filteredbrk.cpp b/icu4c/source/common/filteredbrk.cpp
index d2a6d98..f3c5f3f 100644
--- a/icu4c/source/common/filteredbrk.cpp
+++ b/icu4c/source/common/filteredbrk.cpp
@@ -20,6 +20,7 @@
#include "ubrkimpl.h" // U_ICUDATA_BRKITR
#include "uvector.h"
#include "cmemory.h"
+#include "umutex.h"
U_NAMESPACE_BEGIN
@@ -139,13 +140,30 @@ class SimpleFilteredSentenceBreakData : public UMemory {
public:
SimpleFilteredSentenceBreakData(UCharsTrie *forwards, UCharsTrie *backwards )
: fForwardsPartialTrie(forwards), fBackwardsTrie(backwards), refcount(1) { }
- SimpleFilteredSentenceBreakData *incr() { refcount++; return this; }
- SimpleFilteredSentenceBreakData *decr() { if((--refcount) <= 0) delete this; return 0; }
- virtual ~SimpleFilteredSentenceBreakData();
+ SimpleFilteredSentenceBreakData *incr() {
+ umtx_atomic_inc(&refcount);
+ return this;
+ }
+ SimpleFilteredSentenceBreakData *decr() {
+ if(umtx_atomic_dec(&refcount) <= 0) {
+ delete this;
+ }
+ return 0;
+ }
+ virtual ~SimpleFilteredSentenceBreakData();
- LocalPointer<UCharsTrie> fForwardsPartialTrie; // Has ".a" for "a.M."
- LocalPointer<UCharsTrie> fBackwardsTrie; // i.e. ".srM" for Mrs.
- int32_t refcount;
+ bool hasForwardsPartialTrie() const { return fForwardsPartialTrie.isValid(); }
+ bool hasBackwardsTrie() const { return fBackwardsTrie.isValid(); }
+
+ const UCharsTrie &getForwardsPartialTrie() const { return *fForwardsPartialTrie; }
+ const UCharsTrie &getBackwardsTrie() const { return *fBackwardsTrie; }
+
+private:
+ // These tries own their data arrays.
+ // They are shared and must therefore not be modified.
+ LocalPointer<UCharsTrie> fForwardsPartialTrie; // Has ".a" for "a.M."
+ LocalPointer<UCharsTrie> fBackwardsTrie; // i.e. ".srM" for Mrs.
+ u_atomic_int32_t refcount;
};
SimpleFilteredSentenceBreakData::~SimpleFilteredSentenceBreakData() {}
@@ -244,7 +262,13 @@ SimpleFilteredSentenceBreakIterator::SimpleFilteredSentenceBreakIterator(BreakIt
fData(new SimpleFilteredSentenceBreakData(forwards, backwards)),
fDelegate(adopt)
{
- // all set..
+ if (fData == nullptr) {
+ delete forwards;
+ delete backwards;
+ if (U_SUCCESS(status)) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ }
}
SimpleFilteredSentenceBreakIterator::~SimpleFilteredSentenceBreakIterator() {
@@ -261,59 +285,62 @@ SimpleFilteredSentenceBreakIterator::breakExceptionAt(int32_t n) {
int32_t bestValue = -1;
// loops while 'n' points to an exception.
utext_setNativeIndex(fText.getAlias(), n); // from n..
- fData->fBackwardsTrie->reset();
- UChar32 uch;
//if(debug2) u_printf(" n@ %d\n", n);
// Assume a space is following the '.' (so we handle the case: "Mr. /Brown")
- if((uch=utext_previous32(fText.getAlias()))==(UChar32)0x0020) { // TODO: skip a class of chars here??
+ if(utext_previous32(fText.getAlias())==u' ') { // TODO: skip a class of chars here??
// TODO only do this the 1st time?
//if(debug2) u_printf("skipping prev: |%C| \n", (UChar)uch);
} else {
//if(debug2) u_printf("not skipping prev: |%C| \n", (UChar)uch);
- uch = utext_next32(fText.getAlias());
+ utext_next32(fText.getAlias());
//if(debug2) u_printf(" -> : |%C| \n", (UChar)uch);
}
- UStringTrieResult r = USTRINGTRIE_INTERMEDIATE_VALUE;
-
- while((uch=utext_previous32(fText.getAlias()))!=U_SENTINEL && // more to consume backwards and..
- USTRINGTRIE_HAS_NEXT(r=fData->fBackwardsTrie->nextForCodePoint(uch))) {// more in the trie
- if(USTRINGTRIE_HAS_VALUE(r)) { // remember the best match so far
- bestPosn = utext_getNativeIndex(fText.getAlias());
- bestValue = fData->fBackwardsTrie->getValue();
- }
- //if(debug2) u_printf("rev< /%C/ cont?%d @%d\n", (UChar)uch, r, utext_getNativeIndex(fText.getAlias()));
+ {
+ // Do not modify the shared trie!
+ UCharsTrie iter(fData->getBackwardsTrie());
+ UChar32 uch;
+ while((uch=utext_previous32(fText.getAlias()))!=U_SENTINEL) { // more to consume backwards
+ UStringTrieResult r = iter.nextForCodePoint(uch);
+ if(USTRINGTRIE_HAS_VALUE(r)) { // remember the best match so far
+ bestPosn = utext_getNativeIndex(fText.getAlias());
+ bestValue = iter.getValue();
+ }
+ if(!USTRINGTRIE_HAS_NEXT(r)) {
+ break;
+ }
+ //if(debug2) u_printf("rev< /%C/ cont?%d @%d\n", (UChar)uch, r, utext_getNativeIndex(fText.getAlias()));
+ }
}
- if(USTRINGTRIE_MATCHES(r)) { // exact match?
- //if(debug2) u_printf("rev<?/%C/?end of seq.. r=%d, bestPosn=%d, bestValue=%d\n", (UChar)uch, r, bestPosn, bestValue);
- bestValue = fData->fBackwardsTrie->getValue();
- bestPosn = utext_getNativeIndex(fText.getAlias());
- //if(debug2) u_printf("rev<+/%C/+end of seq.. r=%d, bestPosn=%d, bestValue=%d\n", (UChar)uch, r, bestPosn, bestValue);
- }
+ //if(bestValue >= 0) {
+ //if(debug2) u_printf("rev<+/%C/+end of seq.. r=%d, bestPosn=%d, bestValue=%d\n", (UChar)uch, r, bestPosn, bestValue);
+ //}
if(bestPosn>=0) {
//if(debug2) u_printf("rev< /%C/ end of seq.. r=%d, bestPosn=%d, bestValue=%d\n", (UChar)uch, r, bestPosn, bestValue);
//if(USTRINGTRIE_MATCHES(r)) { // matched - so, now what?
- //int32_t bestValue = fBackwardsTrie->getValue();
+ //int32_t bestValue = iter.getValue();
////if(debug2) u_printf("rev< /%C/ matched, skip..%d bestValue=%d\n", (UChar)uch, r, bestValue);
if(bestValue == kMATCH) { // exact match!
//if(debug2) u_printf(" exact backward match\n");
return kExceptionHere; // See if the next is another exception.
} else if(bestValue == kPARTIAL
- && fData->fForwardsPartialTrie.isValid()) { // make sure there's a forward trie
+ && fData->hasForwardsPartialTrie()) { // make sure there's a forward trie
//if(debug2) u_printf(" partial backward match\n");
// We matched the "Ph." in "Ph.D." - now we need to run everything through the forwards trie
// to see if it matches something going forward.
- fData->fForwardsPartialTrie->reset();
UStringTrieResult rfwd = USTRINGTRIE_INTERMEDIATE_VALUE;
utext_setNativeIndex(fText.getAlias(), bestPosn); // hope that's close ..
//if(debug2) u_printf("Retrying at %d\n", bestPosn);
+ // Do not modify the shared trie!
+ UCharsTrie iter(fData->getForwardsPartialTrie());
+ UChar32 uch;
while((uch=utext_next32(fText.getAlias()))!=U_SENTINEL &&
- USTRINGTRIE_HAS_NEXT(rfwd=fData->fForwardsPartialTrie->nextForCodePoint(uch))) {
+ USTRINGTRIE_HAS_NEXT(rfwd=iter.nextForCodePoint(uch))) {
//if(debug2) u_printf("fwd> /%C/ cont?%d @%d\n", (UChar)uch, rfwd, utext_getNativeIndex(fText.getAlias()));
}
if(USTRINGTRIE_MATCHES(rfwd)) {
@@ -339,7 +366,7 @@ SimpleFilteredSentenceBreakIterator::breakExceptionAt(int32_t n) {
int32_t
SimpleFilteredSentenceBreakIterator::internalNext(int32_t n) {
if(n == UBRK_DONE || // at end or
- fData->fBackwardsTrie.isNull()) { // .. no backwards table loaded == no exceptions
+ !fData->hasBackwardsTrie()) { // .. no backwards table loaded == no exceptions
return n;
}
// OK, do we need to break here?
@@ -369,7 +396,7 @@ SimpleFilteredSentenceBreakIterator::internalNext(int32_t n) {
int32_t
SimpleFilteredSentenceBreakIterator::internalPrev(int32_t n) {
if(n == 0 || n == UBRK_DONE || // at end or
- fData->fBackwardsTrie.isNull()) { // .. no backwards table loaded == no exceptions
+ !fData->hasBackwardsTrie()) { // .. no backwards table loaded == no exceptions
return n;
}
// OK, do we need to break here?
@@ -420,7 +447,7 @@ SimpleFilteredSentenceBreakIterator::previous(void) {
UBool SimpleFilteredSentenceBreakIterator::isBoundary(int32_t offset) {
if (!fDelegate->isBoundary(offset)) return false; // no break to suppress
- if (fData->fBackwardsTrie.isNull()) return true; // no data = no suppressions
+ if (!fData->hasBackwardsTrie()) return true; // no data = no suppressions
UErrorCode status = U_ZERO_ERROR;
resetState(status);
diff --git a/icu4c/source/common/locid.cpp b/icu4c/source/common/locid.cpp
index 8f1b22c..4fec17d 100644
--- a/icu4c/source/common/locid.cpp
+++ b/icu4c/source/common/locid.cpp
@@ -1544,7 +1544,7 @@ AliasReplacer::replaceTransformedExtensions(
const char* str = transformedExtensions.data();
const char* tkey = ultag_getTKeyStart(str);
int32_t tlangLen = (tkey == str) ? 0 :
- ((tkey == nullptr) ? len : (tkey - str - 1));
+ ((tkey == nullptr) ? len : static_cast<int32_t>((tkey - str - 1)));
CharStringByteSink sink(&output);
if (tlangLen > 0) {
Locale tlang = LocaleBuilder()
diff --git a/icu4c/source/common/uloc_tag.cpp b/icu4c/source/common/uloc_tag.cpp
index 0bd4b85..1235081 100644
--- a/icu4c/source/common/uloc_tag.cpp
+++ b/icu4c/source/common/uloc_tag.cpp
@@ -651,7 +651,7 @@ ultag_getTKeyStart(const char *localeID) {
const char *result = localeID;
const char *sep;
while((sep = uprv_strchr(result, SEP)) != nullptr) {
- if (_isTKey(result, sep - result)) {
+ if (_isTKey(result, static_cast<int32_t>(sep - result))) {
return result;
}
result = ++sep;
diff --git a/icu4c/source/i18n/cpdtrans.cpp b/icu4c/source/i18n/cpdtrans.cpp
index 82ee54a..dc0217b 100644
--- a/icu4c/source/i18n/cpdtrans.cpp
+++ b/icu4c/source/i18n/cpdtrans.cpp
@@ -282,6 +282,7 @@ void CompoundTransliterator::freeTransliterators(void) {
CompoundTransliterator& CompoundTransliterator::operator=(
const CompoundTransliterator& t)
{
+ if (this == &t) { return *this; } // self-assignment: no-op
Transliterator::operator=(t);
int32_t i = 0;
UBool failed = FALSE;
diff --git a/icu4c/source/i18n/dtfmtsym.cpp b/icu4c/source/i18n/dtfmtsym.cpp
index 81e3bf1..937cf70 100644
--- a/icu4c/source/i18n/dtfmtsym.cpp
+++ b/icu4c/source/i18n/dtfmtsym.cpp
@@ -450,6 +450,7 @@ DateFormatSymbols::copyData(const DateFormatSymbols& other) {
*/
DateFormatSymbols& DateFormatSymbols::operator=(const DateFormatSymbols& other)
{
+ if (this == &other) { return *this; } // self-assignment: no-op
dispose();
copyData(other);
diff --git a/icu4c/source/i18n/formattedval_sbimpl.cpp b/icu4c/source/i18n/formattedval_sbimpl.cpp
index f3911c0..9ec06da 100644
--- a/icu4c/source/i18n/formattedval_sbimpl.cpp
+++ b/icu4c/source/i18n/formattedval_sbimpl.cpp
@@ -154,7 +154,10 @@ bool FormattedValueStringBuilderImpl::nextPositionImpl(ConstrainedFieldPosition&
if (i > fString.fZero && prevIsSpan) {
int64_t si = cfpos.getInt64IterationContext() - 1;
U_ASSERT(si >= 0);
- if (_field == Field(UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD)) {
+ int32_t previ = i - spanIndices[si].length;
+ U_ASSERT(previ >= fString.fZero);
+ Field prevField = fString.getFieldPtr()[previ];
+ if (prevField == Field(UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD)) {
// Special handling for ULISTFMT_ELEMENT_FIELD
if (cfpos.matchesField(UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD)) {
fieldStart = i - fString.fZero - spanIndices[si].length;
@@ -165,12 +168,13 @@ bool FormattedValueStringBuilderImpl::nextPositionImpl(ConstrainedFieldPosition&
fieldStart,
end);
return true;
+ } else {
+ prevIsSpan = false;
}
} else {
// Re-wind, since there may be multiple fields in the span.
- i -= spanIndices[si].length;
- U_ASSERT(i >= fString.fZero);
- _field = fString.getFieldPtr()[i];
+ i = previ;
+ _field = prevField;
}
}
// Special case: coalesce the INTEGER if we are pointing at the end of the INTEGER.
diff --git a/icu4c/source/i18n/measunit_impl.h b/icu4c/source/i18n/measunit_impl.h
index f88d900..c861763 100644
--- a/icu4c/source/i18n/measunit_impl.h
+++ b/icu4c/source/i18n/measunit_impl.h
@@ -20,22 +20,6 @@ class LongNameHandler;
}
} // namespace number
-// Export an explicit template instantiation of the LocalPointer that is used as a
-// data member of MeasureUnitImpl.
-// (When building DLLs for Windows this is required.)
-#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
-#if defined(_MSC_VER)
-// Ignore warning 4661 as LocalPointerBase does not use operator== or operator!=
-#pragma warning(push)
-#pragma warning(disable : 4661)
-#endif
-template class U_I18N_API LocalPointerBase<MeasureUnitImpl>;
-template class U_I18N_API LocalPointer<MeasureUnitImpl>;
-#if defined(_MSC_VER)
-#pragma warning(pop)
-#endif
-#endif
-
static const char16_t kDefaultCurrency[] = u"XXX";
static const char kDefaultCurrency8[] = "XXX";
@@ -194,9 +178,6 @@ struct MeasureUnitImplWithIndex;
template class U_I18N_API MaybeStackArray<SingleUnitImpl *, 8>;
template class U_I18N_API MemoryPool<SingleUnitImpl, 8>;
template class U_I18N_API MaybeStackVector<SingleUnitImpl, 8>;
-template class U_I18N_API MaybeStackArray<MeasureUnitImplWithIndex *, 8>;
-template class U_I18N_API MemoryPool<MeasureUnitImplWithIndex, 8>;
-template class U_I18N_API MaybeStackVector<MeasureUnitImplWithIndex, 8>;
#endif
/**
@@ -330,6 +311,29 @@ struct U_I18N_API MeasureUnitImplWithIndex : public UMemory {
}
};
+// Export explicit template instantiations of MaybeStackArray, MemoryPool and
+// MaybeStackVector. This is required when building DLLs for Windows. (See
+// datefmt.h, collationiterator.h, erarules.h and others for similar examples.)
+#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
+template class U_I18N_API MaybeStackArray<MeasureUnitImplWithIndex *, 8>;
+template class U_I18N_API MemoryPool<MeasureUnitImplWithIndex, 8>;
+template class U_I18N_API MaybeStackVector<MeasureUnitImplWithIndex, 8>;
+
+// Export an explicit template instantiation of the LocalPointer that is used as a
+// data member of MeasureUnitImpl.
+// (When building DLLs for Windows this is required.)
+#if defined(_MSC_VER)
+// Ignore warning 4661 as LocalPointerBase does not use operator== or operator!=
+#pragma warning(push)
+#pragma warning(disable : 4661)
+#endif
+template class U_I18N_API LocalPointerBase<MeasureUnitImpl>;
+template class U_I18N_API LocalPointer<MeasureUnitImpl>;
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+#endif
+
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/icu4c/source/i18n/number_decimfmtprops.h b/icu4c/source/i18n/number_decimfmtprops.h
index 1ce84d9..0ace241 100644
--- a/icu4c/source/i18n/number_decimfmtprops.h
+++ b/icu4c/source/i18n/number_decimfmtprops.h
@@ -38,7 +38,7 @@ namespace impl {
// Exported as U_I18N_API because it is a public member field of exported DecimalFormatProperties
// Using this wrapper is rather unfortunate, but is needed on Windows platforms in order to allow
-// for DLL-exporting an fully specified template instantiation.
+// for DLL-exporting a fully specified template instantiation.
class U_I18N_API CurrencyPluralInfoWrapper {
public:
LocalPointer<CurrencyPluralInfo> fPtr;
@@ -52,7 +52,8 @@ class U_I18N_API CurrencyPluralInfoWrapper {
}
CurrencyPluralInfoWrapper& operator=(const CurrencyPluralInfoWrapper& other) {
- if (!other.fPtr.isNull()) {
+ if (this != &other && // self-assignment: no-op
+ !other.fPtr.isNull()) {
fPtr.adoptInstead(new CurrencyPluralInfo(*other.fPtr));
}
return *this;
diff --git a/icu4c/source/i18n/number_fluent.cpp b/icu4c/source/i18n/number_fluent.cpp
index 0e27405..a79f224 100644
--- a/icu4c/source/i18n/number_fluent.cpp
+++ b/icu4c/source/i18n/number_fluent.cpp
@@ -442,6 +442,7 @@ LocalizedNumberFormatter::LocalizedNumberFormatter(NFS<LNF>&& src) U_NOEXCEPT
}
LocalizedNumberFormatter& LocalizedNumberFormatter::operator=(const LNF& other) {
+ if (this == &other) { return *this; } // self-assignment: no-op
NFS<LNF>::operator=(static_cast<const NFS<LNF>&>(other));
UErrorCode localStatus = U_ZERO_ERROR; // Can't bubble up the error
lnfCopyHelper(other, localStatus);
diff --git a/icu4c/source/i18n/number_longnames.cpp b/icu4c/source/i18n/number_longnames.cpp
index 6c7a56e..08078c4 100644
--- a/icu4c/source/i18n/number_longnames.cpp
+++ b/icu4c/source/i18n/number_longnames.cpp
@@ -5,6 +5,8 @@
#if !UCONFIG_NO_FORMATTING
+#include <cstdlib>
+
#include "unicode/simpleformatter.h"
#include "unicode/ures.h"
#include "ureslocs.h"
diff --git a/icu4c/source/i18n/number_multiplier.cpp b/icu4c/source/i18n/number_multiplier.cpp
index 8f07e54..58e1e44 100644
--- a/icu4c/source/i18n/number_multiplier.cpp
+++ b/icu4c/source/i18n/number_multiplier.cpp
@@ -46,6 +46,7 @@ Scale::Scale(const Scale& other)
}
Scale& Scale::operator=(const Scale& other) {
+ if (this == &other) { return *this; } // self-assignment: no-op
fMagnitude = other.fMagnitude;
if (other.fArbitrary != nullptr) {
UErrorCode localStatus = U_ZERO_ERROR;
diff --git a/icu4c/source/i18n/number_usageprefs.cpp b/icu4c/source/i18n/number_usageprefs.cpp
index ff285db..ed426da 100644
--- a/icu4c/source/i18n/number_usageprefs.cpp
+++ b/icu4c/source/i18n/number_usageprefs.cpp
@@ -34,6 +34,7 @@ StringProp::StringProp(const StringProp &other) : StringProp() {
// Copy assignment operator
StringProp &StringProp::operator=(const StringProp &other) {
+ if (this == &other) { return *this; } // self-assignment: no-op
fLength = 0;
fError = other.fError;
if (fValue != nullptr) {
diff --git a/icu4c/source/i18n/numrange_fluent.cpp b/icu4c/source/i18n/numrange_fluent.cpp
index d9286d1..f1060b3 100644
--- a/icu4c/source/i18n/numrange_fluent.cpp
+++ b/icu4c/source/i18n/numrange_fluent.cpp
@@ -245,6 +245,7 @@ LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(NFS<LNF>&& src) U_N
}
LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(const LNF& other) {
+ if (this == &other) { return *this; } // self-assignment: no-op
NFS<LNF>::operator=(static_cast<const NFS<LNF>&>(other));
// Do not steal; just clear
delete fAtomicFormatter.exchange(nullptr);
diff --git a/icu4c/source/i18n/olsontz.cpp b/icu4c/source/i18n/olsontz.cpp
index 1d0fa80..b56c4a7 100644
--- a/icu4c/source/i18n/olsontz.cpp
+++ b/icu4c/source/i18n/olsontz.cpp
@@ -274,6 +274,7 @@ OlsonTimeZone::OlsonTimeZone(const OlsonTimeZone& other) :
* Assignment operator
*/
OlsonTimeZone& OlsonTimeZone::operator=(const OlsonTimeZone& other) {
+ if (this == &other) { return *this; } // self-assignment: no-op
canonicalID = other.canonicalID;
transitionTimesPre32 = other.transitionTimesPre32;
diff --git a/icu4c/source/i18n/stsearch.cpp b/icu4c/source/i18n/stsearch.cpp
index 3e6ed46..7fcd2bd 100644
--- a/icu4c/source/i18n/stsearch.cpp
+++ b/icu4c/source/i18n/stsearch.cpp
@@ -184,7 +184,7 @@ StringSearch::clone() const {
// operator overloading ---------------------------------------------
StringSearch & StringSearch::operator=(const StringSearch &that)
{
- if ((*this) != that) {
+ if (this != &that) {
UErrorCode status = U_ZERO_ERROR;
m_text_ = that.m_text_;
m_breakiterator_ = that.m_breakiterator_;
diff --git a/icu4c/source/i18n/translit.cpp b/icu4c/source/i18n/translit.cpp
index ef44f42..9b2eaad 100644
--- a/icu4c/source/i18n/translit.cpp
+++ b/icu4c/source/i18n/translit.cpp
@@ -170,6 +170,7 @@ Transliterator* Transliterator::clone() const {
* Assignment operator.
*/
Transliterator& Transliterator::operator=(const Transliterator& other) {
+ if (this == &other) { return *this; } // self-assignment: no-op
ID = other.ID;
// NUL-terminate the ID string
ID.getTerminatedBuffer();
diff --git a/icu4c/source/i18n/windtfmt.cpp b/icu4c/source/i18n/windtfmt.cpp
index bcf272b..f6a990e 100644
--- a/icu4c/source/i18n/windtfmt.cpp
+++ b/icu4c/source/i18n/windtfmt.cpp
@@ -193,6 +193,7 @@ Win32DateFormat::~Win32DateFormat()
Win32DateFormat &Win32DateFormat::operator=(const Win32DateFormat &other)
{
+ if (this == &other) { return *this; } // self-assignment: no-op
// The following handles fCalendar
DateFormat::operator=(other);
diff --git a/icu4c/source/i18n/winnmfmt.cpp b/icu4c/source/i18n/winnmfmt.cpp
index 72da1be..8b2a9a4 100644
--- a/icu4c/source/i18n/winnmfmt.cpp
+++ b/icu4c/source/i18n/winnmfmt.cpp
@@ -268,6 +268,7 @@ Win32NumberFormat::~Win32NumberFormat()
Win32NumberFormat &Win32NumberFormat::operator=(const Win32NumberFormat &other)
{
+ if (this == &other) { return *this; } // self-assignment: no-op
NumberFormat::operator=(other);
this->fCurrency = other.fCurrency;
diff --git a/icu4c/source/test/intltest/formattedvaluetest.cpp b/icu4c/source/test/intltest/formattedvaluetest.cpp
index 0edf420..ec237da 100644
--- a/icu4c/source/test/intltest/formattedvaluetest.cpp
+++ b/icu4c/source/test/intltest/formattedvaluetest.cpp
@@ -242,7 +242,7 @@ void IntlTestWithFieldPosition::checkMixedFormattedValue(
// Check nextPosition constrained over each category one at a time
for (int32_t category=0; category<UFIELD_CATEGORY_COUNT+1; category++) {
- if (category == UFIELD_CATEGORY_COUNT+1) {
+ if (category == UFIELD_CATEGORY_COUNT) {
category = UFIELD_CATEGORY_LIST_SPAN;
}
cfpos.reset();
diff --git a/icu4c/source/test/intltest/numbertest_api.cpp b/icu4c/source/test/intltest/numbertest_api.cpp
index 689af5c..eedf452 100644
--- a/icu4c/source/test/intltest/numbertest_api.cpp
+++ b/icu4c/source/test/intltest/numbertest_api.cpp
@@ -1209,6 +1209,7 @@ void NumberFormatterApiTest::unitArbitraryMeasureUnits() {
.unit(MeasureUnit::forIdentifier("pow4-mile", status))
.unitWidth(UNUM_UNIT_WIDTH_FULL_NAME)
.locale("en-ZA");
+ lnf.operator=(lnf); // self-assignment should be a no-op
lnf.formatInt(1, status);
status.expectErrorAndReset(U_RESOURCE_TYPE_MISMATCH);
diff --git a/icu4c/source/test/intltest/tsdtfmsy.cpp b/icu4c/source/test/intltest/tsdtfmsy.cpp
index c1efcc2..2c1a183 100644
--- a/icu4c/source/test/intltest/tsdtfmsy.cpp
+++ b/icu4c/source/test/intltest/tsdtfmsy.cpp
@@ -149,6 +149,7 @@ void IntlTestDateFormatSymbols::TestGetSetSpecificItems()
dataerrln("ERROR: Couldn't create English DateFormatSymbols " + (UnicodeString)u_errorName(status));
return;
}
+ symbol->operator=(*symbol); // self-assignment should be a no-op
int32_t cntFmtAbbrev, cntFmtShort, cntStdAloneShort;
const UnicodeString * wdFmtAbbrev = symbol->getWeekdays(cntFmtAbbrev,DateFormatSymbols::FORMAT,DateFormatSymbols::ABBREVIATED);
const UnicodeString * wdFmtShort = symbol->getWeekdays(cntFmtShort,DateFormatSymbols::FORMAT,DateFormatSymbols::SHORT);
diff --git a/icu4c/source/test/intltest/tzfmttst.cpp b/icu4c/source/test/intltest/tzfmttst.cpp
index 0f58a00..882125f 100644
--- a/icu4c/source/test/intltest/tzfmttst.cpp
+++ b/icu4c/source/test/intltest/tzfmttst.cpp
@@ -745,9 +745,9 @@ void TimeZoneFormatTest::RunAdoptDefaultThreadSafeTests(int32_t threadNumber) {
date += 6000 * i;
std::unique_ptr<icu::TimeZone> tz(icu::TimeZone::createDefault());
status = U_ZERO_ERROR;
- tz->getOffset(date, TRUE, rawOffset, dstOffset, status);
+ tz->getOffset(static_cast<UDate>(date), TRUE, rawOffset, dstOffset, status);
status = U_ZERO_ERROR;
- tz->getOffset(date, FALSE, rawOffset, dstOffset, status);
+ tz->getOffset(static_cast<UDate>(date), FALSE, rawOffset, dstOffset, status);
}
}
}
diff --git a/icu4c/source/test/intltest/tztest.cpp b/icu4c/source/test/intltest/tztest.cpp
index 93d992f..b877db5 100644
--- a/icu4c/source/test/intltest/tztest.cpp
+++ b/icu4c/source/test/intltest/tztest.cpp
@@ -1171,8 +1171,10 @@ void TimeZoneTest::TestCustomParse()
TimeZone *zone = TimeZone::createTimeZone(id);
UnicodeString itsID, temp;
- if (dynamic_cast<OlsonTimeZone *>(zone) != NULL) {
+ OlsonTimeZone *ozone = dynamic_cast<OlsonTimeZone *>(zone);
+ if (ozone != nullptr) {
logln(id + " -> Olson time zone");
+ ozone->operator=(*ozone); // self-assignment should be a no-op
} else {
zone->getID(itsID);
int32_t ioffset = zone->getRawOffset()/1000;
diff --git a/icu4c/source/test/testdata/rbbitst.txt b/icu4c/source/test/testdata/rbbitst.txt
index 7bc7bd5..f59433f 100644
--- a/icu4c/source/test/testdata/rbbitst.txt
+++ b/icu4c/source/test/testdata/rbbitst.txt
@@ -62,6 +62,11 @@
<data>\
•Doctor with a D. •As in, Ph.D., you know.•</data>
+# ICU-21459 logic error.
+<locale en@ss=standard>
+<sent>
+<data>•on. •But after a day in the arena sun, the metal feels hot enough to blister my hands.•</data>
+
# same as root (unless some exceptions are added!)
<locale tfg@ss=standard>
<sent>
diff --git a/icu4c/source/tools/genren/README b/icu4c/source/tools/genren/README
index e2e13bc..a18c294 100644
--- a/icu4c/source/tools/genren/README
+++ b/icu4c/source/tools/genren/README
@@ -20,6 +20,14 @@
cd icu4c/source
svn export https://github.com/behdad/icu-le-hb/trunk/src layout
+(As an alternative to the above handling of layout engine header files, you can do the following:
+1. In the Makefile in this directory, temporarily delete $(LEX) from the list of objects for LIBS
+ before running make install-header
+2. After running make install-header, restore the deleted $(LEX) in the Makefile
+3. Then when comparing the old urename.h to the newly generated one, copy all of the lines beginning
+ "#define pl_" from the old version to the new one.
+ - Peter E)
+
- Regenerate urename.h
cd icu4c/source/tools/genren
diff --git a/icu4j/build.properties b/icu4j/build.properties
index 2bd4c31..260b986 100644
--- a/icu4j/build.properties
+++ b/icu4j/build.properties
@@ -6,7 +6,7 @@
#*******************************************************************************
api.report.version = 69
api.report.prev.version = 68
-release.file.ver = 69rc
-api.doc.version = 69.1 Release Candidate
-maven.pom.ver = 69.1-SNAPSHOT
+release.file.ver = 69_1
+api.doc.version = 69.1
+maven.pom.ver = 69.1
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/SimpleFilteredSentenceBreakIterator.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/SimpleFilteredSentenceBreakIterator.java
index bef89a2..e9655a8 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/impl/SimpleFilteredSentenceBreakIterator.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/SimpleFilteredSentenceBreakIterator.java
@@ -19,6 +19,7 @@
import com.ibm.icu.util.BytesTrie;
import com.ibm.icu.util.CharsTrie;
import com.ibm.icu.util.CharsTrieBuilder;
+import com.ibm.icu.util.ICUCloneNotSupportedException;
import com.ibm.icu.util.StringTrieBuilder;
import com.ibm.icu.util.ULocale;
@@ -72,8 +73,6 @@ private final boolean breakExceptionAt(int n) {
backwardsTrie.reset();
int uch;
-
-
// Assume a space is following the '.' (so we handle the case: "Mr. /Brown")
if ((uch = text.previousCodePoint()) == ' ') { // TODO: skip a class of chars here??
// TODO only do this the 1st time?
@@ -81,20 +80,17 @@ private final boolean breakExceptionAt(int n) {
uch = text.nextCodePoint();
}
- BytesTrie.Result r = BytesTrie.Result.INTERMEDIATE_VALUE;
-
- while ((uch = text.previousCodePoint()) != UCharacterIterator.DONE && // more to consume backwards and..
- ((r = backwardsTrie.nextForCodePoint(uch)).hasNext())) {// more in the trie
+ while ((uch = text.previousCodePoint()) >= 0) { // more to consume backwards
+ BytesTrie.Result r = backwardsTrie.nextForCodePoint(uch);
if (r.hasValue()) { // remember the best match so far
bestPosn = text.getIndex();
bestValue = backwardsTrie.getValue();
}
+ if (!r.hasNext()) {
+ break;
+ }
}
-
- if (r.matches()) { // exact match?
- bestValue = backwardsTrie.getValue();
- bestPosn = text.getIndex();
- }
+ backwardsTrie.reset(); // for equals() & hashCode()
if (bestPosn >= 0) {
if (bestValue == Builder.MATCH) { // exact match!
@@ -110,6 +106,7 @@ private final boolean breakExceptionAt(int n) {
while ((uch = text.nextCodePoint()) != BreakIterator.DONE
&& ((rfwd = forwardsPartialTrie.nextForCodePoint(uch)).hasNext())) {
}
+ forwardsPartialTrie.reset(); // for equals() & hashCode()
if (rfwd.matches()) {
// Exception here
return true;
@@ -186,18 +183,39 @@ public boolean equals(Object obj) {
if (getClass() != obj.getClass())
return false;
SimpleFilteredSentenceBreakIterator other = (SimpleFilteredSentenceBreakIterator) obj;
- return delegate.equals(other.delegate) && text.equals(other.text) && backwardsTrie.equals(other.backwardsTrie)
+ // TODO(ICU-21575): CharsTrie.equals() is not defined.
+ // Should compare the underlying data, and can then stop resetting after iteration.
+ return delegate.equals(other.delegate) && text.equals(other.text)
+ && backwardsTrie.equals(other.backwardsTrie)
&& forwardsPartialTrie.equals(other.forwardsPartialTrie);
}
@Override
public int hashCode() {
- return (forwardsPartialTrie.hashCode() * 39) + (backwardsTrie.hashCode() * 11) + delegate.hashCode();
+ // TODO(ICU-21575): CharsTrie.hashCode() is not defined.
+ return (forwardsPartialTrie.hashCode() * 39) + (backwardsTrie.hashCode() * 11)
+ + delegate.hashCode();
}
@Override
public Object clone() {
SimpleFilteredSentenceBreakIterator other = (SimpleFilteredSentenceBreakIterator) super.clone();
+ try {
+ if (delegate != null) {
+ other.delegate = (BreakIterator) delegate.clone();
+ }
+ if (text != null) {
+ other.text = (UCharacterIterator) text.clone();
+ }
+ if (backwardsTrie != null) {
+ other.backwardsTrie = backwardsTrie.clone();
+ }
+ if (forwardsPartialTrie != null) {
+ other.forwardsPartialTrie = forwardsPartialTrie.clone();
+ }
+ } catch (CloneNotSupportedException e) {
+ throw new ICUCloneNotSupportedException(e);
+ }
return other;
}
@@ -273,7 +291,7 @@ public static class Builder extends FilteredBreakIteratorBuilder {
/**
* filter set to store all exceptions
*/
- private HashSet<CharSequence> filterSet = new HashSet<CharSequence>();
+ private HashSet<CharSequence> filterSet = new HashSet<>();
static final int PARTIAL = (1 << 0); // < partial - need to run through forward trie
static final int MATCH = (1 << 1); // < exact match - skip this one.
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/StringSegment.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/StringSegment.java
index b8f5baf..19d9eff 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/impl/StringSegment.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/StringSegment.java
@@ -202,23 +202,13 @@ private static final boolean codePointsEqual(int cp1, int cp2, boolean foldCase)
}
/**
- * Equals any CharSequence with the same chars as this segment.
+ * Returns true if this segment contains the same characters as the other CharSequence.
*
- * <p>
- * This method does not perform case folding; if you want case-insensitive equality, use
+ * <p>This method does not perform case folding; if you want case-insensitive equality, use
* {@link #getCommonPrefixLength}.
*/
- @Override
- public boolean equals(Object other) {
- if (!(other instanceof CharSequence))
- return false;
- return Utility.charSequenceEquals(this, (CharSequence) other);
- }
-
- /** Returns a hash code equivalent to calling .toString().hashCode() */
- @Override
- public int hashCode() {
- return Utility.charSequenceHashCode(this);
+ public boolean contentEquals(CharSequence other) {
+ return Utility.charSequenceEquals(this, other);
}
/** Returns a string representation useful for debugging. */
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/number/NumberSkeletonImpl.java b/icu4j/main/classes/core/src/com/ibm/icu/number/NumberSkeletonImpl.java
index f36a98a..54555d8 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/number/NumberSkeletonImpl.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/number/NumberSkeletonImpl.java
@@ -1368,7 +1368,7 @@ private static boolean parseFracSigOption(StringSegment segment, MacroProps macr
/** @return Whether we successfully found and parsed a trailing zero option. */
private static boolean parseTrailingZeroOption(StringSegment segment, MacroProps macros) {
- if (segment.equals("w")) {
+ if (segment.contentEquals("w")) {
macros.precision = macros.precision.trailingZeroDisplay(TrailingZeroDisplay.HIDE_IF_WHOLE);
return true;
}
diff --git a/icu4j/main/shared/data/icudata.jar b/icu4j/main/shared/data/icudata.jar
index fc600ed..3176247 100644
--- a/icu4j/main/shared/data/icudata.jar
+++ b/icu4j/main/shared/data/icudata.jar
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8f668e5db6c9c9e8b2fcf5feaeb1bc16bb7b036466b0e045778ddd9dc00ad13a
-size 13383795
+oid sha256:8f02ab2967eaf73b6d28c8340d70b20d5f194f6c0ac24fe8464b25fd56763b04
+size 13383786
diff --git a/icu4j/main/shared/data/icutzdata.jar b/icu4j/main/shared/data/icutzdata.jar
index 647ac05..c0b07c2 100644
--- a/icu4j/main/shared/data/icutzdata.jar
+++ b/icu4j/main/shared/data/icutzdata.jar
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ecb74957c99d65a50729cd1d72e7e92e7254560381362980d73675d246281371
-size 95105
+oid sha256:da82185ad36c6b747848c409fff8661892c0ed5d5ebc0cdf8be9d29f4e3f65ef
+size 95096
diff --git a/icu4j/main/shared/data/testdata.jar b/icu4j/main/shared/data/testdata.jar
index 61a2c94..783e69a 100644
--- a/icu4j/main/shared/data/testdata.jar
+++ b/icu4j/main/shared/data/testdata.jar
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:382f6e65ed9855715493eb48fb11e3bba62ff84754bf36fbe11370479a4c27bc
-size 723620
+oid sha256:26a032e0c9492cd986546eefb5ba54687598eb431caed531ccb00b12469421ca
+size 726547
diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/impl/StringSegmentTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/impl/StringSegmentTest.java
index 1a2baf6..028f2f9 100644
--- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/impl/StringSegmentTest.java
+++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/impl/StringSegmentTest.java
@@ -3,6 +3,8 @@
package com.ibm.icu.dev.test.impl;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import org.junit.Test;
@@ -47,10 +49,15 @@ public void testLength() {
public void testCharAt() {
StringSegment segment = new StringSegment(SAMPLE_STRING, false);
assertCharSequenceEquals(SAMPLE_STRING, segment);
+ assertTrue(segment.contentEquals(SAMPLE_STRING));
segment.adjustOffset(3);
assertCharSequenceEquals("radio 📻", segment);
+ assertTrue(segment.contentEquals("radio 📻"));
+ assertFalse(segment.contentEquals(SAMPLE_STRING));
segment.setLength(5);
assertCharSequenceEquals("radio", segment);
+ assertTrue(segment.contentEquals("radio"));
+ assertFalse(segment.contentEquals(SAMPLE_STRING));
}
@Test
diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/rbbi/rbbitst.txt b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/rbbi/rbbitst.txt
index 7bc7bd5..f59433f 100644
--- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/rbbi/rbbitst.txt
+++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/rbbi/rbbitst.txt
@@ -62,6 +62,11 @@
<data>\
•Doctor with a D. •As in, Ph.D., you know.•</data>
+# ICU-21459 logic error.
+<locale en@ss=standard>
+<sent>
+<data>•on. •But after a day in the arena sun, the metal feels hot enough to blister my hands.•</data>
+
# same as root (unless some exceptions are added!)
<locale tfg@ss=standard>
<sent>
diff --git a/tools/cldr/cldr-to-icu/pom.xml b/tools/cldr/cldr-to-icu/pom.xml
index e157280..89c6dfd 100644
--- a/tools/cldr/cldr-to-icu/pom.xml
+++ b/tools/cldr/cldr-to-icu/pom.xml
@@ -83,7 +83,7 @@
<dependency>
<groupId>com.ibm.icu</groupId>
<artifactId>icu4j-for-cldr</artifactId>
- <version>69.1-SNAPSHOT-cldr-2021-03-09</version>
+ <version>69.1-SNAPSHOT-release-69-rc</version>
<!-- Note: see https://github.com/unicode-org/icu/packages/411079/versions
for the icu4j-for-cldr version tag to use -->
</dependency>