string repeat: Don't allocate repeated string all at once (#9124)

* string repeat: Don't allocate repeated string all at once

This used to allocate one string and fill it with the necessary
repetitions, which could be a very very large string.

Now, it instead uses one buffer and fills it to a chunk size,
and then writes that.

This fixes:

1. We no longer crash with too large max/count values. Before they
caused a bad_alloc because we tried to fill all RAM.
2. We no longer fill all RAM if given a big-but-not-too-big value. You
could've caused fish to eat *most* of your RAM here.
3. It can start writing almost immediately, instead of waiting
potentially minutes to start.

Performance is about the same to slightly faster overall.
This commit is contained in:
Fabian Boehm
2022-08-09 19:58:56 +02:00
committed by GitHub
parent 6128b58be6
commit eac808a819
2 changed files with 92 additions and 37 deletions

View File

@@ -504,6 +504,32 @@ string repeat -n3 ""
or echo string repeat empty string failed
# CHECK: string repeat empty string failed
# See that we hit the expected length
# First with "max", i.e. maximum number of characters
string repeat -m 5000 aab | string length
# CHECK: 5000
string repeat -m 5000 ab | string length
# CHECK: 5000
string repeat -m 5000 a | string length
# CHECK: 5000
string repeat -m 17 aab | string length
# CHECK: 17
string repeat -m 17 ab | string length
# CHECK: 17
string repeat -m 17 a | string length
# CHECK: 17
# Then with "count", i.e. number of repetitions.
# (these are count * length long)
string repeat -n 17 aab | string length
# CHECK: 51
string repeat -n 17 ab | string length
# CHECK: 34
string repeat -n 17 a | string length
# CHECK: 17
# And a more tricksy case with a long string that we truncate.
string repeat -m 5 (string repeat -n 500000 aaaaaaaaaaaaaaaaaa) | string length
# CHECK: 5
# Test equivalent matches with/without the --entire, --regex, and --invert flags.
string match -e x abc dxf xyz jkx x z
or echo exit 1