| 2981 | |
| 2982 | template <class T> |
| 2983 | static String _remove_chars_common(const String &p_this, const T *p_chars, int p_chars_len) { |
| 2984 | // Delegate if p_chars has a single element. |
| 2985 | if (p_chars_len == 1) { |
| 2986 | return p_this.remove_char(*p_chars); |
| 2987 | } else if (p_chars_len == 0) { |
| 2988 | return p_this; |
| 2989 | } |
| 2990 | |
| 2991 | int len = p_this.length(); |
| 2992 | |
| 2993 | if (len == 0) { |
| 2994 | return p_this; |
| 2995 | } |
| 2996 | |
| 2997 | int index = 0; |
| 2998 | const char32_t *old_ptr = p_this.ptr(); |
| 2999 | for (; index < len; ++index) { |
| 3000 | if (_contains_char(old_ptr[index], p_chars, p_chars_len)) { |
| 3001 | break; |
| 3002 | } |
| 3003 | } |
| 3004 | |
| 3005 | // If no occurrence of `chars` was found, return this. |
| 3006 | if (index == len) { |
| 3007 | return p_this; |
| 3008 | } |
| 3009 | |
| 3010 | // If we found at least one occurrence of `chars`, create new string, allocating enough space for the current length minus one. |
| 3011 | String new_string; |
| 3012 | new_string.resize_uninitialized(len); |
| 3013 | char32_t *new_ptr = new_string.ptrw(); |
| 3014 | |
| 3015 | // Copy part of input before `char`. |
| 3016 | memcpy(new_ptr, old_ptr, index * sizeof(char32_t)); |
| 3017 | |
| 3018 | int new_size = index; |
| 3019 | |
| 3020 | // Copy rest, skipping `chars`. |
| 3021 | for (++index; index < len; ++index) { |
| 3022 | const char32_t old_char = old_ptr[index]; |
| 3023 | if (!_contains_char(old_char, p_chars, p_chars_len)) { |
| 3024 | new_ptr[new_size] = old_char; |
| 3025 | ++new_size; |
| 3026 | } |
| 3027 | } |
| 3028 | |
| 3029 | new_ptr[new_size] = 0; |
| 3030 | |
| 3031 | // Shrink new string to fit. |
| 3032 | new_string.resize_uninitialized(new_size + 1); |
| 3033 | |
| 3034 | return new_string; |
| 3035 | } |
| 3036 | |
| 3037 | String String::remove_chars(const String &p_chars) const { |
| 3038 | return _remove_chars_common(*this, p_chars.ptr(), p_chars.length()); |
no test coverage detected