Changeset 261257 in webkit
- Timestamp:
- May 6, 2020, 4:01:06 PM (5 years ago)
- Location:
- trunk/Source
- Files:
-
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r261233 r261257 1 2020-05-06 Darin Adler <darin@apple.com> 2 3 Make a helper for the pattern of ICU functions that may need to be called twice to populate a buffer 4 https://bugs.webkit.org/show_bug.cgi?id=211499 5 6 Reviewed by Ross Kirsling. 7 8 * runtime/IntlDateTimeFormat.cpp: 9 (JSC::defaultTimeZone): Use callBufferProducingFunction. 10 (JSC::canonicalizeTimeZoneName): Ditto. 11 (JSC::IntlDateTimeFormat::initializeDateTimeFormat): Ditto. 12 (JSC::IntlDateTimeFormat::format const): Ditto. 13 (JSC::IntlDateTimeFormat::formatToParts const): Ditto. 14 * runtime/IntlLocale.cpp: 15 (JSC::LocaleIDBuilder::toCanonical): Ditto. 16 (JSC::IntlLocale::language): Ditto. 17 (JSC::IntlLocale::script): Ditto. 18 (JSC::IntlLocale::region): Ditto. 19 * runtime/IntlNumberFormat.cpp: 20 (JSC::IntlNumberFormat::format const): Ditto. 21 (JSC::IntlNumberFormat::formatToParts const): Ditto. 22 * runtime/IntlObject.cpp: 23 (JSC::languageTagForLocaleID): Ditto. 24 * runtime/IntlRelativeTimeFormat.cpp: 25 (JSC::IntlRelativeTimeFormat::formatInternal const): Ditto. 26 (JSC::IntlRelativeTimeFormat::formatToParts const): Ditto. 27 * runtime/StringPrototype.cpp: 28 (JSC::toLocaleCase): Ditto. 29 1 30 2020-05-06 Devin Rousso <drousso@apple.com> 2 31 -
trunk/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp
r261182 r261257 106 106 static String defaultTimeZone() 107 107 { 108 UErrorCode status = U_ZERO_ERROR;109 108 String canonical; 110 109 111 Vector<UChar, 32> buffer(32); 112 auto bufferLength = ucal_getDefaultTimeZone(buffer.data(), buffer.size(), &status); 113 if (needsToGrowToProduceBuffer(status)) { 114 status = U_ZERO_ERROR; 115 buffer.grow(bufferLength); 116 ucal_getDefaultTimeZone(buffer.data(), bufferLength, &status); 117 } 110 Vector<UChar, 32> buffer; 111 auto status = callBufferProducingFunction(ucal_getDefaultTimeZone, buffer); 118 112 if (U_SUCCESS(status)) { 119 status = U_ZERO_ERROR; 120 Vector<UChar, 32> canonicalBuffer(32); 121 auto canonicalLength = ucal_getCanonicalTimeZoneID(buffer.data(), bufferLength, canonicalBuffer.data(), canonicalBuffer.size(), nullptr, &status); 122 if (needsToGrowToProduceBuffer(status)) { 123 status = U_ZERO_ERROR; 124 canonicalBuffer.grow(canonicalLength); 125 ucal_getCanonicalTimeZoneID(buffer.data(), bufferLength, canonicalBuffer.data(), canonicalLength, nullptr, &status); 126 } 113 Vector<UChar, 32> canonicalBuffer; 114 status = callBufferProducingFunction(ucal_getCanonicalTimeZoneID, buffer.data(), buffer.size(), canonicalBuffer, nullptr); 127 115 if (U_SUCCESS(status)) 128 canonical = String(canonicalBuffer .data(), canonicalLength);116 canonical = String(canonicalBuffer); 129 117 } 130 118 … … 147 135 status = U_ZERO_ERROR; 148 136 int32_t ianaTimeZoneLength; 149 // Time zone names are re spresented as UChar[] in all related ICU apis.137 // Time zone names are represented as UChar[] in all related ICU APIs. 150 138 const UChar* ianaTimeZone = uenum_unext(timeZones, &ianaTimeZoneLength, &status); 151 139 ASSERT(U_SUCCESS(status)); … … 164 152 // 2. If ianaTimeZone is a Link name, then let ianaTimeZone be the corresponding Zone name as specified in the “backward” file of the IANA Time Zone Database. 165 153 166 Vector<UChar, 32> buffer(ianaTimeZoneLength); 167 status = U_ZERO_ERROR; 168 auto canonicalLength = ucal_getCanonicalTimeZoneID(ianaTimeZone, ianaTimeZoneLength, buffer.data(), ianaTimeZoneLength, nullptr, &status); 169 if (needsToGrowToProduceBuffer(status)) { 170 buffer.grow(canonicalLength); 171 status = U_ZERO_ERROR; 172 ucal_getCanonicalTimeZoneID(ianaTimeZone, ianaTimeZoneLength, buffer.data(), canonicalLength, nullptr, &status); 173 } 174 ASSERT(U_SUCCESS(status)); 175 canonical = String(buffer.data(), canonicalLength); 154 Vector<UChar, 32> buffer; 155 auto status = callBufferProducingFunction(ucal_getCanonicalTimeZoneID, ianaTimeZone, ianaTimeZoneLength, buffer, nullptr); 156 ASSERT_UNUSED(status, U_SUCCESS(status)); 157 canonical = String(buffer); 176 158 } while (canonical.isNull()); 177 159 uenum_close(timeZones); … … 637 619 String skeleton = skeletonBuilder.toString(); 638 620 StringView skeletonView(skeleton); 639 Vector<UChar, 32> patternBuffer(32); 640 status = U_ZERO_ERROR; 641 auto patternLength = udatpg_getBestPatternWithOptions(generator, skeletonView.upconvertedCharacters(), skeletonView.length(), UDATPG_MATCH_HOUR_FIELD_LENGTH, patternBuffer.data(), patternBuffer.size(), &status); 642 if (needsToGrowToProduceBuffer(status)) { 643 status = U_ZERO_ERROR; 644 patternBuffer.grow(patternLength); 645 udatpg_getBestPattern(generator, skeletonView.upconvertedCharacters(), skeletonView.length(), patternBuffer.data(), patternLength, &status); 646 } 621 Vector<UChar, 32> patternBuffer; 622 status = callBufferProducingFunction(udatpg_getBestPatternWithOptions, generator, skeletonView.upconvertedCharacters(), skeletonView.length(), UDATPG_MATCH_HOUR_FIELD_LENGTH, patternBuffer); 647 623 udatpg_close(generator); 648 624 if (U_FAILURE(status)) { … … 663 639 bool isEscaped = false; 664 640 bool hasHour = false; 665 for (auto i = 0; i < patternLength; ++i) { 666 UChar c = patternBuffer[i]; 641 for (auto& c : patternBuffer) { 667 642 if (c == '\'') 668 643 isEscaped = !isEscaped; 669 644 else if (!isEscaped && (c == 'h' || c == 'H' || c == 'k' || c == 'K')) { 670 patternBuffer[i]= hour;645 c = hour; 671 646 hasHour = true; 672 647 } … … 676 651 } 677 652 678 StringView pattern(patternBuffer.data(), pattern Length);653 StringView pattern(patternBuffer.data(), patternBuffer.size()); 679 654 setFormatsFromPattern(pattern); 680 655 … … 895 870 return throwRangeError(globalObject, scope, "date value is not finite in DateTimeFormat format()"_s); 896 871 897 UErrorCode status = U_ZERO_ERROR; 898 Vector<UChar, 32> result(32); 899 auto resultLength = udat_format(m_dateFormat.get(), value, result.data(), result.size(), nullptr, &status); 900 if (needsToGrowToProduceBuffer(status)) { 901 status = U_ZERO_ERROR; 902 result.grow(resultLength); 903 udat_format(m_dateFormat.get(), value, result.data(), resultLength, nullptr, &status); 904 } 872 Vector<UChar, 32> result; 873 auto status = callBufferProducingFunction(udat_format, m_dateFormat.get(), value, result, nullptr); 905 874 if (U_FAILURE(status)) 906 875 return throwTypeError(globalObject, scope, "failed to format date value"_s); 907 876 908 return jsString(vm, String(result .data(), resultLength));877 return jsString(vm, String(result)); 909 878 } 910 879 … … 987 956 return throwTypeError(globalObject, scope, "failed to open field position iterator"_s); 988 957 989 status = U_ZERO_ERROR; 990 Vector<UChar, 32> result(32); 991 auto resultLength = udat_formatForFields(m_dateFormat.get(), value, result.data(), result.size(), fields.get(), &status); 992 if (needsToGrowToProduceBuffer(status)) { 993 status = U_ZERO_ERROR; 994 result.grow(resultLength); 995 udat_formatForFields(m_dateFormat.get(), value, result.data(), resultLength, fields.get(), &status); 996 } 958 Vector<UChar, 32> result; 959 status = callBufferProducingFunction(udat_formatForFields, m_dateFormat.get(), value, result, fields.get()); 997 960 if (U_FAILURE(status)) 998 961 return throwTypeError(globalObject, scope, "failed to format date value"_s); … … 1002 965 return throwOutOfMemoryError(globalObject, scope); 1003 966 1004 auto resultString = String(result .data(), resultLength);967 auto resultString = String(result); 1005 968 auto literalString = jsNontrivialString(vm, "literal"_s); 1006 969 970 int32_t resultLength = result.size(); 1007 971 int32_t previousEndIndex = 0; 1008 972 int32_t beginIndex = 0; -
trunk/Source/JavaScriptCore/runtime/IntlLocale.cpp
r261215 r261257 91 91 ASSERT(m_buffer.size()); 92 92 93 UErrorCode status = U_ZERO_ERROR; 94 Vector<char, 32> result(32); 95 auto resultLength = uloc_canonicalize(m_buffer.data(), result.data(), result.size(), &status); 96 if (needsToGrowToProduceBuffer(status)) { 97 result.grow(resultLength); 98 status = U_ZERO_ERROR; 99 uloc_canonicalize(m_buffer.data(), result.data(), resultLength, &status); 100 } 93 Vector<char, 32> result; 94 auto status = callBufferProducingFunction(uloc_canonicalize, m_buffer.data(), result); 101 95 if (U_FAILURE(status)) 102 96 return CString(); 103 97 104 return CString(result.data(), result Length);98 return CString(result.data(), result.size()); 105 99 } 106 100 … … 387 381 { 388 382 if (m_language.isNull()) { 389 UErrorCode status = U_ZERO_ERROR; 390 Vector<char, 8> buffer(8); 391 auto bufferLength = uloc_getLanguage(m_localeID.data(), buffer.data(), buffer.size(), &status); 392 if (needsToGrowToProduceBuffer(status)) { 393 buffer.grow(bufferLength); 394 status = U_ZERO_ERROR; 395 uloc_getLanguage(m_localeID.data(), buffer.data(), bufferLength, &status); 396 } 397 ASSERT(U_SUCCESS(status)); 398 399 m_language = String(buffer.data(), bufferLength); 383 Vector<char, 8> buffer; 384 auto status = callBufferProducingFunction(uloc_getLanguage, m_localeID.data(), buffer); 385 ASSERT_UNUSED(status, U_SUCCESS(status)); 386 m_language = String(buffer.data(), buffer.size()); 400 387 } 401 388 return m_language; … … 406 393 { 407 394 if (m_script.isNull()) { 408 UErrorCode status = U_ZERO_ERROR; 409 Vector<char, 4> buffer(4); 410 auto bufferLength = uloc_getScript(m_localeID.data(), buffer.data(), buffer.size(), &status); 411 if (needsToGrowToProduceBuffer(status)) { 412 buffer.grow(bufferLength); 413 status = U_ZERO_ERROR; 414 uloc_getScript(m_localeID.data(), buffer.data(), bufferLength, &status); 415 } 416 ASSERT(U_SUCCESS(status)); 417 418 m_script = String(buffer.data(), bufferLength); 395 Vector<char, 4> buffer; 396 auto status = callBufferProducingFunction(uloc_getScript, m_localeID.data(), buffer); 397 ASSERT_UNUSED(status, U_SUCCESS(status)); 398 m_script = String(buffer.data(), buffer.size()); 419 399 } 420 400 return m_script; … … 425 405 { 426 406 if (m_region.isNull()) { 427 UErrorCode status = U_ZERO_ERROR; 428 Vector<char, 3> buffer(3); 429 auto bufferLength = uloc_getCountry(m_localeID.data(), buffer.data(), buffer.size(), &status); 430 if (needsToGrowToProduceBuffer(status)) { 431 buffer.grow(bufferLength); 432 status = U_ZERO_ERROR; 433 uloc_getCountry(m_localeID.data(), buffer.data(), bufferLength, &status); 434 } 435 ASSERT(U_SUCCESS(status)); 436 437 m_region = String(buffer.data(), bufferLength); 407 Vector<char, 3> buffer; 408 auto status = callBufferProducingFunction(uloc_getCountry, m_localeID.data(), buffer); 409 ASSERT_UNUSED(status, U_SUCCESS(status)); 410 m_region = String(buffer.data(), buffer.size()); 438 411 } 439 412 return m_region; -
trunk/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp
r261182 r261257 348 348 auto scope = DECLARE_THROW_SCOPE(vm); 349 349 350 UErrorCode status = U_ZERO_ERROR; 351 Vector<UChar, 32> buffer(32); 352 auto length = unum_formatDouble(m_numberFormat.get(), value, buffer.data(), buffer.size(), nullptr, &status); 353 if (needsToGrowToProduceBuffer(status)) { 354 buffer.grow(length); 355 status = U_ZERO_ERROR; 356 unum_formatDouble(m_numberFormat.get(), value, buffer.data(), length, nullptr, &status); 357 } 350 Vector<UChar, 32> buffer; 351 auto status = callBufferProducingFunction(unum_formatDouble, m_numberFormat.get(), value, buffer, nullptr); 358 352 if (U_FAILURE(status)) 359 353 return throwTypeError(globalObject, scope, "Failed to format a number."_s); 360 354 361 return jsString(vm, String(buffer .data(), length));355 return jsString(vm, String(buffer)); 362 356 } 363 357 … … 376 370 auto* rawString = reinterpret_cast<const char*>(string.characters8()); 377 371 378 UErrorCode status = U_ZERO_ERROR; 379 Vector<UChar, 32> buffer(32); 380 auto length = unum_formatDecimal(m_numberFormat.get(), rawString, string.length(), buffer.data(), buffer.size(), nullptr, &status); 381 if (needsToGrowToProduceBuffer(status)) { 382 buffer.grow(length); 383 status = U_ZERO_ERROR; 384 unum_formatDecimal(m_numberFormat.get(), rawString, string.length(), buffer.data(), length, nullptr, &status); 385 } 372 Vector<UChar, 32> buffer; 373 auto status = callBufferProducingFunction(unum_formatDecimal, m_numberFormat.get(), rawString, string.length(), buffer, nullptr); 386 374 if (U_FAILURE(status)) 387 375 return throwTypeError(globalObject, scope, "Failed to format a BigInt."_s); 388 376 389 return jsString(vm, String(buffer .data(), length));377 return jsString(vm, String(buffer)); 390 378 } 391 379 … … 540 528 return throwTypeError(globalObject, scope, "failed to open field position iterator"_s); 541 529 542 Vector<UChar, 32> result(32); 543 auto resultLength = unum_formatDoubleForFields(m_numberFormat.get(), value, result.data(), result.size(), fieldItr.get(), &status); 544 if (needsToGrowToProduceBuffer(status)) { 545 status = U_ZERO_ERROR; 546 result.grow(resultLength); 547 unum_formatDoubleForFields(m_numberFormat.get(), value, result.data(), resultLength, fieldItr.get(), &status); 548 } 530 Vector<UChar, 32> result; 531 status = callBufferProducingFunction(unum_formatDoubleForFields, m_numberFormat.get(), value, result, fieldItr.get()); 549 532 if (U_FAILURE(status)) 550 533 return throwTypeError(globalObject, scope, "failed to format a number."_s); 551 534 552 auto resultString = String(result .data(), resultLength);535 auto resultString = String(result); 553 536 554 537 JSArray* parts = JSArray::tryCreate(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous), 0); -
trunk/Source/JavaScriptCore/runtime/IntlObject.cpp
r261215 r261257 179 179 String languageTagForLocaleID(const char* localeID, bool isImmortal) 180 180 { 181 UErrorCode status = U_ZERO_ERROR; 182 Vector<char, 32> buffer(32); 183 auto length = uloc_toLanguageTag(localeID, buffer.data(), buffer.size(), false, &status); 184 if (needsToGrowToProduceBuffer(status)) { 185 buffer.grow(length); 186 status = U_ZERO_ERROR; 187 uloc_toLanguageTag(localeID, buffer.data(), length, false, &status); 188 } 181 Vector<char, 32> buffer; 182 auto status = callBufferProducingFunction(uloc_toLanguageTag, localeID, buffer, false); 189 183 if (U_FAILURE(status)) 190 184 return String(); … … 193 187 // This must be immortal to make concurrent ref/deref safe. 194 188 if (isImmortal) 195 return String (StringImpl::createStaticStringImpl(buffer.data(), length));196 197 return String(buffer.data(), length);189 return StringImpl::createStaticStringImpl(buffer.data(), buffer.size()); 190 191 return String(buffer.data(), buffer.size()); 198 192 } 199 193 -
trunk/Source/JavaScriptCore/runtime/IntlRelativeTimeFormat.cpp
r261182 r261257 246 246 auto formatRelativeTime = m_numeric ? ureldatefmt_formatNumeric : ureldatefmt_format; 247 247 248 UErrorCode status = U_ZERO_ERROR; 249 Vector<UChar, 32> result(32); 250 auto resultLength = formatRelativeTime(m_relativeDateTimeFormatter.get(), value, unitType.value(), result.data(), result.size(), &status); 251 if (needsToGrowToProduceBuffer(status)) { 252 status = U_ZERO_ERROR; 253 result.grow(resultLength); 254 formatRelativeTime(m_relativeDateTimeFormatter.get(), value, unitType.value(), result.data(), resultLength, &status); 255 } 248 Vector<UChar, 32> result; 249 auto status = callBufferProducingFunction(formatRelativeTime, m_relativeDateTimeFormatter.get(), value, unitType.value(), result); 256 250 if (UNLIKELY(U_FAILURE(status))) { 257 251 throwTypeError(globalObject, scope, "failed to format relative time"_s); … … 259 253 } 260 254 261 return String(result .data(), resultLength);255 return String(result); 262 256 } 263 257 … … 289 283 double absValue = std::abs(value); 290 284 291 Vector<UChar, 32> buffer(32); 292 auto numberLength = unum_formatDoubleForFields(m_numberFormat.get(), absValue, buffer.data(), buffer.size(), iterator.get(), &status); 293 if (needsToGrowToProduceBuffer(status)) { 294 status = U_ZERO_ERROR; 295 buffer.grow(numberLength); 296 unum_formatDoubleForFields(m_numberFormat.get(), absValue, buffer.data(), numberLength, iterator.get(), &status); 297 } 285 Vector<UChar, 32> buffer; 286 status = callBufferProducingFunction(unum_formatDoubleForFields, m_numberFormat.get(), absValue, buffer, iterator.get()); 298 287 if (U_FAILURE(status)) 299 288 return throwTypeError(globalObject, scope, "failed to format relative time"_s); 300 289 301 auto formattedNumber = String(buffer .data(), numberLength);290 auto formattedNumber = String(buffer); 302 291 303 292 JSArray* parts = JSArray::tryCreate(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous), 0); … … 312 301 size_t numberStart = formattedRelativeTime.find(formattedNumber); 313 302 if (numberStart != notFound) { 314 numberEnd = numberStart + numberLength;303 numberEnd = numberStart + buffer.size(); 315 304 316 305 // Add initial literal if there is one. -
trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp
r260882 r261257 1558 1558 auto scope = DECLARE_THROW_SCOPE(vm); 1559 1559 1560 auto convertCase = [&] (auto&&... args) {1561 if (mode == CaseConversionMode::Lower)1562 return u_strToLower(std::forward<decltype(args)>(args)...);1563 return u_strToUpper(std::forward<decltype(args)>(args)...);1564 };1565 1566 1560 // 1. Let O be RequireObjectCoercible(this value). 1567 1561 JSValue thisValue = callFrame->thisValue(); … … 1609 1603 if (locale.isNull()) 1610 1604 locale = "und"_s; 1611 1612 CString utf8LocaleBuffer = locale.utf8();1613 const StringView view(s);1614 const int32_t viewLength = view.length();1615 1605 1616 1606 // Delegate the following steps to icu u_strToLower or u_strToUpper. … … 1622 1612 1623 1613 // Most strings lower/upper case will be the same size as original, so try that first. 1624 UErrorCode error = U_ZERO_ERROR; 1625 Vector<UChar> buffer(viewLength); 1626 String lower; 1627 const int32_t resultLength = convertCase(buffer.data(), viewLength, view.upconvertedCharacters(), viewLength, utf8LocaleBuffer.data(), &error); 1628 if (U_SUCCESS(error)) 1629 lower = String(buffer.data(), resultLength); 1630 else if (needsToGrowToProduceBuffer(error)) { 1631 // Converted case needs more space than original. Try again. 1632 UErrorCode error = U_ZERO_ERROR; 1633 Vector<UChar> buffer(resultLength); 1634 convertCase(buffer.data(), resultLength, view.upconvertedCharacters(), viewLength, utf8LocaleBuffer.data(), &error); 1635 if (U_FAILURE(error)) 1636 return throwVMTypeError(globalObject, scope, u_errorName(error)); 1637 lower = String(buffer.data(), resultLength); 1638 } else 1639 return throwVMTypeError(globalObject, scope, u_errorName(error)); 1614 Vector<UChar> buffer; 1615 buffer.reserveInitialCapacity(s.length()); 1616 auto convertCase = mode == CaseConversionMode::Lower ? u_strToLower : u_strToUpper; 1617 auto status = callBufferProducingFunction(convertCase, buffer, StringView { s }.upconvertedCharacters(), s.length(), locale.utf8().data()); 1618 if (U_FAILURE(status)) 1619 return throwVMTypeError(globalObject, scope, u_errorName(status)); 1640 1620 1641 1621 // 18. Return L. 1642 RELEASE_AND_RETURN(scope, JSValue::encode(jsString(vm, lower)));1622 RELEASE_AND_RETURN(scope, JSValue::encode(jsString(vm, String(buffer)))); 1643 1623 } 1644 1624 -
trunk/Source/WTF/ChangeLog
r261254 r261257 1 2020-05-06 Darin Adler <darin@apple.com> 2 3 Make a helper for the pattern of ICU functions that may need to be called twice to populate a buffer 4 https://bugs.webkit.org/show_bug.cgi?id=211499 5 6 Reviewed by Ross Kirsling. 7 8 This first cut version is ready to be used in most, but not all, of the places we use the 9 needsToGrowToProduceBuffer function. The places it is not right for yet are ones that have 10 special considerations because of null character termination or destinations that are 11 not a Vector. Later we can refine that further, if we like, and possibly use something 12 similar in call sites that use needsToGrowToProduceCString as well. 13 14 * wtf/unicode/icu/ICUHelpers.h: 15 (WTF::needsToGrowToProduceBuffer): Changed to constexpr, since we can. 16 (WTF::needsToGrowToProduceCString): Ditto. 17 (WTF::CallBufferProducingFunction::findVector): Added. Implementation detail 18 of callBufferProducingFunction. 19 (WTF::CallBufferProducingFunction::argumentTuple): Ditto. 20 (WTF::callBufferProducingFunction): Added. 21 1 22 2020-05-06 Alex Christensen <achristensen@webkit.org> 2 23 -
trunk/Source/WTF/wtf/unicode/icu/ICUHelpers.h
r260882 r261257 26 26 #pragma once 27 27 28 #include <tuple> 28 29 #include <unicode/utypes.h> 30 #include <wtf/Forward.h> 29 31 30 32 namespace WTF { 31 33 32 inline bool needsToGrowToProduceCString(UErrorCode errorCode) 33 { 34 return errorCode == U_BUFFER_OVERFLOW_ERROR || errorCode == U_STRING_NOT_TERMINATED_WARNING; 35 } 34 constexpr bool needsToGrowToProduceBuffer(UErrorCode); 35 constexpr bool needsToGrowToProduceCString(UErrorCode); 36 36 37 inline bool needsToGrowToProduceBuffer(UErrorCode errorCode) 37 // Use this to call a function from ICU that has the following properties: 38 // - Takes a buffer pointer and capacity. 39 // - Returns the length of the buffer needed. 40 // - Takes a UErrorCode* as its last argument, returning the status, including U_BUFFER_OVERFLOW_ERROR. 41 // Pass the arguments, but pass a Vector in place of the buffer pointer and capacity, and don't pass a UErrorCode*. 42 // This will call the function, once or twice as needed, resizing the buffer as needed. 43 // 44 // Example: 45 // 46 // Vector<UChar, 32> buffer; 47 // auto status = callBufferProducingFunction(ucal_getDefaultTimeZone, buffer); 48 // 49 template<typename FunctionType, typename ...ArgumentTypes> UErrorCode callBufferProducingFunction(const FunctionType&, ArgumentTypes&&...); 50 51 // Implementations of the functions declared above. 52 53 constexpr bool needsToGrowToProduceBuffer(UErrorCode errorCode) 38 54 { 39 55 return errorCode == U_BUFFER_OVERFLOW_ERROR; 40 56 } 41 57 58 constexpr bool needsToGrowToProduceCString(UErrorCode errorCode) 59 { 60 return needsToGrowToProduceBuffer(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING; 42 61 } 43 62 63 namespace CallBufferProducingFunction { 64 65 template<typename CharacterType, size_t inlineCapacity, typename ...ArgumentTypes> auto& findVector(Vector<CharacterType, inlineCapacity>& buffer, ArgumentTypes&&...) 66 { 67 return buffer; 68 } 69 70 template<typename FirstArgumentType, typename ...ArgumentTypes> auto& findVector(FirstArgumentType&&, ArgumentTypes&&... arguments) 71 { 72 return findVector(std::forward<ArgumentTypes>(arguments)...); 73 } 74 75 constexpr std::tuple<> argumentTuple() { return { }; } 76 77 template<typename FirstArgumentType, typename ...OtherArgumentTypes> auto argumentTuple(FirstArgumentType&&, OtherArgumentTypes&&...); 78 79 template<typename CharacterType, size_t inlineCapacity, typename ...OtherArgumentTypes> auto argumentTuple(Vector<CharacterType, inlineCapacity>& buffer, OtherArgumentTypes&&... otherArguments) 80 { 81 return tuple_cat(std::make_tuple(buffer.data(), buffer.size()), argumentTuple(std::forward<OtherArgumentTypes>(otherArguments)...)); 82 } 83 84 template<typename FirstArgumentType, typename ...OtherArgumentTypes> auto argumentTuple(FirstArgumentType&& firstArgument, OtherArgumentTypes&&... otherArguments) 85 { 86 return tuple_cat(std::make_tuple(std::forward<FirstArgumentType>(firstArgument)), argumentTuple(std::forward<OtherArgumentTypes>(otherArguments)...)); 87 } 88 89 } 90 91 template<typename FunctionType, typename ...ArgumentTypes> UErrorCode callBufferProducingFunction(const FunctionType& function, ArgumentTypes&&... arguments) 92 { 93 auto& buffer = CallBufferProducingFunction::findVector(std::forward<ArgumentTypes>(arguments)...); 94 buffer.grow(buffer.capacity()); 95 auto status = U_ZERO_ERROR; 96 auto resultLength = apply(function, CallBufferProducingFunction::argumentTuple(std::forward<ArgumentTypes>(arguments)..., &status)); 97 if (U_SUCCESS(status)) 98 buffer.shrink(resultLength); 99 else if (needsToGrowToProduceBuffer(status)) { 100 status = U_ZERO_ERROR; 101 buffer.grow(resultLength); 102 apply(function, CallBufferProducingFunction::argumentTuple(std::forward<ArgumentTypes>(arguments)..., &status)); 103 ASSERT(U_SUCCESS(status)); 104 } 105 return status; 106 } 107 108 } 109 110 using WTF::callBufferProducingFunction; 44 111 using WTF::needsToGrowToProduceCString; 45 112 using WTF::needsToGrowToProduceBuffer; -
trunk/Source/WebCore/ChangeLog
r261256 r261257 1 2020-05-06 Darin Adler <darin@apple.com> 2 3 Make a helper for the pattern of ICU functions that may need to be called twice to populate a buffer 4 https://bugs.webkit.org/show_bug.cgi?id=211499 5 6 Reviewed by Ross Kirsling. 7 8 * editing/TextIterator.cpp: 9 (WebCore::normalizeCharacters): Use callBufferProducingFunction. 10 1 11 2020-05-06 Simon Fraser <simon.fraser@apple.com> 2 12 -
trunk/Source/WebCore/editing/TextIterator.cpp
r260882 r261257 1832 1832 { 1833 1833 UErrorCode status = U_ZERO_ERROR; 1834 const UNormalizer2* normalizer = unorm2_getNFCInstance(&status);1834 auto* normalizer = unorm2_getNFCInstance(&status); 1835 1835 ASSERT(U_SUCCESS(status)); 1836 1836 1837 buffer.resize(length); 1838 1839 auto normalizedLength = unorm2_normalize(normalizer, characters, length, buffer.data(), length, &status); 1840 ASSERT(U_SUCCESS(status) || needsToGrowToProduceBuffer(status)); 1841 1842 buffer.resize(normalizedLength); 1843 1844 if (U_SUCCESS(status)) 1845 return; 1846 1847 status = U_ZERO_ERROR; 1848 unorm2_normalize(normalizer, characters, length, buffer.data(), length, &status); 1837 buffer.reserveCapacity(length); 1838 1839 status = callBufferProducingFunction(unorm2_normalize, normalizer, characters, length, buffer); 1849 1840 ASSERT(U_SUCCESS(status)); 1850 1841 }
Note:
See TracChangeset
for help on using the changeset viewer.