about summary refs log tree commit diff
path: root/third_party/nix/src
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/nix/src')
-rw-r--r--third_party/nix/src/libexpr/attr-set.cc8
-rw-r--r--third_party/nix/src/libexpr/attr-set.hh3
-rw-r--r--third_party/nix/src/libexpr/eval.cc25
3 files changed, 14 insertions, 22 deletions
diff --git a/third_party/nix/src/libexpr/attr-set.cc b/third_party/nix/src/libexpr/attr-set.cc
index 8b2af8639eff..e0fac9234b14 100644
--- a/third_party/nix/src/libexpr/attr-set.cc
+++ b/third_party/nix/src/libexpr/attr-set.cc
@@ -37,6 +37,14 @@ Bindings::iterator Bindings::find(const Symbol& name) {
 Bindings::iterator Bindings::begin() { return &(attributes_.begin()->second); }
 
 Bindings::iterator Bindings::end() { return &(attributes_.end()->second); }
+void Bindings::merge(Bindings* other) {
+  // We want the values from the other attribute set to take
+  // precedence, but .merge() works the other way around.
+  //
+  // To work around that, we merge and then swap.
+  other->attributes_.merge(attributes_);
+  attributes_.swap(other->attributes_);
+}
 
 // /* Allocate a new array of attributes for an attribute set with a specific
 //    capacity. The space is implicitly reserved after the Bindings structure.
diff --git a/third_party/nix/src/libexpr/attr-set.hh b/third_party/nix/src/libexpr/attr-set.hh
index 551cddaae4eb..39af7c482eab 100644
--- a/third_party/nix/src/libexpr/attr-set.hh
+++ b/third_party/nix/src/libexpr/attr-set.hh
@@ -50,6 +50,9 @@ class Bindings {
   iterator begin();
   iterator end();
 
+  // Merge values from other into the current attribute
+  void merge(Bindings* other);
+
   // ???
   [[deprecated]] void sort();
 
diff --git a/third_party/nix/src/libexpr/eval.cc b/third_party/nix/src/libexpr/eval.cc
index 760bada7b0bf..dcaaadbd0896 100644
--- a/third_party/nix/src/libexpr/eval.cc
+++ b/third_party/nix/src/libexpr/eval.cc
@@ -1301,31 +1301,12 @@ void ExprOpUpdate::eval(EvalState& state, Env& env, Value& v) {
     return;
   }
 
-  state.mkAttrs(v, v1.attrs->size() + v2.attrs->size());
+  state.mkAttrs(v, /* capacity = */ 0);
 
   /* Merge the sets, preferring values from the second set.  Make
      sure to keep the resulting vector in sorted order. */
-  Bindings::iterator i = v1.attrs->begin();
-  Bindings::iterator j = v2.attrs->begin();
-
-  while (i != v1.attrs->end() && j != v2.attrs->end()) {
-    if (i->name == j->name) {
-      v.attrs->push_back(*j);
-      ++i;
-      ++j;
-    } else if (i->name < j->name) {
-      v.attrs->push_back(*i++);
-    } else {
-      v.attrs->push_back(*j++);
-    }
-  }
-
-  while (i != v1.attrs->end()) {
-    v.attrs->push_back(*i++);
-  }
-  while (j != v2.attrs->end()) {
-    v.attrs->push_back(*j++);
-  }
+  v.attrs->merge(v1.attrs);
+  v.attrs->merge(v2.attrs);
 
   state.nrOpUpdateValuesCopied += v.attrs->size();
 }