@@ -2021,35 +2021,14 @@ void EvalState::concatLists(
20212021void ExprConcatStrings::eval (EvalState & state, Env & env, Value & v)
20222022{
20232023 NixStringContext context;
2024- std::vector<BackedStringView> s ;
2024+ std::vector<BackedStringView> strings ;
20252025 size_t sSize = 0 ;
20262026 NixInt n{0 };
20272027 NixFloat nf = 0 ;
20282028
20292029 bool first = !forceString;
20302030 ValueType firstType = nString;
20312031
2032- const auto str = [&] {
2033- std::string result;
2034- result.reserve (sSize );
2035- for (const auto & part : s)
2036- result += *part;
2037- return result;
2038- };
2039- /* c_str() is not str().c_str() because we want to create a string
2040- Value. allocating a GC'd string directly and moving it into a
2041- Value lets us avoid an allocation and copy. */
2042- const auto c_str = [&] {
2043- char * result = allocString (sSize + 1 );
2044- char * tmp = result;
2045- for (const auto & part : s) {
2046- memcpy (tmp, part->data (), part->size ());
2047- tmp += part->size ();
2048- }
2049- *tmp = 0 ;
2050- return result;
2051- };
2052-
20532032 // List of returned strings. References to these Values must NOT be persisted.
20542033 SmallTemporaryValueVector<conservativeStackReservation> values (es.size ());
20552034 Value * vTmpP = values.data ();
@@ -2097,33 +2076,46 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
20972076 .withFrame (env, *this )
20982077 .debugThrow ();
20992078 } else {
2100- if (s .empty ())
2101- s .reserve (es.size ());
2079+ if (strings .empty ())
2080+ strings .reserve (es.size ());
21022081 /* skip canonization of first path, which would only be not
21032082 canonized in the first place if it's coming from a ./${foo} type
21042083 path */
21052084 auto part = state.coerceToString (
21062085 i_pos, vTmp, context, " while evaluating a path segment" , false , firstType == nString, !first);
21072086 sSize += part->size ();
2108- s .emplace_back (std::move (part));
2087+ strings .emplace_back (std::move (part));
21092088 }
21102089
21112090 first = false ;
21122091 }
21132092
2114- if (firstType == nInt)
2093+ if (firstType == nInt) {
21152094 v.mkInt (n);
2116- else if (firstType == nFloat)
2095+ } else if (firstType == nFloat) {
21172096 v.mkFloat (nf);
2118- else if (firstType == nPath) {
2097+ } else if (firstType == nPath) {
21192098 if (!context.empty ())
21202099 state.error <EvalError>(" a string that refers to a store path cannot be appended to a path" )
21212100 .atPos (pos)
21222101 .withFrame (env, *this )
21232102 .debugThrow ();
2124- v.mkPath (state.rootPath (CanonPath (str ())));
2125- } else
2126- v.mkStringMove (c_str (), context);
2103+ std::string result_str;
2104+ result_str.reserve (sSize );
2105+ for (const auto & part : strings) {
2106+ result_str += *part;
2107+ }
2108+ v.mkPath (state.rootPath (CanonPath (result_str)));
2109+ } else {
2110+ char * result_str = allocString (sSize + 1 );
2111+ char * tmp = result_str;
2112+ for (const auto & part : strings) {
2113+ memcpy (tmp, part->data (), part->size ());
2114+ tmp += part->size ();
2115+ }
2116+ *tmp = 0 ;
2117+ v.mkStringMove (result_str, context);
2118+ }
21272119}
21282120
21292121void ExprPos::eval (EvalState & state, Env & env, Value & v)
0 commit comments