diff options
author | Raphael <glephunter@gmail.com> | 2024-02-03 15:29:05 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-03 15:29:05 +0800 |
commit | 51702e0aea99fddba74e299e2640dd350a348df3 (patch) | |
tree | 6ae4b0d9b21813a6bde6fb53ead43468ed92da77 /src/nvim/strings.c | |
parent | 6709f7f8f130377f44c36b2150a167a2afcbdff9 (diff) | |
download | rneovim-51702e0aea99fddba74e299e2640dd350a348df3.tar.gz rneovim-51702e0aea99fddba74e299e2640dd350a348df3.tar.bz2 rneovim-51702e0aea99fddba74e299e2640dd350a348df3.zip |
refactor(strcase_save): optimize memory allocation (#27319)
Problem: Double xmalloc usage led to excess memory allocations.
Solution: Switch to xrealloc to adjust memory as needed, minimizing allocations.
Diffstat (limited to 'src/nvim/strings.c')
-rw-r--r-- | src/nvim/strings.c | 61 |
1 files changed, 33 insertions, 28 deletions
diff --git a/src/nvim/strings.c b/src/nvim/strings.c index 468e9213a9..c16b1f4ad0 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -335,36 +335,41 @@ void vim_strup(char *p) char *strcase_save(const char *const orig, bool upper) FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL { - char *res = xstrdup(orig); + // Calculate the initial length and allocate memory for the result + size_t orig_len = strlen(orig); + // +1 for the null terminator + char *res = xmalloc(orig_len + 1); + // Index in the result string + size_t res_index = 0; + // Current position in the original string + const char *p = orig; - char *p = res; while (*p != NUL) { - int c = utf_ptr2char(p); - int l = utf_ptr2len(p); - if (c == 0) { - // overlong sequence, use only the first byte - c = (uint8_t)(*p); - l = 1; - } - int uc = upper ? mb_toupper(c) : mb_tolower(c); - - // Reallocate string when byte count changes. This is rare, - // thus it's OK to do another malloc()/free(). - int newl = utf_char2len(uc); - if (newl != l) { - // TODO(philix): use xrealloc() in strcase_save() - char *s = xmalloc(strlen(res) + (size_t)(1 + newl - l)); - memcpy(s, res, (size_t)(p - res)); - STRCPY(s + (p - res) + newl, p + l); - p = s + (p - res); - xfree(res); - res = s; - } - - utf_char2bytes(uc, p); - p += newl; - } - + CharInfo char_info = utf_ptr2CharInfo(p); + int c = char_info.value < 0 ? (uint8_t)(*p) : char_info.value; + int newc = upper ? mb_toupper(c) : mb_tolower(c); + // Cast to size_t to avoid mixing types in arithmetic + size_t newl = (size_t)utf_char2len(newc); + + // Check if there's enough space in the allocated memory + if (res_index + newl > orig_len) { + // Need more space: allocate extra space for the new character and the null terminator + size_t new_size = res_index + newl + 1; + res = xrealloc(res, new_size); + // Adjust the original length to the new size, minus the null terminator + orig_len = new_size - 1; + } + + // Write the possibly new character into the result string + utf_char2bytes(newc, res + res_index); + // Move the index in the result string + res_index += newl; + // Move to the next character in the original string + p += char_info.len; + } + + // Null-terminate the result string + res[res_index] = NUL; return res; } |