aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libexpr/eval.cc29
-rw-r--r--src/libexpr/eval.hh2
-rw-r--r--src/libexpr/primops.cc10
3 files changed, 33 insertions, 8 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 871dfa64c..5351ca0c3 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -912,16 +912,29 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v)
{
- state.nrListConcats++;
Value v1; e1->eval(state, env, v1);
- state.forceList(v1);
Value v2; e2->eval(state, env, v2);
- state.forceList(v2);
- state.mkList(v, v1.list.length + v2.list.length);
- for (unsigned int n = 0; n < v1.list.length; ++n)
- v.list.elems[n] = v1.list.elems[n];
- for (unsigned int n = 0; n < v2.list.length; ++n)
- v.list.elems[n + v1.list.length] = v2.list.elems[n];
+ Value * lists[2] = { &v1, &v2 };
+ state.concatLists(v, 2, lists);
+}
+
+
+void EvalState::concatLists(Value & v, unsigned int nrLists, Value * * lists)
+{
+ nrListConcats++;
+
+ unsigned int len = 0;
+ for (unsigned int n = 0; n < nrLists; ++n) {
+ forceList(*lists[n]);
+ len += lists[n]->list.length;
+ }
+
+ mkList(v, len);
+ 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 *));
+ pos += l;
+ }
}
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index 4e66c4dfc..a1f26a056 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -232,6 +232,8 @@ public:
void mkAttrs(Value & v, unsigned int expected);
void mkThunk_(Value & v, Expr * expr);
+ void concatLists(Value & v, unsigned int nrLists, Value * * lists);
+
/* Print statistics. */
void printStats();
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index aa27df6ad..f5c004044 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -931,6 +931,7 @@ static void prim_filter(EvalState & state, Value * * args, Value & v)
}
+/* Return true if a list contains a given element. */
static void prim_elem(EvalState & state, Value * * args, Value & v)
{
bool res = false;
@@ -944,6 +945,14 @@ static void prim_elem(EvalState & state, Value * * args, Value & v)
}
+/* Concatenate a list of lists. */
+static void prim_concatLists(EvalState & state, Value * * args, Value & v)
+{
+ state.forceList(*args[0]);
+ state.concatLists(v, args[0]->list.length, args[0]->list.elems);
+}
+
+
/* Return the length of a list. This is an O(1) time operation. */
static void prim_length(EvalState & state, Value * * args, Value & v)
{
@@ -1160,6 +1169,7 @@ void EvalState::createBaseEnv()
addPrimOp("map", 2, prim_map);
addPrimOp("__filter", 2, prim_filter);
addPrimOp("__elem", 2, prim_elem);
+ addPrimOp("__concatLists", 1, prim_concatLists);
addPrimOp("__length", 1, prim_length);
// Integer arithmetic