about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2010-10-24T20·09+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2010-10-24T20·09+0000
commit43535499f38acc04367eeb4dd0d9938e9f8666f8 (patch)
treee563d03b531d47558c89a66f87e358e6bf8f87e0
parente0b7fb8f2710ec3012afe6b9d2096f770429a389 (diff)
* When allocating an attribute set, reserve enough space for all
  elements.  This prevents the vector from having to resize itself.

-rw-r--r--src/libexpr/eval.cc16
-rw-r--r--src/libexpr/eval.hh4
-rw-r--r--src/libexpr/primops.cc23
-rw-r--r--src/nix-env/user-env.cc6
4 files changed, 21 insertions, 28 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 4aa8fc1e44b5..919ebd4ba9b6 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -340,11 +340,12 @@ void EvalState::mkList(Value & v, unsigned int length)
 }
 
 
-void EvalState::mkAttrs(Value & v)
+void EvalState::mkAttrs(Value & v, unsigned int expected)
 {
     clearValue(v);
     v.type = tAttrs;
     v.attrs = NEW Bindings;
+    v.attrs->reserve(expected);
     nrAttrsets++;
 }
 
@@ -391,13 +392,6 @@ Value * EvalState::maybeThunk(Env & env, Expr * expr)
 }
 
 
-void EvalState::cloneAttrs(Value & src, Value & dst)
-{
-    mkAttrs(dst);
-    *dst.attrs = *src.attrs;
-}
-
-
 void EvalState::evalFile(const Path & path, Value & v)
 {
     startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path);
