From 03cd353398555353a124de2e867a038bcc7a34d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20Hamb=C3=BCchen?= Date: Tue, 18 Aug 2020 03:41:27 +0200 Subject: [PATCH] builtins.concatStringsSep: Guarantee amortised O(n) --- src/libexpr/primops.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 3955287b7e44..e1a16c198c08 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -2111,12 +2111,18 @@ static void prim_concatStringSep(EvalState & state, const Pos & pos, Value * * a state.forceList(*args[1], pos); string res; - res.reserve((args[1]->listSize() + 32) * sep.size()); + res.reserve((args[1]->listSize() + 32) * sep.size()); // guess bool first = true; for (unsigned int n = 0; n < args[1]->listSize(); ++n) { if (first) first = false; else res += sep; - res += state.coerceToString(pos, *args[1]->listElems()[n], context); + string s = state.coerceToString(pos, *args[1]->listElems()[n], context); + // Exponential growth for amortised overall linear append. + if (res.capacity() < res.size() + s.length()) { + size_t add = std::max(s.length(), (size_t) (0.5 * res.capacity())); + res.reserve(res.capacity() + add); + } + res += s; } mkString(v, res, context);