aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/strings.c
diff options
context:
space:
mode:
authorRaphael <glephunter@gmail.com>2024-02-03 15:29:05 +0800
committerGitHub <noreply@github.com>2024-02-03 15:29:05 +0800
commit51702e0aea99fddba74e299e2640dd350a348df3 (patch)
tree6ae4b0d9b21813a6bde6fb53ead43468ed92da77 /src/nvim/strings.c
parent6709f7f8f130377f44c36b2150a167a2afcbdff9 (diff)
downloadrneovim-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.c61
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;
}