Skip to content

Commit dc849e9

Browse files
authored
Improve performance of repeating strings (#3272)
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 5df471f commit dc849e9

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
@@ -343,21 +343,10 @@ jv binop_multiply(jv a, jv b) {
343343
str = b;
344344
num = a;
345345
}
346-
jv res;
347346
double d = jv_number_value(num);
348-
if (d < 0 || isnan(d)) {
349-
res = jv_null();
350-
} else {
351-
int n = d;
352-
size_t alen = jv_string_length_bytes(jv_copy(str));
353-
res = jv_string_empty(alen * n);
354-
for (; n > 0; n--) {
355-
res = jv_string_append_buf(res, jv_string_value(str), alen);
356-
}
357-
}
358-
jv_free(str);
359347
jv_free(num);
360-
return res;
348+
return jv_string_repeat(str,
349+
d < 0 || isnan(d) ? -1 : d > INT_MAX ? INT_MAX : (int)d);
361350
} else if (ak == JV_KIND_OBJECT && bk == JV_KIND_OBJECT) {
362351
return jv_object_merge_recursive(a, b);
363352
} else {

src/jv.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1324,6 +1324,32 @@ jv jv_string_indexes(jv j, jv k) {
13241324
return a;
13251325
}
13261326

1327+
jv jv_string_repeat(jv j, int n) {
1328+
assert(JVP_HAS_KIND(j, JV_KIND_STRING));
1329+
if (n < 0) {
1330+
jv_free(j);
1331+
return jv_null();
1332+
}
1333+
int len = jv_string_length_bytes(jv_copy(j));
1334+
int64_t res_len = (int64_t)len * n;
1335+
if (res_len >= INT_MAX) {
1336+
jv_free(j);
1337+
return jv_invalid_with_msg(jv_string("Repeat string result too long"));
1338+
}
1339+
if (res_len == 0) {
1340+
jv_free(j);
1341+
return jv_string("");
1342+
}
1343+
jv res = jv_string_empty(res_len);
1344+
res = jvp_string_append(res, jv_string_value(j), len);
1345+
for (int curr = len, grow; curr < res_len; curr += grow) {
1346+
grow = MIN(res_len - curr, curr);
1347+
res = jvp_string_append(res, jv_string_value(res), grow);
1348+
}
1349+
jv_free(j);
1350+
return res;
1351+
}
1352+
13271353
jv jv_string_split(jv j, jv sep) {
13281354
assert(JVP_HAS_KIND(j, JV_KIND_STRING));
13291355
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
@@ -136,6 +136,7 @@ jv jv_string_fmt(const char*, ...) JV_PRINTF_LIKE(1, 2);
136136
jv jv_string_append_codepoint(jv a, uint32_t c);
137137
jv jv_string_append_buf(jv a, const char* buf, int len);
138138
jv jv_string_append_str(jv a, const char* str);
139+
jv jv_string_repeat(jv j, int n);
139140
jv jv_string_split(jv j, jv sep);
140141
jv jv_string_explode(jv j);
141142
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)