MCPcopy Create free account
hub / github.com/apache/impala / Utf8CaseConversion

Function Utf8CaseConversion

be/src/exprs/string-functions-ir.cc:382–441  ·  view source on GitHub ↗

Converts string based on the transform function 'fn'. The unit of the conversion is a wchar_t (i.e. uint32_t) which is parsed from multi bytes using std::mbtowc(). The transform function 'fn' accepts two parameters: the original wchar_t and a flag indicating whether it's the first character of a word. After the transformation, the wchar_t is converted back to bytes.

Source from the content-addressed store, hash-verified

380/// indicating whether it's the first character of a word.
381/// After the transformation, the wchar_t is converted back to bytes.
382static StringVal Utf8CaseConversion(FunctionContext* context, const StringVal& str,
383 uint32_t (*fn)(uint32_t, bool*)) {
384 // Usually the upper/lower cases have the same size in bytes. Here we add 4 bytes
385 // buffer in case of illegal Unicodes.
386 int max_result_bytes = str.len + 4;
387 StringVal result(context, max_result_bytes);
388 if (UNLIKELY(result.is_null)) return StringVal::null();
389 wchar_t wc;
390 int wc_bytes;
391 bool word_start = true;
392 uint8_t* result_ptr = result.ptr;
393 std::mbstate_t wc_state{};
394 std::mbstate_t mb_state{};
395 for (int i = 0; i < str.len; i += wc_bytes) {
396 // std::mbtowc converts a multibyte sequence to a wide character. It's not
397 // thread safe. Here we use std::mbrtowc instead.
398 wc_bytes = std::mbrtowc(&wc, reinterpret_cast<char*>(str.ptr + i), str.len - i,
399 &wc_state);
400 bool needs_conversion = true;
401 if (wc_bytes == 0) {
402 // std::mbtowc returns 0 when hitting '\0'.
403 wc = 0;
404 wc_bytes = 1;
405 } else if (wc_bytes < 0) {
406 ReportErrorBytes(context, str, i);
407 // Replace it to the replacement character (U+FFFD)
408 wc = 0xFFFD;
409 needs_conversion = false;
410 // Jump to the next legal UTF-8 start byte.
411 wc_bytes = 1;
412 while (i + wc_bytes < str.len && !BitUtil::IsUtf8StartByte(str.ptr[i + wc_bytes])) {
413 wc_bytes++;
414 }
415 }
416 if (needs_conversion) wc = fn(wc, &word_start);
417 // std::wctomb converts a wide character to a multibyte sequence. It's not
418 // thread safe. Here we use std::wcrtomb instead.
419 int res_bytes = std::wcrtomb(reinterpret_cast<char*>(result_ptr), wc, &mb_state);
420 if (res_bytes <= 0) {
421 if (needs_conversion) {
422 context->AddWarning(Substitute(
423 "Ignored illegal wide character in results: $0. Current locale: $1",
424 wc, std::locale("").name()).c_str());
425 }
426 continue;
427 }
428 result_ptr += res_bytes;
429 if (result_ptr - result.ptr > max_result_bytes - 4) {
430 // Double the result buffer for overflow
431 max_result_bytes *= 2;
432 max_result_bytes = min<int>(StringVal::MAX_LENGTH,
433 static_cast<int>(BitUtil::RoundUpToPowerOfTwo(max_result_bytes)));
434 int offset = result_ptr - result.ptr;
435 if (UNLIKELY(!result.Resize(context, max_result_bytes))) return StringVal::null();
436 result_ptr = result.ptr + offset;
437 }
438 }
439 result.len = result_ptr - result.ptr;

Callers 3

LowerUtf8Method · 0.85
UpperUtf8Method · 0.85
InitCapUtf8Method · 0.85

Calls 6

ReportErrorBytesFunction · 0.85
SubstituteFunction · 0.85
AddWarningMethod · 0.80
fnFunction · 0.50
nameMethod · 0.45
ResizeMethod · 0.45

Tested by

no test coverage detected