1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-12-24 01:41:08 +01:00

libexpr: avoid std::regex copies on RegexCache hits

- RegexCache::get() returned std::regex by value, copying the compiled regex on every cache hit.
- Store the compiled regex behind std::shared_ptr<const std::regex> and return the shared pointer instead, so callers reuse the same compiled object.
- BM_EvalManyBuiltinsMatchSameRegex_mean improved about 8%
This commit is contained in:
Kamil Monicz 2025-12-18 03:11:38 +00:00
parent 723c47550e
commit 0c8751d3f4
No known key found for this signature in database
GPG key ID: F9FB19F1C1DC9C23

View file

@ -4709,21 +4709,28 @@ static RegisterPrimOp primop_convertHash({
struct RegexCache struct RegexCache
{ {
boost::concurrent_flat_map<std::string, std::regex, StringViewHash, std::equal_to<>> cache; struct Entry
std::regex get(std::string_view re)
{ {
std::regex regex; ref<const std::regex> regex;
/* No std::regex constructor overload from std::string_view, but can be constructed
from a pointer + size or an iterator range. */ Entry(const char * s, size_t count)
: regex(make_ref<const std::regex>(s, count, std::regex::extended))
{
}
};
boost::concurrent_flat_map<std::string, Entry, StringViewHash, std::equal_to<>> cache;
ref<const std::regex> get(std::string_view re)
{
std::optional<ref<const std::regex>> regex;
cache.try_emplace_and_cvisit( cache.try_emplace_and_cvisit(
re, re,
/*s=*/re.data(), /*s=*/re.data(),
/*count=*/re.size(), /*count=*/re.size(),
std::regex::extended, [&regex](const auto & kv) { regex = kv.second.regex; },
[&regex](const auto & kv) { regex = kv.second; }, [&regex](const auto & kv) { regex = kv.second.regex; });
[&regex](const auto & kv) { regex = kv.second; }); return *regex;
return regex;
} }
}; };
@ -4745,7 +4752,7 @@ void prim_match(EvalState & state, const PosIdx pos, Value ** args, Value & v)
state.forceString(*args[1], context, pos, "while evaluating the second argument passed to builtins.match"); state.forceString(*args[1], context, pos, "while evaluating the second argument passed to builtins.match");
std::cmatch match; std::cmatch match;
if (!std::regex_match(str.begin(), str.end(), match, regex)) { if (!std::regex_match(str.begin(), str.end(), match, *regex)) {
v.mkNull(); v.mkNull();
return; return;
} }
@ -4818,7 +4825,7 @@ void prim_split(EvalState & state, const PosIdx pos, Value ** args, Value & v)
const auto str = const auto str =
state.forceString(*args[1], context, pos, "while evaluating the second argument passed to builtins.split"); state.forceString(*args[1], context, pos, "while evaluating the second argument passed to builtins.split");
auto begin = std::cregex_iterator(str.begin(), str.end(), regex); auto begin = std::cregex_iterator(str.begin(), str.end(), *regex);
auto end = std::cregex_iterator(); auto end = std::cregex_iterator();
// Any matches results are surrounded by non-matching results. // Any matches results are surrounded by non-matching results.