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;
         }