From f4dee1869326bc6e2e0bab8d4bfa0bff4392b00c Mon Sep 17 00:00:00 2001 From: eldritch horrors Date: Sun, 28 Sep 2025 00:02:21 +0200 Subject: [PATCH] libexpr: remove type punning in primt_attrValues there's no measurable performance gain in real-world testing to abusing our list value storage like this. we haven't tested how much storage we actually need on the stack to offset most of the temporary storage cost and used 128 as a "good enough" value instead, reserving 1 kiB of stack space on 64 bit platforms in a leaf function. this should do for a bit. Change-Id: Ie98519b1da3e6fe685da88d1c44ffb4580fb592a --- lix/libexpr/primops.cc | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/lix/libexpr/primops.cc b/lix/libexpr/primops.cc index fc1aed5ba..f298c36df 100644 --- a/lix/libexpr/primops.cc +++ b/lix/libexpr/primops.cc @@ -1666,21 +1666,20 @@ static void prim_attrValues(EvalState & state, Value * * args, Value & v) auto result = state.ctx.mem.newList(args[0]->attrs()->size()); v = {NewValueAs::list, result}; - // FIXME: this is incredibly evil, *why* - // NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast) - unsigned int n = 0; - for (auto & i : *args[0]->attrs()) - result->elems[n++] = (Value *) &i; + boost::container::small_vector tmp; + tmp.reserve(args[0]->attrs()->size()); - std::sort(result->elems, result->elems + n, [&](Value * v1, Value * v2) { - std::string_view s1 = state.ctx.symbols[((Attr *) v1)->name], - s2 = state.ctx.symbols[((Attr *) v2)->name]; + for (auto & i : *args[0]->attrs()) + tmp.push_back(&i); + + std::sort(tmp.begin(), tmp.end(), [&](const Attr * v1, const Attr * v2) { + std::string_view s1 = state.ctx.symbols[v1->name], s2 = state.ctx.symbols[v2->name]; return s1 < s2; }); - for (unsigned int i = 0; i < n; ++i) - result->elems[i] = ((Attr *) result->elems[i])->value; - // NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast) + for (auto [i, attr] : enumerate(tmp)) { + result->elems[i] = attr->value; + } } /* Dynamic version of the `.' operator. */