diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index c879cf99008..53788758890 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -88,6 +88,33 @@ bool select_word(const String &p_s, int p_col, int &r_beg, int &r_end) { } } +// This function assumes both strings are at least len length. +template >, typename = std::enable_if_t>> +_FORCE_INLINE_ constexpr bool string_equal(const LHS *lhs, const RHS *rhs, size_t len) { + if constexpr (std::is_same_v) { + // Can optimize this case. + return memcmp(lhs, rhs, len * sizeof(LHS)) == 0; + } else { + for (size_t j = 0; j < len; j++) { + if ((char32_t)lhs[j] != (char32_t)rhs[j]) { + return false; + } + } + return true; + } +} + +// This function assumes both strings are at least len length. +template +_FORCE_INLINE_ constexpr bool string_equal_lower(const LHS *lhs, const RHS *rhs, size_t len) { + for (size_t j = 0; j < len; j++) { + if (_find_lower(lhs[j]) != _find_lower(rhs[j])) { + return false; + } + } + return true; +} + /*************************************************************************/ /* Char16String */ /*************************************************************************/ @@ -3101,38 +3128,22 @@ int String::find(const String &p_str, int p_from) const { return -1; } - const int src_len = p_str.length(); - + const int str_len = p_str.length(); const int len = length(); - if (src_len == 0 || len == 0) { - return -1; // won't find anything! + if (str_len == 0 || len == 0 || str_len > (len - p_from)) { + return -1; // Won't find anything! } - if (src_len == 1) { + if (str_len == 1) { return find_char(p_str[0], p_from); // Optimize with single-char find. } const char32_t *src = get_data(); const char32_t *str = p_str.get_data(); - for (int i = p_from; i <= (len - src_len); i++) { - bool found = true; - for (int j = 0; j < src_len; j++) { - int read_pos = i + j; - - if (read_pos >= len) { - ERR_PRINT("read_pos>=len"); - return -1; - } - - if (src[read_pos] != str[j]) { - found = false; - break; - } - } - - if (found) { + for (int i = p_from; i <= (len - str_len); i++) { + if (string_equal(src + i, str, str_len)) { return i; } } @@ -3145,49 +3156,22 @@ int String::find(const char *p_str, int p_from) const { return -1; } - const int src_len = strlen(p_str); - + const int str_len = strlen(p_str); const int len = length(); - if (len == 0 || src_len == 0) { - return -1; // won't find anything! + if (len == 0 || str_len == 0 || str_len > (len - p_from)) { + return -1; // Won't find anything! } - if (src_len == 1) { + if (str_len == 1) { return find_char(*p_str, p_from); // Optimize with single-char find. } const char32_t *src = get_data(); - if (src_len == 1) { - const char32_t needle = p_str[0]; - - for (int i = p_from; i < len; i++) { - if (src[i] == needle) { - return i; - } - } - - } else { - for (int i = p_from; i <= (len - src_len); i++) { - bool found = true; - for (int j = 0; j < src_len; j++) { - int read_pos = i + j; - - if (read_pos >= len) { - ERR_PRINT("read_pos>=len"); - return -1; - } - - if (src[read_pos] != (char32_t)p_str[j]) { - found = false; - break; - } - } - - if (found) { - return i; - } + for (int i = p_from; i <= (len - str_len); i++) { + if (string_equal(src + i, p_str, str_len)) { + return i; } } @@ -3206,47 +3190,31 @@ int String::findmk(const Vector &p_keys, int p_from, int *r_key) const { return -1; } - //int src_len=p_str.length(); const String *keys = &p_keys[0]; - int key_count = p_keys.size(); - int len = length(); + const int key_count = p_keys.size(); + const int len = length(); if (len == 0) { - return -1; // won't find anything! + return -1; // Won't find anything! } const char32_t *src = get_data(); for (int i = p_from; i < len; i++) { - bool found = true; for (int k = 0; k < key_count; k++) { - found = true; - if (r_key) { - *r_key = k; + const int str_len = keys[k].length(); + + if (i + str_len > len) { + continue; // Can't find this key here. } - const char32_t *cmp = keys[k].get_data(); - int l = keys[k].length(); - for (int j = 0; j < l; j++) { - int read_pos = i + j; - - if (read_pos >= len) { - found = false; - break; - } - - if (src[read_pos] != cmp[j]) { - found = false; - break; + const char32_t *str = keys[k].get_data(); + if (string_equal(src + i, str, str_len)) { + if (r_key) { + *r_key = k; } + return i; } - if (found) { - break; - } - } - - if (found) { - return i; } } @@ -3258,34 +3226,18 @@ int String::findn(const String &p_str, int p_from) const { return -1; } - int src_len = p_str.length(); + const int str_len = p_str.length(); + const int len = length(); - if (src_len == 0 || length() == 0) { - return -1; // won't find anything! + if (str_len == 0 || len == 0 || str_len > (len - p_from)) { + return -1; // Won't find anything! } - const char32_t *srcd = get_data(); + const char32_t *src = get_data(); + const char32_t *str = p_str.get_data(); - for (int i = p_from; i <= (length() - src_len); i++) { - bool found = true; - for (int j = 0; j < src_len; j++) { - int read_pos = i + j; - - if (read_pos >= length()) { - ERR_PRINT("read_pos>=length()"); - return -1; - } - - char32_t src = _find_lower(srcd[read_pos]); - char32_t dst = _find_lower(p_str[j]); - - if (src != dst) { - found = false; - break; - } - } - - if (found) { + for (int i = p_from; i <= (len - str_len); i++) { + if (string_equal_lower(src + i, str, str_len)) { return i; } } @@ -3294,38 +3246,21 @@ int String::findn(const String &p_str, int p_from) const { } int String::findn(const char *p_str, int p_from) const { - if (p_from < 0) { + if (p_from < 0 || !p_str) { return -1; } - int src_len = strlen(p_str); + const int str_len = strlen(p_str); + const int len = length(); - if (src_len == 0 || length() == 0) { - return -1; // won't find anything! + if (str_len == 0 || len == 0 || str_len > (len - p_from)) { + return -1; // Won't find anything! } - const char32_t *srcd = get_data(); + const char32_t *src = get_data(); - for (int i = p_from; i <= (length() - src_len); i++) { - bool found = true; - for (int j = 0; j < src_len; j++) { - int read_pos = i + j; - - if (read_pos >= length()) { - ERR_PRINT("read_pos>=length()"); - return -1; - } - - char32_t src = _find_lower(srcd[read_pos]); - char32_t dst = _find_lower(p_str[j]); - - if (src != dst) { - found = false; - break; - } - } - - if (found) { + for (int i = p_from; i <= (len - str_len); i++) { + if (string_equal_lower(src + i, p_str, str_len)) { return i; } } @@ -3334,45 +3269,20 @@ int String::findn(const char *p_str, int p_from) const { } int String::rfind(const String &p_str, int p_from) const { - // establish a limit - int limit = length() - p_str.length(); - if (limit < 0) { - return -1; - } - - // establish a starting point - if (p_from < 0) { - p_from = limit; - } else if (p_from > limit) { - p_from = limit; - } - - int src_len = p_str.length(); - int len = length(); - - if (src_len == 0 || len == 0) { - return -1; // won't find anything! + const int str_len = p_str.length(); + const int len = length(); + const int max_findable_idx = length() - str_len; + + if (str_len == 0 || len == 0 || max_findable_idx < 0) { + return -1; // Won't find anything! } + const int from = p_from < 0 ? max_findable_idx : MIN(p_from, max_findable_idx); const char32_t *src = get_data(); + const char32_t *str = p_str.get_data(); - for (int i = p_from; i >= 0; i--) { - bool found = true; - for (int j = 0; j < src_len; j++) { - int read_pos = i + j; - - if (read_pos >= len) { - ERR_PRINT("read_pos>=len"); - return -1; - } - - if (src[read_pos] != p_str[j]) { - found = false; - break; - } - } - - if (found) { + for (int i = from; i >= 0; i--) { + if (string_equal(src + i, str, str_len)) { return i; } } @@ -3381,49 +3291,19 @@ int String::rfind(const String &p_str, int p_from) const { } int String::rfind(const char *p_str, int p_from) const { - const int source_length = length(); - int substring_length = strlen(p_str); + const int len = length(); + const int str_len = strlen(p_str); + const int max_findable_idx = length() - str_len; - if (source_length == 0 || substring_length == 0) { - return -1; // won't find anything! + if (len == 0 || str_len == 0 || max_findable_idx < 0) { + return -1; // Won't find anything! } - // establish a limit - int limit = length() - substring_length; - if (limit < 0) { - return -1; - } + const int from = p_from < 0 ? max_findable_idx : MIN(p_from, max_findable_idx); + const char32_t *src = get_data(); - // establish a starting point - int starting_point; - if (p_from < 0) { - starting_point = limit; - } else if (p_from > limit) { - starting_point = limit; - } else { - starting_point = p_from; - } - - const char32_t *source = get_data(); - - for (int i = starting_point; i >= 0; i--) { - bool found = true; - for (int j = 0; j < substring_length; j++) { - int read_pos = i + j; - - if (read_pos >= source_length) { - ERR_PRINT("read_pos>=source_length"); - return -1; - } - - const char32_t key_needle = p_str[j]; - if (source[read_pos] != key_needle) { - found = false; - break; - } - } - - if (found) { + for (int i = from; i >= 0; i--) { + if (string_equal(src + i, p_str, str_len)) { return i; } } @@ -3436,48 +3316,20 @@ int String::rfind_char(char32_t p_char, int p_from) const { } int String::rfindn(const String &p_str, int p_from) const { - // establish a limit - int limit = length() - p_str.length(); - if (limit < 0) { - return -1; - } - - // establish a starting point - if (p_from < 0) { - p_from = limit; - } else if (p_from > limit) { - p_from = limit; - } - - int src_len = p_str.length(); - int len = length(); - - if (src_len == 0 || len == 0) { - return -1; // won't find anything! + const int str_len = p_str.length(); + const int len = length(); + const int max_findable_idx = length() - str_len; + + if (str_len == 0 || len == 0 || max_findable_idx < 0) { + return -1; // Won't find anything! } + const int from = p_from < 0 ? max_findable_idx : MIN(p_from, max_findable_idx); const char32_t *src = get_data(); + const char32_t *str = p_str.get_data(); - for (int i = p_from; i >= 0; i--) { - bool found = true; - for (int j = 0; j < src_len; j++) { - int read_pos = i + j; - - if (read_pos >= len) { - ERR_PRINT("read_pos>=len"); - return -1; - } - - char32_t srcc = _find_lower(src[read_pos]); - char32_t dstc = _find_lower(p_str[j]); - - if (srcc != dstc) { - found = false; - break; - } - } - - if (found) { + for (int i = from; i >= 0; i--) { + if (string_equal_lower(src + i, str, str_len)) { return i; } } @@ -3486,52 +3338,19 @@ int String::rfindn(const String &p_str, int p_from) const { } int String::rfindn(const char *p_str, int p_from) const { - const int source_length = length(); - int substring_length = strlen(p_str); + const int len = length(); + const int str_len = strlen(p_str); + const int max_findable_idx = length() - str_len; - if (source_length == 0 || substring_length == 0) { - return -1; // won't find anything! + if (len == 0 || str_len == 0 || max_findable_idx < 0) { + return -1; // Won't find anything! } - // establish a limit - int limit = length() - substring_length; - if (limit < 0) { - return -1; - } + const char32_t *src = get_data(); + const int from = p_from < 0 ? max_findable_idx : MIN(p_from, max_findable_idx); - // establish a starting point - int starting_point; - if (p_from < 0) { - starting_point = limit; - } else if (p_from > limit) { - starting_point = limit; - } else { - starting_point = p_from; - } - - const char32_t *source = get_data(); - - for (int i = starting_point; i >= 0; i--) { - bool found = true; - for (int j = 0; j < substring_length; j++) { - int read_pos = i + j; - - if (read_pos >= source_length) { - ERR_PRINT("read_pos>=source_length"); - return -1; - } - - const char32_t key_needle = p_str[j]; - int srcc = _find_lower(source[read_pos]); - int keyc = _find_lower(key_needle); - - if (srcc != keyc) { - found = false; - break; - } - } - - if (found) { + for (int i = from; i >= 0; i--) { + if (string_equal_lower(src + i, p_str, str_len)) { return i; } } diff --git a/tests/core/string/test_string.h b/tests/core/string/test_string.h index ea60230947d..dfb7b7ae04d 100644 --- a/tests/core/string/test_string.h +++ b/tests/core/string/test_string.h @@ -376,6 +376,8 @@ TEST_CASE("[String] Find") { MULTICHECK_STRING_EQ(s, find, "tty", 3); MULTICHECK_STRING_EQ(s, find, "Revenge of the Monster Truck", -1); MULTICHECK_STRING_INT_EQ(s, find, "Wo", 9, 13); + MULTICHECK_STRING_INT_EQ(s, find, "Wo", 1000, -1); + MULTICHECK_STRING_INT_EQ(s, find, "Wo", -1, -1); MULTICHECK_STRING_EQ(s, find, "", -1); MULTICHECK_STRING_EQ(s, find, "Pretty Woman Woman", 0); MULTICHECK_STRING_EQ(s, find, "WOMAN", -1); @@ -387,6 +389,8 @@ TEST_CASE("[String] Find") { MULTICHECK_STRING_EQ(s, rfind, "man", 15); MULTICHECK_STRING_EQ(s, rfind, "WOMAN", -1); MULTICHECK_STRING_INT_EQ(s, rfind, "", 15, -1); + MULTICHECK_STRING_INT_EQ(s, rfind, "Wo", 1000, 13); + MULTICHECK_STRING_INT_EQ(s, rfind, "Wo", -1, 13); } TEST_CASE("[String] Find character") { @@ -406,6 +410,8 @@ TEST_CASE("[String] Find case insensitive") { String s = "Pretty Whale Whale"; MULTICHECK_STRING_EQ(s, findn, "WHA", 7); MULTICHECK_STRING_INT_EQ(s, findn, "WHA", 9, 13); + MULTICHECK_STRING_INT_EQ(s, findn, "WHA", 1000, -1); + MULTICHECK_STRING_INT_EQ(s, findn, "WHA", -1, -1); MULTICHECK_STRING_EQ(s, findn, "Revenge of the Monster SawFish", -1); MULTICHECK_STRING_EQ(s, findn, "", -1); MULTICHECK_STRING_EQ(s, findn, "wha", 7); @@ -417,6 +423,8 @@ TEST_CASE("[String] Find case insensitive") { MULTICHECK_STRING_EQ(s, rfindn, "wha", 13); MULTICHECK_STRING_EQ(s, rfindn, "Wha", 13); MULTICHECK_STRING_INT_EQ(s, rfindn, "", 13, -1); + MULTICHECK_STRING_INT_EQ(s, rfindn, "WHA", 1000, 13); + MULTICHECK_STRING_INT_EQ(s, rfindn, "WHA", -1, 13); } TEST_CASE("[String] Find MK") { @@ -433,6 +441,9 @@ TEST_CASE("[String] Find MK") { CHECK(s.findmk(keys, 5, &key) == 9); CHECK(key == 2); + + CHECK(s.findmk(keys, -1, &key) == -1); + CHECK(s.findmk(keys, 1000, &key) == -1); } TEST_CASE("[String] Find and replace") {