Convert an utf8 string to its corresponding lowercase string
| 215 | |
| 216 | // Convert an utf8 string to its corresponding lowercase string |
| 217 | GANDIVA_EXPORT |
| 218 | const char* gdv_fn_lower_utf8(int64_t context, const char* data, int32_t data_len, |
| 219 | int32_t* out_len) { |
| 220 | if (data_len == 0) { |
| 221 | *out_len = 0; |
| 222 | return ""; |
| 223 | } |
| 224 | |
| 225 | // If it is a single-byte character (ASCII), corresponding lowercase is always 1-byte |
| 226 | // long; if it is >= 2 bytes long, lowercase can be at most 4 bytes long, so length of |
| 227 | // the output can be at most twice the length of the input |
| 228 | char* out = reinterpret_cast<char*>(gdv_fn_context_arena_malloc(context, 2 * data_len)); |
| 229 | if (out == nullptr) { |
| 230 | gdv_fn_context_set_error_msg(context, "Could not allocate memory for output string"); |
| 231 | *out_len = 0; |
| 232 | return ""; |
| 233 | } |
| 234 | |
| 235 | int32_t char_len, out_char_len, out_idx = 0; |
| 236 | uint32_t char_codepoint; |
| 237 | |
| 238 | for (int32_t i = 0; i < data_len; i += char_len) { |
| 239 | char_len = gdv_fn_utf8_char_length(data[i]); |
| 240 | // For single byte characters: |
| 241 | // If it is an uppercase ASCII character, set the output to its corresponding |
| 242 | // lowercase character; else, set the output to the read character |
| 243 | if (char_len == 1) { |
| 244 | char cur = data[i]; |
| 245 | // 'A' - 'Z' : 0x41 - 0x5a |
| 246 | // 'a' - 'z' : 0x61 - 0x7a |
| 247 | if (cur >= 0x41 && cur <= 0x5a) { |
| 248 | out[out_idx++] = static_cast<char>(cur + 0x20); |
| 249 | } else { |
| 250 | out[out_idx++] = cur; |
| 251 | } |
| 252 | continue; |
| 253 | } |
| 254 | |
| 255 | // Control reaches here when we encounter a multibyte character |
| 256 | const auto* in_char = (const uint8_t*)(data + i); |
| 257 | |
| 258 | // Decode the multibyte character |
| 259 | bool is_valid_utf8_char = |
| 260 | arrow::util::UTF8Decode((const uint8_t**)&in_char, &char_codepoint); |
| 261 | |
| 262 | // If it is an invalid utf8 character, UTF8Decode evaluates to false |
| 263 | if (!is_valid_utf8_char) { |
| 264 | gdv_fn_set_error_for_invalid_utf8(context, data[i]); |
| 265 | *out_len = 0; |
| 266 | return ""; |
| 267 | } |
| 268 | |
| 269 | // Convert the encoded codepoint to its lowercase codepoint |
| 270 | int32_t lower_codepoint = utf8proc_tolower(char_codepoint); |
| 271 | |
| 272 | // UTF8Encode advances the pointer by the number of bytes present in the lowercase |
| 273 | // character |
| 274 | auto* out_char = (uint8_t*)(out + out_idx); |