aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorpennae <github@quasiparticle.net>2022-01-02 00:41:21 +0100
committerpennae <github@quasiparticle.net>2022-01-14 14:01:52 +0100
commitc9fc975259e27220caeb4291f3dff453e65f1965 (patch)
tree0a354f5e80c59ad5eac65b84bb6db3ba0869d8e3 /src
parent6401e443a441f58f48e2cbab5286b89ec162835a (diff)
optimize removeAttrs builtin
use a sorted array of symbols to be removed instead of a set. this saves a lot of memory allocations and slightly speeds up removal.
Diffstat (limited to 'src')
-rw-r--r--src/libexpr/attr-set.hh7
-rw-r--r--src/libexpr/primops.cc20
2 files changed, 20 insertions, 7 deletions
diff --git a/src/libexpr/attr-set.hh b/src/libexpr/attr-set.hh
index 82c348287..3e4899efc 100644
--- a/src/libexpr/attr-set.hh
+++ b/src/libexpr/attr-set.hh
@@ -121,6 +121,8 @@ class BindingsBuilder
Bindings * bindings;
public:
+ // needed by std::back_inserter
+ using value_type = Attr;
EvalState & state;
@@ -135,6 +137,11 @@ public:
void insert(const Attr & attr)
{
+ push_back(attr);
+ }
+
+ void push_back(const Attr & attr)
+ {
bindings->push_back(attr);
}
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 003e588a4..839fbb95c 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -12,6 +12,8 @@
#include "value-to-xml.hh"
#include "primops.hh"
+#include <boost/container/small_vector.hpp>
+
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -2270,21 +2272,25 @@ static void prim_removeAttrs(EvalState & state, const Pos & pos, Value * * args,
state.forceAttrs(*args[0], pos);
state.forceList(*args[1], pos);
- /* Get the attribute names to be removed. */
- std::set<Symbol> names;
+ /* Get the attribute names to be removed.
+ We keep them as Attrs instead of Symbols so std::set_difference
+ can be used to remove them from attrs[0]. */
+ boost::container::small_vector<Attr, 64> names;
+ names.reserve(args[1]->listSize());
for (auto elem : args[1]->listItems()) {
state.forceStringNoCtx(*elem, pos);
- names.insert(state.symbols.create(elem->string.s));
+ names.emplace_back(state.symbols.create(elem->string.s), nullptr);
}
+ std::sort(names.begin(), names.end());
/* 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. */
auto attrs = state.buildBindings(args[0]->attrs->size());
- for (auto & i : *args[0]->attrs) {
- if (!names.count(i.name))
- attrs.insert(i);
- }
+ std::set_difference(
+ args[0]->attrs->begin(), args[0]->attrs->end(),
+ names.begin(), names.end(),
+ std::back_inserter(attrs));
v.mkAttrs(attrs.alreadySorted());
}