aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2020-02-21 19:25:49 +0100
committerEelco Dolstra <edolstra@gmail.com>2020-03-04 11:44:33 +0100
commit401b5bc5418f3eb6d57da9d9e66df055f8bce122 (patch)
treedef41918a82908b259517da056a69c790a88d2c5
parentd700eecea9a274c1b45549141f40180ac74454ce (diff)
builtins.cache: Cache regular expressions
The evaluator was spending about 1% of its time compiling a small number of regexes over and over again.
-rw-r--r--src/libexpr/eval.hh4
-rw-r--r--src/libexpr/primops.cc8
2 files changed, 9 insertions, 3 deletions
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index cabc92d15..34a212aa4 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -114,6 +114,9 @@ private:
/* Cache used by checkSourcePath(). */
std::unordered_map<Path, Path> resolvedPaths;
+ /* Cache used by prim_match(). */
+ std::unordered_map<std::string, std::regex> regexCache;
+
public:
EvalState(const Strings & _searchPath, ref<Store> store);
@@ -314,6 +317,7 @@ private:
friend struct ExprOpConcatLists;
friend struct ExprSelect;
friend void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v);
+ friend void prim_match(EvalState & state, const Pos & pos, Value * * args, Value & v);
};
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 29302c9b6..4cd28698c 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -1811,19 +1811,21 @@ static void prim_hashString(EvalState & state, const Pos & pos, Value * * args,
/* Match a regular expression against a string and return either
‘null’ or a list containing substring matches. */
-static void prim_match(EvalState & state, const Pos & pos, Value * * args, Value & v)
+void prim_match(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
auto re = state.forceStringNoCtx(*args[0], pos);
try {
- std::regex regex(re, std::regex::extended);
+ auto regex = state.regexCache.find(re);
+ if (regex == state.regexCache.end())
+ regex = state.regexCache.emplace(re, std::regex(re, std::regex::extended)).first;
PathSet context;
const std::string str = state.forceString(*args[1], context, pos);
std::smatch match;
- if (!std::regex_match(str, match, regex)) {
+ if (!std::regex_match(str, match, regex->second)) {
mkNull(v);
return;
}