| 823 | |
| 824 | template <StringFunctions::TrimPosition D> |
| 825 | StringVal StringFunctions::DoUtf8TrimString(const StringVal& str, |
| 826 | const TrimContext& trim_ctx) { |
| 827 | if (UNLIKELY(str.len == 0)) return str; |
| 828 | |
| 829 | const uint8_t* begin = str.ptr; |
| 830 | const uint8_t* end = begin + str.len; |
| 831 | // Find new starting position. |
| 832 | if constexpr (D == LEADING || D == BOTH) { |
| 833 | while (begin < end) { |
| 834 | size_t char_size = BitUtil::NumBytesInUtf8Encoding(*begin); |
| 835 | if (UNLIKELY(begin + char_size > end)) char_size = end - begin; |
| 836 | if (!trim_ctx.Contains(begin, char_size)) break; |
| 837 | begin += char_size; |
| 838 | } |
| 839 | } |
| 840 | // Find new ending position. |
| 841 | if constexpr (D == TRAILING || D == BOTH) { |
| 842 | while (begin < end) { |
| 843 | int char_index = FindUtf8PosBackward(begin, end - begin, 0); |
| 844 | DCHECK_NE(char_index, -1); |
| 845 | const uint8_t* char_begin = begin + char_index; |
| 846 | if (!trim_ctx.Contains(char_begin, end - char_begin)) break; |
| 847 | end = char_begin; |
| 848 | } |
| 849 | } |
| 850 | |
| 851 | return StringVal(const_cast<uint8_t*>(begin), end - begin); |
| 852 | } |
| 853 | |
| 854 | StringVal StringFunctions::Trim(FunctionContext* context, const StringVal& str) { |
| 855 | return DoTrimString<BOTH, true>(context, str, StringVal(" ")); |
nothing calls this directly
no test coverage detected