Fix PluginMetadata::NameMatches() performance

This reverts 15781c9b6b in favour of a
more complete fix that breaks ABI stability.
This commit is contained in:
Oliver Hamlet
2022-02-06 19:06:17 +00:00
parent bd242e847b
commit 7204e37721
5 changed files with 21 additions and 39 deletions
+2
View File
@@ -257,6 +257,8 @@ public:
private:
std::string name_;
std::optional<std::regex> nameRegex_;
std::optional<std::string> group_;
std::vector<File> loadAfter_;
std::vector<File> requirements_;
+11 -4
View File
@@ -45,8 +45,13 @@ PluginMetadata::PluginMetadata() {}
PluginMetadata::PluginMetadata(const std::string& n) : name_(n) {
// If the name passed ends in '.ghost', that should be trimmed.
if (boost::iends_with(name_, ".ghost"))
if (boost::iends_with(name_, ".ghost")) {
name_ = name_.substr(0, name_.length() - 6);
}
if (IsRegexPlugin()) {
nameRegex_ = std::regex(name_, std::regex::ECMAScript | std::regex::icase);
}
}
void PluginMetadata::MergeMetadata(const PluginMetadata& plugin) {
@@ -206,9 +211,11 @@ bool PluginMetadata::IsRegexPlugin() const {
bool PluginMetadata::NameMatches(const std::string& pluginName) const {
if (IsRegexPlugin()) {
return std::regex_match(
pluginName,
std::regex(name_, std::regex::ECMAScript | std::regex::icase));
if (!nameRegex_.has_value()) {
throw std::runtime_error("Regex plugin does not have regex object");
}
return std::regex_match(pluginName, nameRegex_.value());
}
return CompareFilenames(name_, pluginName) == 0;
+7 -12
View File
@@ -84,18 +84,13 @@ struct convert<loot::PluginMetadata> {
node.Mark(),
"bad conversion: 'name' key missing from 'plugin metadata' object");
rhs = loot::PluginMetadata(node["name"].as<std::string>());
// Test for valid regex.
if (rhs.IsRegexPlugin()) {
try {
std::regex(rhs.GetName(), std::regex::ECMAScript | std::regex::icase);
} catch (std::regex_error& e) {
throw RepresentationException(
node.Mark(),
std::string("bad conversion: invalid regex in 'name' key: ") +
e.what());
}
try {
rhs = loot::PluginMetadata(node["name"].as<std::string>());
} catch (std::regex_error& e) {
throw RepresentationException(
node.Mark(),
std::string("bad conversion: invalid regex in 'name' key: ") +
e.what());
}
if (node["group"])
+1 -21
View File
@@ -280,8 +280,6 @@ void MetadataList::Clear() {
unevaluatedPlugins_.clear();
unevaluatedRegexPlugins_.clear();
unevaluatedMessages_.clear();
pluginRegexNamesCache.clear();
}
std::vector<PluginMetadata> MetadataList::Plugins() const {
@@ -336,25 +334,7 @@ std::optional<PluginMetadata> MetadataList::FindPlugin(
// Now we want to also match possibly multiple regex entries.
auto nameMatches = [&](const PluginMetadata& pluginMetadata) {
// This doesn't call PluginMetadata::NameMatches() because that
// creates a std::regex object every time it's called, which is
// inefficient. NameMatches() can't be easily improved without
// breaking binary compatibility, so instead perform similar logic
// but cache plugin name regexes in the MetadataList object.
auto name = pluginMetadata.GetName();
if (pluginMetadata.IsRegexPlugin()) {
auto it = pluginRegexNamesCache.find(name);
if (it == pluginRegexNamesCache.end()) {
auto regex =
std::regex(name, std::regex::ECMAScript | std::regex::icase);
it = pluginRegexNamesCache.emplace(name, regex).first;
}
return std::regex_match(pluginName, it->second);
}
return CompareFilenames(name, pluginName) == 0;
return pluginMetadata.NameMatches(pluginName);
};
auto regIt = find_if(regexPlugins_.begin(), regexPlugins_.end(), nameMatches);
while (regIt != regexPlugins_.end()) {
-2
View File
@@ -92,8 +92,6 @@ protected:
std::vector<PluginMetadata> unevaluatedRegexPlugins_;
std::vector<Message> unevaluatedMessages_;
mutable std::unordered_map<std::string, std::regex> pluginRegexNamesCache;
void Load(std::istream& istream, const std::filesystem::path& source_path);
};
}