refactor: avoid quadratic behavior in backslash_halve() (#27827)

The original implementation has a worst-case of O(n^2). Every time
rem_backslash() is true, it calculates the length of the rest of the
string, and shift the rest of it to the left; backslash_halve_save()
copies the original string before doing backslash_halve().

The new implementation is O(n). It will find the first character where
rem_backslash() is true (it will do nothing if it's always false), and
shift the characters in-place; backslash_halve_save() avoids copying the
original string before doing backslash_halve().
This commit is contained in:
James
2024-03-12 13:35:53 +07:00
committed by GitHub
parent a74e869ffa
commit 3bd84317fb

View File

@@ -1457,11 +1457,21 @@ bool rem_backslash(const char *str)
/// @param p /// @param p
void backslash_halve(char *p) void backslash_halve(char *p)
{ {
for (; *p; p++) { for (; *p && !rem_backslash(p); p++) {}
if (*p != NUL) {
char *dst = p;
goto start;
while (*p != NUL) {
if (rem_backslash(p)) { if (rem_backslash(p)) {
STRMOVE(p, p + 1); start:
*dst++ = *(p + 1);
p += 2;
} else {
*dst++ = *p++;
} }
} }
*dst = '\0';
}
} }
/// backslash_halve() plus save the result in allocated memory. /// backslash_halve() plus save the result in allocated memory.
@@ -1472,8 +1482,16 @@ void backslash_halve(char *p)
char *backslash_halve_save(const char *p) char *backslash_halve_save(const char *p)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
{ {
// TODO(philix): simplify and improve backslash_halve_save algorithm char *res = xmalloc(strlen(p) + 1);
char *res = xstrdup(p); char *dst = res;
backslash_halve(res); while (*p != NUL) {
if (rem_backslash(p)) {
*dst++ = *(p + 1);
p += 2;
} else {
*dst++ = *p++;
}
}
*dst = '\0';
return res; return res;
} }