diff options
author | pennae <github@quasiparticle.net> | 2022-01-02 00:41:21 +0100 |
---|---|---|
committer | pennae <github@quasiparticle.net> | 2022-01-14 14:01:52 +0100 |
commit | c9fc975259e27220caeb4291f3dff453e65f1965 (patch) | |
tree | 0a354f5e80c59ad5eac65b84bb6db3ba0869d8e3 /src | |
parent | 6401e443a441f58f48e2cbab5286b89ec162835a (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.hh | 7 | ||||
-rw-r--r-- | src/libexpr/primops.cc | 20 |
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()); } |