fileutil: improve cache handling of file globs
Avoid needless allocations by letting the cache vector manage our
memory. Further, clarify the interface by passing vectors of glob files
by immutable const&.
Signed-off-by: Matthias Maennich <[email protected]>
diff --git a/src/eval.cc b/src/eval.cc
index cff4799..58d8d5b 100644
--- a/src/eval.cc
+++ b/src/eval.cc
@@ -635,11 +635,10 @@
const string&& pats = stmt->expr->Eval(this);
for (StringPiece pat : WordScanner(pats)) {
ScopedTerminator st(pat);
- vector<string>* files;
- Glob(pat.data(), &files);
+ const auto& files = Glob(pat.data());
if (stmt->should_exist) {
- if (files->empty()) {
+ if (files.empty()) {
// TODO: Kati does not support building a missing include file.
Error(StringPrintf("%s: %s", pat.data(), strerror(errno)));
}
@@ -647,7 +646,7 @@
include_stack_.push_back(stmt->loc());
- for (const string& fname : *files) {
+ for (const string& fname : files) {
if (!stmt->should_exist && g_flags.ignore_optional_include_pattern &&
Pattern(g_flags.ignore_optional_include_pattern).Match(fname)) {
continue;
diff --git a/src/fileutil.cc b/src/fileutil.cc
index 1a0179d..fef8d82 100644
--- a/src/fileutil.cc
+++ b/src/fileutil.cc
@@ -159,50 +159,42 @@
class GlobCache {
public:
~GlobCache() { Clear(); }
-
- void Get(const char* pat, vector<string>** files) {
- auto p = cache_.emplace(pat, nullptr);
- if (p.second) {
- vector<string>* files = p.first->second = new vector<string>;
+ const GlobMap::mapped_type& Get(const char* pat) {
+ auto [it, inserted] = cache_.try_emplace(pat);
+ auto& files = it->second;
+ if (inserted) {
if (strcspn(pat, "?*[\\") != strlen(pat)) {
glob_t gl;
glob(pat, 0, NULL, &gl);
for (size_t i = 0; i < gl.gl_pathc; i++) {
- files->push_back(gl.gl_pathv[i]);
+ files.push_back(gl.gl_pathv[i]);
}
globfree(&gl);
} else {
if (Exists(pat))
- files->push_back(pat);
+ files.push_back(pat);
}
}
- *files = p.first->second;
+ return files;
}
- const unordered_map<string, vector<string>*>& GetAll() const {
- return cache_;
- }
+ const GlobMap& GetAll() const { return cache_; }
- void Clear() {
- for (auto& p : cache_) {
- delete p.second;
- }
- cache_.clear();
- }
+ void Clear() { cache_.clear(); }
private:
- unordered_map<string, vector<string>*> cache_;
+ GlobMap cache_;
};
static GlobCache g_gc;
} // namespace
-void Glob(const char* pat, vector<string>** files) {
- g_gc.Get(pat, files);
+const GlobMap::mapped_type& Glob(const char* pat) {
+ return g_gc.Get(pat);
}
-const unordered_map<string, vector<string>*>& GetAllGlobCache() {
+const GlobMap& GetAllGlobCache() {
return g_gc.GetAll();
}
diff --git a/src/fileutil.h b/src/fileutil.h
index f50291f..1ff4fc1 100644
--- a/src/fileutil.h
+++ b/src/fileutil.h
@@ -44,9 +44,11 @@
std::string GetExecutablePath();
-void Glob(const char* pat, vector<string>** files);
+using GlobMap = std::unordered_map<std::string, std::vector<std::string>>;
-const unordered_map<string, vector<string>*>& GetAllGlobCache();
+const GlobMap::mapped_type& Glob(const char* pat);
+
+const GlobMap& GetAllGlobCache();
void ClearGlobCache();
diff --git a/src/func.cc b/src/func.cc
index 5d226c7..8c298a7 100644
--- a/src/func.cc
+++ b/src/func.cc
@@ -323,11 +323,10 @@
// Note GNU make does not delay the execution of $(wildcard) so we
// do not need to check avoid_io here.
WordWriter ww(s);
- vector<string>* files;
for (StringPiece tok : WordScanner(pat)) {
ScopedTerminator st(tok);
- Glob(tok.data(), &files);
- for (const string& file : *files) {
+ const auto& files = Glob(tok.data());
+ for (const string& file : files) {
ww.Write(file);
}
}
diff --git a/src/ninja.cc b/src/ninja.cc
index 76fd5dc..660c8c0 100644
--- a/src/ninja.cc
+++ b/src/ninja.cc
@@ -741,12 +741,10 @@
DumpString(fp, value);
}
- const std::unordered_map<std::string, std::vector<std::string>*>& globs =
- GetAllGlobCache();
+ auto& globs = GetAllGlobCache();
DumpInt(fp, globs.size());
- for (const auto& [key, values] : globs) {
+ for (const auto& [key, files] : globs) {
DumpString(fp, key);
- const std::vector<std::string>& files = *values;
#if 0
std::unordered_set<std::string> dirs;
GetReadDirs(p.first, files, &dirs);
diff --git a/src/regen.cc b/src/regen.cc
index 10587cd..ee2559f 100644
--- a/src/regen.cc
+++ b/src/regen.cc
@@ -278,12 +278,11 @@
bool CheckGlobResult(const GlobResult* gr, string* err) {
COLLECT_STATS("glob time (regen)");
- vector<string>* files;
- Glob(gr->pat.c_str(), &files);
- bool needs_regen = files->size() != gr->result.size();
+ const auto& files = Glob(gr->pat.c_str());
+ bool needs_regen = files.size() != gr->result.size();
for (size_t i = 0; i < gr->result.size(); i++) {
if (!needs_regen) {
- if ((*files)[i] != gr->result[i]) {
+ if (files[i] != gr->result[i]) {
needs_regen = true;
break;
}