From 048e46674aec9a0f90f40064011abadb9ac8ee04 Mon Sep 17 00:00:00 2001 From: Victor Chang Date: Mon, 1 Feb 2021 22:20:48 +0000 Subject: [PATCH] ICU-21455 Add new API ubrk_clone() and deprecate ubrk_safeClone() --- icu4c/source/common/ubrk.cpp | 12 ++++ icu4c/source/common/unicode/ubrk.h | 21 ++++++- icu4c/source/test/cintltst/cbiapts.c | 84 ++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 1 deletion(-) diff --git a/icu4c/source/common/ubrk.cpp b/icu4c/source/common/ubrk.cpp index f8bdf5a6b65..bb5bdd1b501 100644 --- a/icu4c/source/common/ubrk.cpp +++ b/icu4c/source/common/ubrk.cpp @@ -174,6 +174,18 @@ ubrk_safeClone( return (UBreakIterator *)newBI; } +U_CAPI UBreakIterator * U_EXPORT2 +ubrk_clone(const UBreakIterator *bi, UErrorCode *status) { + if (U_FAILURE(*status)) { + return nullptr; + } + BreakIterator *newBI = ((BreakIterator *)bi)->clone(); + if (newBI == nullptr) { + *status = U_MEMORY_ALLOCATION_ERROR; + return nullptr; + } + return (UBreakIterator *)newBI; +} U_CAPI void U_EXPORT2 diff --git a/icu4c/source/common/unicode/ubrk.h b/icu4c/source/common/unicode/ubrk.h index 37189a85984..1249b0b160d 100644 --- a/icu4c/source/common/unicode/ubrk.h +++ b/icu4c/source/common/unicode/ubrk.h @@ -296,6 +296,8 @@ ubrk_openBinaryRules(const uint8_t *binaryRules, int32_t rulesLength, const UChar * text, int32_t textLength, UErrorCode * status); +#ifndef U_HIDE_DEPRECATED_API + /** * Thread safe cloning operation * @param bi iterator to be cloned @@ -312,7 +314,7 @@ ubrk_openBinaryRules(const uint8_t *binaryRules, int32_t rulesLength, * @param status to indicate whether the operation went on smoothly or there were errors * An informational status value, U_SAFECLONE_ALLOCATED_ERROR, is used if any allocations were necessary. * @return pointer to the new clone - * @stable ICU 2.0 + * @deprecated ICU 69 Use ubrk_clone() instead. */ U_CAPI UBreakIterator * U_EXPORT2 ubrk_safeClone( @@ -321,6 +323,23 @@ ubrk_safeClone( int32_t *pBufferSize, UErrorCode *status); +#endif /* U_HIDE_DEPRECATED_API */ + +#ifndef U_HIDE_DRAFT_API + +/** + * Thread safe cloning operation. + * @param bi iterator to be cloned + * @param status to indicate whether the operation went on smoothly or there were errors + * @return pointer to the new clone + * @draft ICU 69 + */ +U_CAPI UBreakIterator * U_EXPORT2 +ubrk_clone(const UBreakIterator *bi, + UErrorCode *status); + +#endif // U_HIDE_DRAFT_API + #ifndef U_HIDE_DEPRECATED_API /** diff --git a/icu4c/source/test/cintltst/cbiapts.c b/icu4c/source/test/cintltst/cbiapts.c index c72de75bcd3..40272c8ff73 100644 --- a/icu4c/source/test/cintltst/cbiapts.c +++ b/icu4c/source/test/cintltst/cbiapts.c @@ -49,6 +49,7 @@ #if !UCONFIG_NO_FILE_IO static void TestBreakIteratorSafeClone(void); +static void TestBreakIteratorClone(void); #endif static void TestBreakIteratorRules(void); static void TestBreakIteratorRuleError(void); @@ -66,6 +67,7 @@ void addBrkIterAPITest(TestNode** root) #if !UCONFIG_NO_FILE_IO addTest(root, &TestBreakIteratorCAPI, "tstxtbd/cbiapts/TestBreakIteratorCAPI"); addTest(root, &TestBreakIteratorSafeClone, "tstxtbd/cbiapts/TestBreakIteratorSafeClone"); + addTest(root, &TestBreakIteratorClone, "tstxtbd/cbiapts/TestBreakIteratorClone"); addTest(root, &TestBreakIteratorUText, "tstxtbd/cbiapts/TestBreakIteratorUText"); #endif addTest(root, &TestBreakIteratorRules, "tstxtbd/cbiapts/TestBreakIteratorRules"); @@ -515,6 +517,88 @@ static void TestBreakIteratorSafeClone(void) ubrk_close(someIterators[i]); } } + +static void TestBreakIteratorClone(void) +{ + const UChar text[] = u"He's from Africa. Mr. Livingston, I presume? Yeah"; + UBreakIterator * someIterators [CLONETEST_ITERATOR_COUNT]; + + UBreakIterator * brk; + UErrorCode status = U_ZERO_ERROR; + int32_t start,pos; + int32_t i; + + /*Testing ubrk_clone */ + + /* US & Thai - rule-based & dictionary based */ + someIterators[0] = ubrk_open(UBRK_WORD, "en_US", text, u_strlen(text), &status); + if(!someIterators[0] || U_FAILURE(status)) { + log_data_err("Couldn't open en_US word break iterator - %s\n", u_errorName(status)); + return; + } + + someIterators[1] = ubrk_open(UBRK_WORD, "th_TH", text, u_strlen(text), &status); + if(!someIterators[1] || U_FAILURE(status)) { + log_data_err("Couldn't open th_TH word break iterator - %s\n", u_errorName(status)); + return; + } + + /* test each type of iterator */ + for (i = 0; i < CLONETEST_ITERATOR_COUNT; i++) + { + /* error status - should return 0 & keep error the same */ + status = U_MEMORY_ALLOCATION_ERROR; + if (NULL != ubrk_clone(someIterators[i], &status) || status != U_MEMORY_ALLOCATION_ERROR) + { + log_err("FAIL: Cloned Iterator failed to deal correctly with incoming error status\n"); + } + + status = U_ZERO_ERROR; + + /* Do these cloned Iterators work at all - make a first & next call */ + brk = ubrk_clone(someIterators[i], &status); + + start = ubrk_first(brk); + if(start!=0) + log_err("error ubrk_start(clone) did not return 0, but %i\n", start); + pos=ubrk_next(brk); + if(pos!=4) + log_err("error ubrk_next(clone) did not return 4, but %i\n", pos); + + ubrk_close(brk); + + pos = ubrk_next(someIterators[i]); + if (pos != 4) { + log_err("error ubrk_next(iter) did not return 4, but %i\n", pos); + } + + brk = ubrk_clone(someIterators[i], &status); + // The text position should be kept in the new clone. + start = ubrk_current(brk); + if (start != 4) { + log_err("error ubrk_current(clone) did not return 4, but %i\n", start); + } + + pos = ubrk_next(brk); + if (pos != 5) { + log_err("error ubrk_next(clone) did not return 5, but %i\n", pos); + } + start = ubrk_current(brk); + if (start != 5) { + log_err("error ubrk_current(clone) did not return 5, but %i\n", start); + } + + start = ubrk_current(someIterators[i]); + if (start != 4) { + log_err("error ubrk_current(iter) did not keep the same position of 4," + " but %i after advancing the position in its clone.\n", start); + } + + ubrk_close(brk); + + ubrk_close(someIterators[i]); + } +} #endif