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

Optimize small lists

The value pointers of lists with 1 or 2 elements are now stored in the
list value itself. In particular, this makes the "concatMap (x: if
cond then [(f x)] else [])" idiom cheaper.
This commit is contained in:
Eelco Dolstra 2015-07-23 22:05:09 +02:00
parent 14be783676
commit b83801f8b3
11 changed files with 157 additions and 121 deletions

View file

@ -108,10 +108,12 @@ static void printValue(std::ostream & str, std::set<const Value *> & active, con
str << "}";
break;
}
case tList:
case tList1:
case tList2:
case tListN:
str << "[ ";
for (unsigned int n = 0; n < v.list.length; ++n) {
printValue(str, active, *v.list.elems[n]);
for (unsigned int n = 0; n < v.listSize(); ++n) {
printValue(str, active, *v.listElems()[n]);
str << " ";
}
str << "]";
@ -157,7 +159,7 @@ string showType(const Value & v)
case tPath: return "a path";
case tNull: return "null";
case tAttrs: return "a set";
case tList: return "a list";
case tList1: case tList2: case tListN: return "a list";
case tThunk: return "a thunk";
case tApp: return "a function application";
case tLambda: return "a function";
@ -519,13 +521,19 @@ Bindings * EvalState::allocBindings(Bindings::size_t capacity)
}
void EvalState::mkList(Value & v, unsigned int length)
void EvalState::mkList(Value & v, unsigned int size)
{
clearValue(v);
v.type = tList;
v.list.length = length;
v.list.elems = length ? (Value * *) allocBytes(length * sizeof(Value *)) : 0;
nrListElems += length;
if (size == 1)
v.type = tList1;
else if (size == 2)
v.type = tList2;
else {
v.type = tListN;
v.bigList.size = size;
v.bigList.elems = size ? (Value * *) allocBytes(size * sizeof(Value *)) : 0;
}
nrListElems += size;
}
@ -807,8 +815,8 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v)
void ExprList::eval(EvalState & state, Env & env, Value & v)
{
state.mkList(v, elems.size());
for (unsigned int n = 0; n < v.list.length; ++n)
v.list.elems[n] = elems[n]->maybeThunk(state, env);
for (unsigned int n = 0; n < elems.size(); ++n)
v.listElems()[n] = elems[n]->maybeThunk(state, env);
}
@ -1201,20 +1209,21 @@ void EvalState::concatLists(Value & v, unsigned int nrLists, Value * * lists, co
unsigned int len = 0;
for (unsigned int n = 0; n < nrLists; ++n) {
forceList(*lists[n], pos);
unsigned int l = lists[n]->list.length;
unsigned int l = lists[n]->listSize();
len += l;
if (l) nonEmpty = lists[n];
}
if (nonEmpty && len == nonEmpty->list.length) {
if (nonEmpty && len == nonEmpty->listSize()) {
v = *nonEmpty;
return;
}
mkList(v, len);
auto out = v.listElems();
for (unsigned int n = 0, pos = 0; n < nrLists; ++n) {
unsigned int l = lists[n]->list.length;
memcpy(v.list.elems + pos, lists[n]->list.elems, l * sizeof(Value *));
unsigned int l = lists[n]->listSize();
memcpy(out + pos, lists[n]->listElems(), l * sizeof(Value *));
pos += l;
}
}
@ -1290,9 +1299,9 @@ void EvalState::forceValueDeep(Value & v)
}
}
else if (v.type == tList) {
for (unsigned int n = 0; n < v.list.length; ++n)
recurse(*v.list.elems[n]);
else if (v.isList()) {
for (unsigned int n = 0; n < v.listSize(); ++n)
recurse(*v.listElems()[n]);
}
};
@ -1416,14 +1425,14 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
if (v.type == tInt) return int2String(v.integer);
if (v.type == tNull) return "";
if (v.type == tList) {
if (v.isList()) {
string result;
for (unsigned int n = 0; n < v.list.length; ++n) {
result += coerceToString(pos, *v.list.elems[n],
for (unsigned int n = 0; n < v.listSize(); ++n) {
result += coerceToString(pos, *v.listElems()[n],
context, coerceMore, copyToStore);
if (n < v.list.length - 1
if (n < v.listSize() - 1
/* !!! not quite correct */
&& (v.list.elems[n]->type != tList || v.list.elems[n]->list.length != 0))
&& (!v.listElems()[n]->isList() || v.listElems()[n]->listSize() != 0))
result += " ";
}
return result;
@ -1494,10 +1503,12 @@ bool EvalState::eqValues(Value & v1, Value & v2)
case tNull:
return true;
case tList:
if (v1.list.length != v2.list.length) return false;
for (unsigned int n = 0; n < v1.list.length; ++n)
if (!eqValues(*v1.list.elems[n], *v2.list.elems[n])) return false;
case tList1:
case tList2:
case tListN:
if (v1.listSize() != v2.listSize()) return false;
for (unsigned int n = 0; n < v1.listSize(); ++n)
if (!eqValues(*v1.listElems()[n], *v2.listElems()[n])) return false;
return true;
case tAttrs: {
@ -1645,12 +1656,14 @@ size_t valueSize(Value & v)
sz += doValue(*i.value);
}
break;
case tList:
if (seen.find(v.list.elems) == seen.end()) {
seen.insert(v.list.elems);
sz += v.list.length * sizeof(Value *);
for (unsigned int n = 0; n < v.list.length; ++n)
sz += doValue(*v.list.elems[n]);
case tList1:
case tList2:
case tListN:
if (seen.find(v.listElems()) == seen.end()) {
seen.insert(v.listElems());
sz += v.listSize() * sizeof(Value *);
for (unsigned int n = 0; n < v.listSize(); ++n)
sz += doValue(*v.listElems()[n]);
}
break;
case tThunk: