[git commit] hush: optimize ${var/pattern/repl} for trivial patterns

Denys Vlasenko vda.linux at googlemail.com
Tue Jul 27 15:53:55 UTC 2021


commit: https://git.busybox.net/busybox/commit/?id=49cc3cac30c504abdbd2c075928f5711da4066e8
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

function                                             old     new   delta
expand_one_var                                      2353    2507    +154

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 shell/hush.c  | 13 +++++++++++++
 shell/match.c |  3 +--
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/shell/hush.c b/shell/hush.c
index 6b910569f..179155f66 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -6466,6 +6466,19 @@ static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p)
 /* ${var/[/]pattern[/repl]} helpers */
 static char *strstr_pattern(char *val, const char *pattern, int *size)
 {
+	if (!strpbrk(pattern, "*?[\\")) {
+		/* Optimization for trivial patterns.
+		 * Testcase for very slow replace (performs about 22k replaces):
+		 * x=::::::::::::::::::::::
+		 * x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;echo ${#x}
+		 * echo "${x//:/|}"
+		 */
+		char *found = strstr(val, pattern);
+		if (found)
+			*size = strlen(pattern);
+		return found;
+	}
+
 	while (1) {
 		char *end = scan_and_match(val, pattern, SCAN_MOVE_FROM_RIGHT + SCAN_MATCH_LEFT_HALF);
 		debug_printf_varexp("val:'%s' pattern:'%s' end:'%s'\n", val, pattern, end);
diff --git a/shell/match.c b/shell/match.c
index ee8abb2db..90f77546d 100644
--- a/shell/match.c
+++ b/shell/match.c
@@ -64,11 +64,10 @@ char* FAST_FUNC scan_and_match(char *string, const char *pattern, unsigned flags
 	}
 
 	while (loc != end) {
-		char c;
 		int r;
 
-		c = *loc;
 		if (flags & SCAN_MATCH_LEFT_HALF) {
+			char c = *loc;
 			*loc = '\0';
 			r = fnmatch(pattern, string, 0);
 			//bb_error_msg("fnmatch('%s','%s',0):%d", pattern, string, r);


More information about the busybox-cvs mailing list