[C++] Regenerate ninja file when $(wildcard) is changed
diff --git a/fileutil.cc b/fileutil.cc
index 4c87e9c..11f8f6d 100644
--- a/fileutil.cc
+++ b/fileutil.cc
@@ -123,9 +123,7 @@
 class GlobCache {
  public:
   ~GlobCache() {
-    for (auto& p : cache_) {
-      delete p.second;
-    }
+    Clear();
   }
 
   void Get(const char* pat, vector<string>** files) {
@@ -147,13 +145,33 @@
     *files = p.first->second;
   }
 
+  const unordered_map<string, vector<string>*>& GetAll() const {
+    return cache_;
+  }
+
+  void Clear() {
+    for (auto& p : cache_) {
+      delete p.second;
+    }
+    cache_.clear();
+  }
+
  private:
   unordered_map<string, vector<string>*> cache_;
 };
 
+static GlobCache g_gc;
+
 }  // namespace
 
 void Glob(const char* pat, vector<string>** files) {
-  static GlobCache gc;
-  gc.Get(pat, files);
+  g_gc.Get(pat, files);
+}
+
+const unordered_map<string, vector<string>*>& GetAllGlobCache() {
+  return g_gc.GetAll();
+}
+
+void ClearGlobCache() {
+  g_gc.Clear();
 }
diff --git a/fileutil.h b/fileutil.h
index 96659d9..b282603 100644
--- a/fileutil.h
+++ b/fileutil.h
@@ -17,6 +17,7 @@
 
 #include <memory>
 #include <string>
+#include <unordered_map>
 #include <vector>
 
 #include "string_piece.h"
@@ -33,4 +34,8 @@
 
 void Glob(const char* pat, vector<string>** files);
 
+const unordered_map<string, vector<string>*>& GetAllGlobCache();
+
+void ClearGlobCache();
+
 #endif  // FILEUTIL_H_
diff --git a/main.cc b/main.cc
index e8eafa1..c45e7a1 100644
--- a/main.cc
+++ b/main.cc
@@ -227,6 +227,7 @@
       fprintf(stderr, "No need to regenerate ninja file\n");
       return 0;
     }
+    ClearGlobCache();
   }
 
   time_t start_time;
diff --git a/ninja.cc b/ninja.cc
index 636e867..cbf8b4f 100644
--- a/ninja.cc
+++ b/ninja.cc
@@ -20,6 +20,7 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
+#include <algorithm>
 #include <map>
 #include <memory>
 #include <string>
@@ -663,6 +664,48 @@
     fclose(fp);
   }
 
+  void GetCommonPrefixDir(const vector<string>& files, string* o) {
+    for (const string& file : files) {
+      size_t l = min(file.size(), o->size());
+      for (size_t i = 0; i < l; i++) {
+        if (file[i] != (*o)[i]) {
+          size_t index = o->rfind('/', i);
+          if (index == string::npos)
+            index = 0;
+          o->resize(index);
+          break;
+        }
+      }
+    }
+  }
+
+  void GetReadDirs(const string& pat,
+                   const vector<string>& files,
+                   unordered_set<string>* dirs) {
+    string prefix_dir = Dirname(pat).as_string();
+    size_t index = prefix_dir.find_first_of("?*[\\");
+    if (index != string::npos) {
+      index = prefix_dir.rfind('/', index);
+      if (index == string::npos) {
+        prefix_dir = "";
+      } else {
+        prefix_dir = prefix_dir.substr(0, index);
+      }
+    }
+
+    GetCommonPrefixDir(files, &prefix_dir);
+    if (prefix_dir.empty())
+      prefix_dir = ".";
+    dirs->insert(prefix_dir);
+    for (const string& file : files) {
+      StringPiece dir = Dirname(file);
+      while (dir != prefix_dir) {
+        dirs->insert(dir.as_string());
+        dir = Dirname(dir);
+      }
+    }
+  }
+
   void GenerateStamp() {
     FILE* fp = fopen(GetStampFilename().c_str(), "wb");
 
@@ -682,6 +725,23 @@
       DumpString(fp, p.second);
     }
 
+    const unordered_map<string, vector<string>*>& globs = GetAllGlobCache();
+    DumpInt(fp, globs.size());
+    for (const auto& p : globs) {
+      DumpString(fp, p.first);
+      const vector<string>& files = *p.second;
+      unordered_set<string> dirs;
+      GetReadDirs(p.first, files, &dirs);
+      DumpInt(fp, dirs.size());
+      for (const string& dir : dirs) {
+        DumpString(fp, dir);
+      }
+      DumpInt(fp, files.size());
+      for (const string& file : files) {
+        DumpString(fp, file);
+      }
+    }
+
     fclose(fp);
   }
 
@@ -723,8 +783,8 @@
   time_t gen_time = LoadInt(fp);
 
   string s, s2;
-  int l = LoadInt(fp);
-  for (int i = 0; i < l; i++) {
+  int num_files = LoadInt(fp);
+  for (int i = 0; i < num_files; i++) {
     LoadString(fp, &s);
     if (gen_time < GetTimestamp(s)) {
       fprintf(stderr, "%s was modified, regenerating...\n", s.c_str());
@@ -732,8 +792,8 @@
     }
   }
 
-  l = LoadInt(fp);
-  for (int i = 0; i < l; i++) {
+  int num_envs = LoadInt(fp);
+  for (int i = 0; i < num_envs; i++) {
     LoadString(fp, &s);
     StringPiece val(getenv(s.c_str()));
     LoadString(fp, &s2);
@@ -745,5 +805,42 @@
     }
   }
 
+  int num_globs = LoadInt(fp);
+  string pat;
+  for (int i = 0; i < num_globs; i++) {
+    LoadString(fp, &pat);
+    bool needs_reglob = false;
+    int num_dirs = LoadInt(fp);
+    for (int j = 0; j < num_dirs; j++) {
+      LoadString(fp, &s);
+      needs_reglob |= gen_time < GetTimestamp(s);
+    }
+
+    int num_files = LoadInt(fp);
+    if (needs_reglob) {
+      vector<string>* files;
+      Glob(pat.c_str(), &files);
+      sort(files->begin(), files->end());
+      bool needs_regen = files->size() != static_cast<size_t>(num_files);
+      if (!needs_regen) {
+        for (int j = 0; j < num_files; j++) {
+          LoadString(fp, &s);
+          if ((*files)[j] != s) {
+            needs_regen = true;
+            break;
+          }
+        }
+      }
+      if (needs_regen) {
+        fprintf(stderr, "wildcard(%s) was changed, regenerating...\n",
+                pat.c_str());
+        return true;
+      }
+    } else {
+      for (int j = 0; j < num_files; j++)
+        LoadString(fp, &s);
+    }
+  }
+
   return false;
 }