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:
parent
723c47550e
commit
0c8751d3f4
1 changed files with 19 additions and 12 deletions
|
|
@ -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,
|
[®ex](const auto & kv) { regex = kv.second.regex; },
|
||||||
[®ex](const auto & kv) { regex = kv.second; },
|
[®ex](const auto & kv) { regex = kv.second.regex; });
|
||||||
[®ex](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.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue