1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-12-23 17:31: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
{
boost::concurrent_flat_map<std::string, std::regex, StringViewHash, std::equal_to<>> cache;
std::regex get(std::string_view re)
struct Entry
{
std::regex regex;
/* No std::regex constructor overload from std::string_view, but can be constructed
from a pointer + size or an iterator range. */
ref<const std::regex> regex;
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(
re,
/*s=*/re.data(),
/*count=*/re.size(),
std::regex::extended,
[&regex](const auto & kv) { regex = kv.second; },
[&regex](const auto & kv) { regex = kv.second; });
return regex;
[&regex](const auto & kv) { regex = kv.second.regex; },
[&regex](const auto & kv) { regex = kv.second.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");
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();
return;
}
@ -4818,7 +4825,7 @@ void prim_split(EvalState & state, const PosIdx pos, Value ** args, Value & v)
const auto str =
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();
// Any matches results are surrounded by non-matching results.