From 401b5bc5418f3eb6d57da9d9e66df055f8bce122 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 21 Feb 2020 19:25:49 +0100 Subject: [PATCH] builtins.cache: Cache regular expressions The evaluator was spending about 1% of its time compiling a small number of regexes over and over again. --- src/libexpr/eval.hh | 4 ++++ src/libexpr/primops.cc | 8 +++++--- 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 resolvedPaths; + /* Cache used by prim_match(). */ + std::unordered_map regexCache; + public: EvalState(const Strings & _searchPath, ref 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; }