1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-07-06 09:11:47 +02:00

Add a ListBuilder helper for constructing list values

Previously, `state.mkList()` would set the type of the value to tList
and allocate the list vector, but it would not initialize the values
in the list. This has two problems:

* If an exception occurs, the list is left in an undefined state.

* More importantly, for multithreaded evaluation, if a value
  transitions from thunk to non-thunk, it should be final (i.e. other
  threads should be able to access the value safely).

To address this, there now is a `ListBuilder` class (analogous to
`BindingsBuilder`) to build the list vector prior to the call to
`Value::mkList()`. Typical usage:

   auto list = state.buildList(size);
   for (auto & v : list)
       v = ... set value ...;
   vRes.mkList(list);
This commit is contained in:
Eelco Dolstra 2024-03-14 19:10:31 +01:00
parent bff5c94184
commit fecff520d7
10 changed files with 228 additions and 157 deletions

View file

@ -18,6 +18,7 @@
namespace nix {
struct Value;
class BindingsBuilder;
@ -134,6 +135,34 @@ class ExternalValueBase
std::ostream & operator << (std::ostream & str, const ExternalValueBase & v);
class ListBuilder
{
const size_t size;
Value * inlineElems[2] = {nullptr, nullptr};
public:
Value * * elems;
ListBuilder(EvalState & state, size_t size);
ListBuilder(ListBuilder && x)
: size(x.size)
, inlineElems{x.inlineElems[0], x.inlineElems[1]}
, elems(size <= 2 ? inlineElems : x.elems)
{ }
Value * & operator [](size_t n)
{
return elems[n];
}
typedef Value * * iterator;
iterator begin() { return &elems[0]; }
iterator end() { return &elems[size]; }
friend class Value;
};
struct Value
{
private:
@ -323,16 +352,20 @@ public:
Value & mkAttrs(BindingsBuilder & bindings);
inline void mkList(size_t size)
void mkList(const ListBuilder & builder)
{
clearValue();
if (size == 1)
if (builder.size == 1) {
smallList[0] = builder.inlineElems[0];
internalType = tList1;
else if (size == 2)
} else if (builder.size == 2) {
smallList[0] = builder.inlineElems[0];
smallList[1] = builder.inlineElems[1];
internalType = tList2;
else {
} else {
bigList.size = builder.size;
bigList.elems = builder.elems;
internalType = tListN;
bigList.size = size;
}
}