Files
lix/lix/libexpr/attr-set.cc
T
eldritch horrors 80654b84b6 libexpr: de-ptr-ize Value references
thunk values are shareable, and we can represent invalid/uninitialized
values with a special bit pattern that makes no sense otherwise. there
is no need to keep allocating values on the heap, instead we can treat
values like reference-counted smart pointers to heap objects, which in
turn lets us save a lot of allocations and, ultimately, gc heap space.

compared to our baseline (main of 2025-09-27) we save 15%+ memory on a
system rebuild and 17% on nix search. eval time regresses by ~3% for a
system rebuild, while nix search is 7% faster. further optimization is
probably possible (but for now this will just have to be good enough).

Change-Id: Ib6c47acdbe2fac4f76a83c2269f16f30ef66b2e1
2025-10-05 16:23:05 +02:00

54 lines
1.1 KiB
C++

#include "lix/libexpr/attr-set.hh"
#include "lix/libexpr/eval.hh"
#include "lix/libexpr/gc-alloc.hh"
#include <algorithm>
namespace nix {
Bindings Bindings::EMPTY{};
/* Allocate a new array of attributes for an attribute set with a specific
capacity. The space is implicitly reserved after the Bindings
structure. */
Bindings * EvalMemory::allocBindings(size_t capacity)
{
if (capacity == 0)
return &Bindings::EMPTY;
if (capacity > std::numeric_limits<Bindings::Size>::max())
throw Error("attribute set of size %d is too big", capacity);
stats.nrAttrsets++;
stats.nrAttrsInAttrsets += capacity;
return new (allocBytes(sizeof(Bindings) + sizeof(Attr) * capacity)) Bindings();
}
Value & BindingsBuilder::alloc(Symbol name, PosIdx pos)
{
bindings->push_back(Attr(name, {}, pos));
return (bindings->end() - 1)->value;
}
Value & BindingsBuilder::alloc(std::string_view name, PosIdx pos)
{
return alloc(symbols.create(name), pos);
}
void Bindings::sort()
{
if (size_) std::sort(begin(), end());
}
Value & Value::mkAttrs(BindingsBuilder & bindings)
{
mkAttrs(bindings.finish());
return *this;
}
}