@@ -504,7 +498,7 @@ void ExprPath::eval(EvalState & state, Env & env, Value & v)
 
 void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
 {
-    state.mkAttrs(v); // !!! reserve size
+    state.mkAttrs(v, attrs.size());
 
     if (recursive) {
         /* Create a new environment that contains the attributes in
@@ -758,7 +752,7 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res)
     }
 
     Value actualArgs;
-    mkAttrs(actualArgs);
+    mkAttrs(actualArgs, fun.lambda.fun->formals->formals.size());
 
     foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) {
         Bindings::iterator j = args.find(i->name);
@@ -852,7 +846,7 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
     if (v1.attrs->size() == 0) { v = v2; return; }
     if (v2.attrs->size() == 0) { v = v1; return; }
 
-    state.mkAttrs(v);
+    state.mkAttrs(v, v1.attrs->size() + v2.attrs->size());
 
     /* Merge the attribute sets, preferring values from the second
        set.  Make sure to keep the resulting vector in sorted
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index 7f801d1125fb..7453ac189197 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -319,13 +319,11 @@ public:
     Value * allocAttr(Value & vAttrs, const Symbol & name);
 
     void mkList(Value & v, unsigned int length);
-    void mkAttrs(Value & v);
+    void mkAttrs(Value & v, unsigned int expected);
     void mkThunk_(Value & v, Expr * expr);
 
     Value * maybeThunk(Env & env, Expr * expr);
     
-    void cloneAttrs(Value & src, Value & dst);
-
     /* Print statistics. */
     void printStats();
 
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 7c713f384f33..a4812de06519 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -206,7 +206,7 @@ static void prim_addErrorContext(EvalState & state, Value * * args, Value & v)
  * else => {success=false; value=false;} */
 static void prim_tryEval(EvalState & state, Value * * args, Value & v)
 {
-    state.mkAttrs(v);
+    state.mkAttrs(v, 2);
     try {
         state.forceValue(*args[0]);
         v.attrs->push_back(Attr(state.symbols.create("value"), args[0]));
@@ -484,7 +484,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
     state.drvHashes[drvPath] = hashDerivationModulo(state, drv);
 
     /* !!! assumes a single output */
-    state.mkAttrs(v);
+    state.mkAttrs(v, 2);
     mkString(*state.allocAttr(v, state.sOutPath), outPath, singleton<PathSet>(drvPath));
     mkString(*state.allocAttr(v, state.sDrvPath), drvPath, singleton<PathSet>("=" + drvPath));
     v.attrs->sort();
@@ -745,7 +745,7 @@ static void prim_removeAttrs(EvalState & state, Value * * args, Value & v)
     /* Copy all attributes not in that set.  Note that we don't need
        to sort v.attrs because it's a subset of an already sorted
        vector. */
-    state.mkAttrs(v);
+    state.mkAttrs(v, args[0]->attrs->size());
     foreach (Bindings::iterator, i, *args[0]->attrs) {
         if (names.find(i->name) == names.end())
             v.attrs->push_back(*i);
@@ -761,7 +761,7 @@ static void prim_listToAttrs(EvalState & state, Value * * args, Value & v)
 {
     state.forceList(*args[0]);
 
-    state.mkAttrs(v);
+    state.mkAttrs(v, args[0]->list.length);
 
     std::set<Symbol> seen;
 
@@ -798,7 +798,7 @@ static void prim_intersectAttrs(EvalState & state, Value * * args, Value & v)
     state.forceAttrs(*args[0]);
     state.forceAttrs(*args[1]);
         
-    state.mkAttrs(v);
+    state.mkAttrs(v, std::min(args[0]->attrs->size(), args[1]->attrs->size()));
 
     foreach (Bindings::iterator, i, *args[0]->attrs) {
         Bindings::iterator j = args[1]->attrs->find(i->name);
@@ -827,14 +827,15 @@ static void prim_functionArgs(EvalState & state, Value * * args, Value & v)
     if (args[0]->type != tLambda)
         throw TypeError("`functionArgs' requires a function");
 
-    state.mkAttrs(v);
-
-    if (!args[0]->lambda.fun->matchAttrs) return;
+    if (!args[0]->lambda.fun->matchAttrs) {
+        state.mkAttrs(v, 0);
+        return;
+    }
 
+    state.mkAttrs(v, args[0]->lambda.fun->formals->formals.size());
     foreach (Formals::Formals_::iterator, i, args[0]->lambda.fun->formals->formals)
         // !!! should optimise booleans (allocate only once)
         mkBool(*state.allocAttr(v, i->name), i->def);
-
     v.attrs->sort();
 }
 
@@ -1015,7 +1016,7 @@ static void prim_parseDrvName(EvalState & state, Value * * args, Value & v)
 {
     string name = state.forceStringNoCtx(*args[0]);
     DrvName parsed(name);
-    state.mkAttrs(v);
+    state.mkAttrs(v, 2);
     mkString(*state.allocAttr(v, state.sName), parsed.name);
     mkString(*state.allocAttr(v, state.symbols.create("version")), parsed.version);
     v.attrs->sort();
@@ -1043,7 +1044,7 @@ void EvalState::createBaseEnv()
     Value v;
 
     /* `builtins' must be first! */
-    mkAttrs(v);
+    mkAttrs(v, 128);
     addConstant("builtins", v);
 
     mkBool(v, true);
diff --git a/src/nix-env/user-env.cc b/src/nix-env/user-env.cc
index acd866197c7c..865d24e2f919 100644
--- a/src/nix-env/user-env.cc
+++ b/src/nix-env/user-env.cc
@@ -61,7 +61,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
 
         Value & v(*state.allocValue());
         manifest.list.elems[n++] = &v;
-        state.mkAttrs(v);
+        state.mkAttrs(v, 8);
 
         mkString(*state.allocAttr(v, state.sType), "derivation");
         mkString(*state.allocAttr(v, state.sName), i->name);
@@ -71,7 +71,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
             mkString(*state.allocAttr(v, state.sDrvPath), i->queryDrvPath(state));
 
         Value & vMeta = *state.allocAttr(v, state.sMeta);
-        state.mkAttrs(vMeta);
+        state.mkAttrs(vMeta, 16);
 
         MetaInfo meta = i->queryMetaInfo(state);
 
@@ -118,7 +118,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
     /* Construct a Nix expression that calls the user environment
        builder with the manifest as argument. */
     Value args, topLevel;
-    state.mkAttrs(args);
+    state.mkAttrs(args, 3);
     mkString(*state.allocAttr(args, state.sSystem), thisSystem);
     mkString(*state.allocAttr(args, state.symbols.create("manifest")),
         manifestFile, singleton<PathSet>(manifestFile));