From: Matthew Fernandez Date: Sun, 7 Aug 2022 16:31:24 +0000 (-0700) Subject: gvpr toUpper: rewrite to use a single buffer X-Git-Tag: 5.0.1~9^2~7 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cfef851ad1a781ecb3d4fa8b9fa2157c10a54b1a;p=graphviz gvpr toUpper: rewrite to use a single buffer `toUpper` worked by using the GVPR state’s temporary buffer, `tmp`, to incrementally construct an uppercase copy of the input. This works but is suboptimal. When printing to the temporary buffer, it has no knowledge of what we are up to and needs to make heuristic-based decisions on how to allocate memory. But we know the exact size of the result string already. This commit takes advantage of this knowledge and allocates the destination memory upfront and then simply writes directly into it. By doing this, we reduce heap pressure and eliminate an intermediate copying operation. This commit also renames the `s` parameter to something more descriptive. Gitlab: #1873 --- diff --git a/lib/gvpr/actions.c b/lib/gvpr/actions.c index c2c8688bc..c878c5e9e 100644 --- a/lib/gvpr/actions.c +++ b/lib/gvpr/actions.c @@ -782,14 +782,20 @@ char *toLower(Expr_t *pgm, char *src) { /* toUpper: * Convert characters to uppercase */ -char *toUpper(Expr_t * pgm, char *s, Sfio_t* tmps) -{ - int c; +char *toUpper(Expr_t *pgm, char *src) { + + const size_t len = strlen(src); + char *dst = exstralloc(pgm, len + 1); + if (UNLIKELY(dst == NULL)) { + return NULL; + } - while ((c = *s++)) - sfputc (tmps, toupper (c)); + for (size_t i = 0; i < len; ++i) { + dst[i] = (char)toupper((int)src[i]); + } - return exstring(pgm, sfstruse(tmps)); + dst[len] = '\0'; + return dst; } /* toHtml: diff --git a/lib/gvpr/actions.h b/lib/gvpr/actions.h index 98941e632..ed12d2a0f 100644 --- a/lib/gvpr/actions.h +++ b/lib/gvpr/actions.h @@ -43,7 +43,7 @@ extern "C" { extern char *canon(Expr_t * pgm, char *); extern char *toHtml(Agraph_t*, char *); extern char *toLower(Expr_t *pgm, char *src); - extern char *toUpper(Expr_t * pgm, char *, Sfio_t*); + extern char *toUpper(Expr_t *pgm, char *src); extern int deleteObj(Agraph_t * g, Agobj_t * obj); extern char *colorx (Expr_t* ex, char* incolor, char* fmt, Sfio_t* fp); extern void gvstart_timer(void); diff --git a/lib/gvpr/compile.c b/lib/gvpr/compile.c index 62fc8dcfe..13cdb19c5 100644 --- a/lib/gvpr/compile.c +++ b/lib/gvpr/compile.c @@ -1463,7 +1463,7 @@ getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref, v.integer = 0; break; case F_toupper: - v.string = toUpper(pgm, args[0].string, state->tmp); + v.string = toUpper(pgm, args[0].string); break; case F_xof: v.string = xyOf(pgm, args[0].string, true);