Skip to content

Commit f0285cc

Browse files
committed
Improve performance of repeating strings
This commit improves the performance of repeating strings, by copying the result string instead of the string being repeated. Also it adds an error message when the result string is too long.
1 parent 8ba03f7 commit f0285cc

File tree

4 files changed

+41
-13
lines changed

4 files changed

+41
-13
lines changed

src/builtin.c

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -340,21 +340,10 @@ jv binop_multiply(jv a, jv b) {
340340
str = b;
341341
num = a;
342342
}
343-
jv res;
344343
double d = jv_number_value(num);
345-
if (d < 0 || isnan(d)) {
346-
res = jv_null();
347-
} else {
348-
int n = d;
349-
size_t alen = jv_string_length_bytes(jv_copy(str));
350-
res = jv_string_empty(alen * n);
351-
for (; n > 0; n--) {
352-
res = jv_string_append_buf(res, jv_string_value(str), alen);
353-
}
354-
}
355-
jv_free(str);
356344
jv_free(num);
357-
return res;
345+
return jv_string_repeat(str,
346+
d < 0 || isnan(d) ? -1 : d > INT_MAX ? INT_MAX : (int)d);
358347
} else if (ak == JV_KIND_OBJECT && bk == JV_KIND_OBJECT) {
359348
return jv_object_merge_recursive(a, b);
360349
} else {

src/jv.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1309,6 +1309,32 @@ jv jv_string_indexes(jv j, jv k) {
13091309
return a;
13101310
}
13111311

1312+
jv jv_string_repeat(jv j, int n) {
1313+
assert(JVP_HAS_KIND(j, JV_KIND_STRING));
1314+
if (n < 0) {
1315+
jv_free(j);
1316+
return jv_null();
1317+
}
1318+
int len = jv_string_length_bytes(jv_copy(j));
1319+
int64_t res_len = (int64_t)len * n;
1320+
if (res_len > INT_MAX) {
1321+
jv_free(j);
1322+
return jv_invalid_with_msg(jv_string("Repeat string result too long"));
1323+
}
1324+
if (res_len == 0) {
1325+
jv_free(j);
1326+
return jv_string("");
1327+
}
1328+
jv res = jv_string_empty(res_len);
1329+
res = jvp_string_append(res, jv_string_value(j), len);
1330+
for (int curr = len, grow; curr < res_len; curr += grow) {
1331+
grow = MIN(res_len - curr, curr);
1332+
res = jvp_string_append(res, jv_string_value(res), grow);
1333+
}
1334+
jv_free(j);
1335+
return res;
1336+
}
1337+
13121338
jv jv_string_split(jv j, jv sep) {
13131339
assert(JVP_HAS_KIND(j, JV_KIND_STRING));
13141340
assert(JVP_HAS_KIND(sep, JV_KIND_STRING));

src/jv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ jv jv_string_fmt(const char*, ...) JV_PRINTF_LIKE(1, 2);
135135
jv jv_string_append_codepoint(jv a, uint32_t c);
136136
jv jv_string_append_buf(jv a, const char* buf, int len);
137137
jv jv_string_append_str(jv a, const char* str);
138+
jv jv_string_repeat(jv j, int n);
138139
jv jv_string_split(jv j, jv sep);
139140
jv jv_string_explode(jv j);
140141
jv jv_string_implode(jv j);

tests/jq.test

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1460,6 +1460,18 @@ indices("o")
14601460
"abc"
14611461
[null,null]
14621462

1463+
. * 100000 | [.[:10],.[-10:]]
1464+
"abc"
1465+
["abcabcabca","cabcabcabc"]
1466+
1467+
. * 1000000000
1468+
""
1469+
""
1470+
1471+
try (. * 1000000000) catch .
1472+
"abc"
1473+
"Repeat string result too long"
1474+
14631475
[.[] / ","]
14641476
["a, bc, def, ghij, jklmn, a,b, c,d, e,f", "a,b,c,d, e,f,g,h"]
14651477
[["a"," bc"," def"," ghij"," jklmn"," a","b"," c","d"," e","f"],["a","b","c","d"," e","f","g","h"]]

0 commit comments

Comments
 (0)