From c6144ccfe366b694bf034bdafa07e7c47ac8bf30 Mon Sep 17 00:00:00 2001 From: Evan Martin Date: Wed, 7 Dec 2011 08:45:16 -0800 Subject: [PATCH] merge FileStat into Node The two were always one-to-one anyway. I started adding accessors to FileStat and then realized most users wanted them on Node and that forwarding them through was silly. --- src/build.cc | 22 ++++++++++----------- src/build_log.cc | 2 +- src/build_test.cc | 20 +++++++++---------- src/clean.cc | 6 +++--- src/disk_interface_test.cc | 8 ++++---- src/graph.cc | 36 +++++++++++++++++----------------- src/graph.h | 48 +++++++++++++++++++++++++++++----------------- src/graph_test.cc | 2 +- src/graphviz.cc | 2 +- src/ninja.cc | 16 ++++++++-------- src/parsers_test.cc | 6 +++--- src/stat_cache.cc | 33 +++++++++++++++++-------------- src/stat_cache.h | 12 +++++++----- src/state.cc | 15 +++------------ 14 files changed, 119 insertions(+), 109 deletions(-) diff --git a/src/build.cc b/src/build.cc index 3da915d..6da821f 100644 --- a/src/build.cc +++ b/src/build.cc @@ -195,8 +195,8 @@ bool Plan::AddSubTarget(Node* node, vector* stack, string* err) { if (node->dirty_) { string referenced; if (!stack->empty()) - referenced = ", needed by '" + stack->back()->file_->path_ + "',"; - *err = "'" + node->file_->path_ + "'" + referenced + " missing " + referenced = ", needed by '" + stack->back()->path() + "',"; + *err = "'" + node->path() + "'" + referenced + " missing " "and no known rule to make it"; } return false; @@ -256,7 +256,7 @@ bool Plan::CheckDependencyCycle(Node* node, vector* stack, string* err) { for (vector::iterator i = start; i != stack->end(); ++i) { if (i != start) err->append(" -> "); - err->append((*i)->file_->path_); + err->append((*i)->path()); } return true; } @@ -324,8 +324,8 @@ void Plan::CleanNode(BuildLog* build_log, Node* node) { // Recompute most_recent_input and command. time_t most_recent_input = 1; for (vector::iterator ni = begin; ni != end; ++ni) - if ((*ni)->file_->mtime_ > most_recent_input) - most_recent_input = (*ni)->file_->mtime_; + if ((*ni)->mtime() > most_recent_input) + most_recent_input = (*ni)->mtime(); string command = (*ei)->EvaluateCommand(); // Now, recompute the dirty state of each output. @@ -454,7 +454,7 @@ Node* Builder::AddTarget(const string& name, string* err) { } bool Builder::AddTarget(Node* node, string* err) { - node->file_->StatIfNecessary(disk_interface_); + node->StatIfNecessary(disk_interface_); if (Edge* in_edge = node->in_edge_) { if (!in_edge->RecomputeDirty(state_, disk_interface_, err)) return false; @@ -555,7 +555,7 @@ bool Builder::StartEdge(Edge* edge, string* err) { // XXX: this will block; do we care? for (vector::iterator i = edge->outputs_.begin(); i != edge->outputs_.end(); ++i) { - if (!disk_interface_->MakeDirs((*i)->file_->path_)) + if (!disk_interface_->MakeDirs((*i)->path())) return false; } @@ -578,9 +578,9 @@ void Builder::FinishEdge(Edge* edge, bool success, const string& output) { for (vector::iterator i = edge->outputs_.begin(); i != edge->outputs_.end(); ++i) { - if ((*i)->file_->exists()) { - time_t new_mtime = disk_interface_->Stat((*i)->file_->path_); - if ((*i)->file_->mtime_ == new_mtime) { + if ((*i)->exists()) { + time_t new_mtime = disk_interface_->Stat((*i)->path()); + if ((*i)->mtime() == new_mtime) { // The rule command did not change the output. Propagate the clean // state through the build graph. plan_.CleanNode(log_, *i); @@ -594,7 +594,7 @@ void Builder::FinishEdge(Edge* edge, bool success, const string& output) { // (existing) non-order-only input or the depfile. for (vector::iterator i = edge->inputs_.begin(); i != edge->inputs_.end() - edge->order_only_deps_; ++i) { - time_t input_mtime = disk_interface_->Stat((*i)->file_->path_); + time_t input_mtime = disk_interface_->Stat((*i)->path()); if (input_mtime == 0) { restat_mtime = 0; break; diff --git a/src/build_log.cc b/src/build_log.cc index 7fd9ca1..852a9d0 100644 --- a/src/build_log.cc +++ b/src/build_log.cc @@ -73,7 +73,7 @@ void BuildLog::RecordCommand(Edge* edge, int start_time, int end_time, const string command = edge->EvaluateCommand(); for (vector::iterator out = edge->outputs_.begin(); out != edge->outputs_.end(); ++out) { - const string& path = (*out)->file_->path_; + const string& path = (*out)->path(); Log::iterator i = log_.find(path.c_str()); LogEntry* log_entry; if (i != log_.end()) { diff --git a/src/build_test.cc b/src/build_test.cc index b1879ff..eb9ead0 100644 --- a/src/build_test.cc +++ b/src/build_test.cc @@ -38,8 +38,8 @@ TEST_F(PlanTest, Basic) { Edge* edge = plan_.FindWork(); ASSERT_TRUE(edge); - ASSERT_EQ("in", edge->inputs_[0]->file_->path_); - ASSERT_EQ("mid", edge->outputs_[0]->file_->path_); + ASSERT_EQ("in", edge->inputs_[0]->path()); + ASSERT_EQ("mid", edge->outputs_[0]->path()); ASSERT_FALSE(plan_.FindWork()); @@ -47,8 +47,8 @@ TEST_F(PlanTest, Basic) { edge = plan_.FindWork(); ASSERT_TRUE(edge); - ASSERT_EQ("mid", edge->inputs_[0]->file_->path_); - ASSERT_EQ("out", edge->outputs_[0]->file_->path_); + ASSERT_EQ("mid", edge->inputs_[0]->path()); + ASSERT_EQ("out", edge->outputs_[0]->path()); plan_.EdgeFinished(edge); @@ -222,7 +222,7 @@ void BuildTest::Dirty(const string& path) { // If it's an input file, mark that we've already stat()ed it and // it's missing. if (!node->in_edge_) - node->file_->mtime_ = 0; + node->MarkMissing(); } bool BuildTest::CanRunMore() { @@ -237,7 +237,7 @@ bool BuildTest::StartCommand(Edge* edge) { edge->rule().name_ == "touch") { for (vector::iterator out = edge->outputs_.begin(); out != edge->outputs_.end(); ++out) { - fs_.Create((*out)->file_->path_, now_, ""); + fs_.Create((*out)->path(), now_, ""); } } else if (edge->rule().name_ == "true" || edge->rule().name_ == "fail") { @@ -508,10 +508,10 @@ TEST_F(BuildTest, OrderOnlyDeps) { EXPECT_EQ(1, edge->order_only_deps_); // Verify the inputs are in the order we expect // (explicit then implicit then orderonly). - EXPECT_EQ("foo.c", edge->inputs_[0]->file_->path_); - EXPECT_EQ("blah.h", edge->inputs_[1]->file_->path_); - EXPECT_EQ("bar.h", edge->inputs_[2]->file_->path_); - EXPECT_EQ("otherfile", edge->inputs_[3]->file_->path_); + EXPECT_EQ("foo.c", edge->inputs_[0]->path()); + EXPECT_EQ("blah.h", edge->inputs_[1]->path()); + EXPECT_EQ("bar.h", edge->inputs_[2]->path()); + EXPECT_EQ("otherfile", edge->inputs_[3]->path()); // Expect the command line we generate to only use the original input. ASSERT_EQ("cc foo.c", edge->EvaluateCommand()); diff --git a/src/clean.cc b/src/clean.cc index 8ae4385..c768629 100644 --- a/src/clean.cc +++ b/src/clean.cc @@ -109,7 +109,7 @@ int Cleaner::CleanAll(bool generator) { continue; for (vector::iterator out_node = (*e)->outputs_.begin(); out_node != (*e)->outputs_.end(); ++out_node) { - Remove((*out_node)->file_->path_); + Remove((*out_node)->path()); } if (!(*e)->rule().depfile_.empty()) Remove((*e)->EvaluateDepFile()); @@ -120,7 +120,7 @@ int Cleaner::CleanAll(bool generator) { void Cleaner::DoCleanTarget(Node* target) { if (target->in_edge_) { - Remove(target->file_->path_); + Remove(target->path()); for (vector::iterator n = target->in_edge_->inputs_.begin(); n != target->in_edge_->inputs_.end(); ++n) { @@ -182,7 +182,7 @@ void Cleaner::DoCleanRule(const Rule* rule) { for (vector::iterator out_node = (*e)->outputs_.begin(); out_node != (*e)->outputs_.end(); ++out_node) - Remove((*out_node)->file_->path_); + Remove((*out_node)->path()); } int Cleaner::CleanRule(const Rule* rule) { diff --git a/src/disk_interface_test.cc b/src/disk_interface_test.cc index 107726b..a7f94bb 100644 --- a/src/disk_interface_test.cc +++ b/src/disk_interface_test.cc @@ -193,7 +193,7 @@ TEST_F(StatTest, Simple) { "build out: cat in\n")); Node* out = GetNode("out"); - out->file_->Stat(this); + out->Stat(this); ASSERT_EQ(1u, stats_.size()); Edge* edge = out->in_edge_; edge->RecomputeDirty(NULL, this, NULL); @@ -208,7 +208,7 @@ TEST_F(StatTest, TwoStep) { "build mid: cat in\n")); Node* out = GetNode("out"); - out->file_->Stat(this); + out->Stat(this); ASSERT_EQ(1u, stats_.size()); Edge* edge = out->in_edge_; edge->RecomputeDirty(NULL, this, NULL); @@ -227,7 +227,7 @@ TEST_F(StatTest, Tree) { "build mid2: cat in21 in22\n")); Node* out = GetNode("out"); - out->file_->Stat(this); + out->Stat(this); ASSERT_EQ(1u, stats_.size()); Edge* edge = out->in_edge_; edge->RecomputeDirty(NULL, this, NULL); @@ -247,7 +247,7 @@ TEST_F(StatTest, Middle) { mtimes_["out"] = 1; Node* out = GetNode("out"); - out->file_->Stat(this); + out->Stat(this); ASSERT_EQ(1u, stats_.size()); Edge* edge = out->in_edge_; edge->RecomputeDirty(NULL, this, NULL); diff --git a/src/graph.cc b/src/graph.cc index 818eb4f..0aa155b 100644 --- a/src/graph.cc +++ b/src/graph.cc @@ -23,7 +23,7 @@ #include "state.h" #include "util.h" -bool FileStat::Stat(DiskInterface* disk_interface) { +bool Node::Stat(DiskInterface* disk_interface) { mtime_ = disk_interface->Stat(path_); return mtime_ > 0; } @@ -41,13 +41,13 @@ bool Edge::RecomputeDirty(State* state, DiskInterface* disk_interface, // Visit all inputs; we're dirty if any of the inputs are dirty. time_t most_recent_input = 1; for (vector::iterator i = inputs_.begin(); i != inputs_.end(); ++i) { - if ((*i)->file_->StatIfNecessary(disk_interface)) { + if ((*i)->StatIfNecessary(disk_interface)) { if (Edge* edge = (*i)->in_edge_) { if (!edge->RecomputeDirty(state, disk_interface, err)) return false; } else { // This input has no in-edge; it is dirty if it is missing. - (*i)->dirty_ = !(*i)->file_->exists(); + (*i)->dirty_ = !(*i)->exists(); } } @@ -63,8 +63,8 @@ bool Edge::RecomputeDirty(State* state, DiskInterface* disk_interface, if ((*i)->dirty_) { dirty = true; } else { - if ((*i)->file_->mtime_ > most_recent_input) - most_recent_input = (*i)->file_->mtime_; + if ((*i)->mtime() > most_recent_input) + most_recent_input = (*i)->mtime(); } } } @@ -77,7 +77,7 @@ bool Edge::RecomputeDirty(State* state, DiskInterface* disk_interface, for (vector::iterator i = outputs_.begin(); i != outputs_.end(); ++i) { - (*i)->file_->StatIfNecessary(disk_interface); + (*i)->StatIfNecessary(disk_interface); if (RecomputeOutputDirty(build_log, most_recent_input, command, *i)) { dirty = true; break; @@ -88,7 +88,7 @@ bool Edge::RecomputeDirty(State* state, DiskInterface* disk_interface, // Finally, visit each output to mark off that we've visited it, and update // their dirty state if necessary. for (vector::iterator i = outputs_.begin(); i != outputs_.end(); ++i) { - (*i)->file_->StatIfNecessary(disk_interface); + (*i)->StatIfNecessary(disk_interface); if (dirty) (*i)->dirty_ = true; } @@ -107,23 +107,23 @@ bool Edge::RecomputeOutputDirty(BuildLog* build_log, time_t most_recent_input, if (is_phony()) { // Phony edges don't write any output. // Outputs are only dirty if there are no inputs and we're missing the output. - return inputs_.empty() && !output->file_->exists(); + return inputs_.empty() && !output->exists(); } BuildLog::LogEntry* entry = 0; // Dirty if we're missing the output. - if (!output->file_->exists()) + if (!output->exists()) return true; // Dirty if the output is older than the input. - if (output->file_->mtime_ < most_recent_input) { + if (output->mtime() < most_recent_input) { // If this is a restat rule, we may have cleaned the output with a restat // rule in a previous run and stored the most recent input mtime in the // build log. Use that mtime instead, so that the file will only be // considered dirty if an input was modified since the previous run. if (rule_->restat_ && build_log && - (entry = build_log->LookupByOutput(output->file_->path_))) { + (entry = build_log->LookupByOutput(output->path()))) { if (entry->restat_mtime < most_recent_input) return true; } else { @@ -135,7 +135,7 @@ bool Edge::RecomputeOutputDirty(BuildLog* build_log, time_t most_recent_input, // But if this is a generator rule, the command changing does not make us // dirty. if (!rule_->generator_ && build_log && - (entry || (entry = build_log->LookupByOutput(output->file_->path_)))) { + (entry || (entry = build_log->LookupByOutput(output->path())))) { if (command != entry->command) return true; } @@ -164,14 +164,14 @@ struct EdgeEnv : public Env { i != edge_->inputs_.end() && explicit_deps; ++i, --explicit_deps) { if (!result.empty()) result.push_back(' '); - result.append((*i)->file_->path_); + result.append((*i)->path()); } } else if (var == "out") { for (vector::iterator i = edge_->outputs_.begin(); i != edge_->outputs_.end(); ++i) { if (!result.empty()) result.push_back(' '); - result.append((*i)->file_->path_); + result.append((*i)->path()); } } else if (edge_->env_) { return edge_->env_->LookupVariable(var); @@ -213,10 +213,10 @@ bool Edge::LoadDepFile(State* state, DiskInterface* disk_interface, } // Check that this depfile matches our output. - StringPiece opath = StringPiece(outputs_[0]->file_->path_); + StringPiece opath = StringPiece(outputs_[0]->path()); if (opath != makefile.out_) { *err = "expected depfile '" + path + "' to mention '" + - outputs_[0]->file_->path_ + "', got '" + makefile.out_.AsString() + "'"; + outputs_[0]->path() + "', got '" + makefile.out_.AsString() + "'"; return false; } @@ -260,11 +260,11 @@ bool Edge::LoadDepFile(State* state, DiskInterface* disk_interface, void Edge::Dump() { printf("[ "); for (vector::iterator i = inputs_.begin(); i != inputs_.end(); ++i) { - printf("%s ", (*i)->file_->path_.c_str()); + printf("%s ", (*i)->path().c_str()); } printf("--%s-> ", rule_->name_.c_str()); for (vector::iterator i = outputs_.begin(); i != outputs_.end(); ++i) { - printf("%s ", (*i)->file_->path_.c_str()); + printf("%s ", (*i)->path().c_str()); } printf("]\n"); } diff --git a/src/graph.h b/src/graph.h index 810d4ec..a52a3d7 100644 --- a/src/graph.h +++ b/src/graph.h @@ -23,11 +23,13 @@ using namespace std; struct DiskInterface; -struct Node; +struct Edge; -/// Information about a single on-disk file: path, mtime. -struct FileStat { - FileStat(const string& path) : path_(path), mtime_(-1), node_(NULL) {} +/// Information about a node in the dependency graph: the file, whether +/// it's dirty, mtime, etc. +struct Node { + Node(const string& path) : path_(path), mtime_(-1), dirty_(false), + in_edge_(NULL) {} /// Return true if the file exists (mtime_ got a value). bool Stat(DiskInterface* disk_interface); @@ -40,6 +42,17 @@ struct FileStat { return true; } + /// Mark as not-yet-stat()ed and not dirty. + void ResetState() { + mtime_ = -1; + dirty_ = false; + } + + /// Mark the Node as already-stat()ed and missing. + void MarkMissing() { + mtime_ = 0; + } + bool exists() const { return mtime_ != 0; } @@ -48,13 +61,25 @@ struct FileStat { return mtime_ != -1; } + const string& path() const { return path_; } + time_t mtime() const { return mtime_; } + + bool dirty() const { return dirty_; } + +private: string path_; // Possible values of mtime_: // -1: file hasn't been examined // 0: we looked, and file doesn't exist // >0: actual file's mtime time_t mtime_; - Node* node_; + + // TODO: make these private as well. But don't just blindly add + // setters/getters, instead pay attention to the proper API. +public: + bool dirty_; + Edge* in_edge_; + vector out_edges_; }; /// An invokable build command and associated metadata (description, etc.). @@ -134,17 +159,4 @@ struct Edge { bool is_phony() const; }; -/// Information about a node in the dependency graph: the file, whether -/// it's dirty, etc. -struct Node { - Node(FileStat* file) : file_(file), dirty_(false), in_edge_(NULL) {} - - bool dirty() const { return dirty_; } - - FileStat* file_; - bool dirty_; - Edge* in_edge_; - vector out_edges_; -}; - #endif // NINJA_GRAPH_H_ diff --git a/src/graph_test.cc b/src/graph_test.cc index e221089..8ab921e 100644 --- a/src/graph_test.cc +++ b/src/graph_test.cc @@ -127,7 +127,7 @@ TEST_F(GraphTest, RootNodes) { vector root_nodes = state_.RootNodes(&err); EXPECT_EQ(4u, root_nodes.size()); for (size_t i = 0; i < root_nodes.size(); ++i) { - string name = root_nodes[i]->file_->path_; + string name = root_nodes[i]->path(); EXPECT_EQ("out", name.substr(0, 3)); } } diff --git a/src/graphviz.cc b/src/graphviz.cc index aa75ea1..aa5bb08 100644 --- a/src/graphviz.cc +++ b/src/graphviz.cc @@ -22,7 +22,7 @@ void GraphViz::AddTarget(Node* node) { if (visited_.find(node) != visited_.end()) return; - printf("\"%p\" [label=\"%s\"]\n", node, node->file_->path_.c_str()); + printf("\"%p\" [label=\"%s\"]\n", node, node->path().c_str()); visited_.insert(node); if (!node->in_edge_) { diff --git a/src/ninja.cc b/src/ninja.cc index 86c9a59..f0525fb 100644 --- a/src/ninja.cc +++ b/src/ninja.cc @@ -168,7 +168,7 @@ bool CollectTargetsFromArgs(State* state, int argc, char* argv[], Node* suggestion = state->SpellcheckNode(path); if (suggestion) { - *err += ", did you mean '" + suggestion->file_->path_ + "'?"; + *err += ", did you mean '" + suggestion->path() + "'?"; } return false; } @@ -207,7 +207,7 @@ int CmdQuery(State* state, int argc, char* argv[]) { printf(" input: %s\n", node->in_edge_->rule_->name_.c_str()); for (vector::iterator in = node->in_edge_->inputs_.begin(); in != node->in_edge_->inputs_.end(); ++in) { - printf(" %s\n", (*in)->file_->path_.c_str()); + printf(" %s\n", (*in)->path().c_str()); } } for (vector::iterator edge = node->out_edges_.begin(); @@ -215,14 +215,14 @@ int CmdQuery(State* state, int argc, char* argv[]) { printf(" output: %s\n", (*edge)->rule_->name_.c_str()); for (vector::iterator out = (*edge)->outputs_.begin(); out != (*edge)->outputs_.end(); ++out) { - printf(" %s\n", (*out)->file_->path_.c_str()); + printf(" %s\n", (*out)->path().c_str()); } } } else { Node* suggestion = state->SpellcheckNode(argv[i]); if (suggestion) { printf("%s unknown, did you mean %s?\n", - argv[i], suggestion->file_->path_.c_str()); + argv[i], suggestion->path().c_str()); } else { printf("%s unknown\n", argv[i]); } @@ -257,7 +257,7 @@ int CmdTargetsList(const vector& nodes, int depth, int indent) { ++n) { for (int i = 0; i < indent; ++i) printf(" "); - const char* target = (*n)->file_->path_.c_str(); + const char* target = (*n)->path().c_str(); if ((*n)->in_edge_) { printf("%s: %s\n", target, (*n)->in_edge_->rule_->name_.c_str()); if (depth > 1 || depth <= 0) @@ -281,7 +281,7 @@ int CmdTargetsSourceList(State* state) { inps != (*e)->inputs_.end(); ++inps) if (!(*inps)->in_edge_) - printf("%s\n", (*inps)->file_->path_.c_str()); + printf("%s\n", (*inps)->path().c_str()); return 0; } @@ -294,7 +294,7 @@ int CmdTargetsList(State* state, const string& rule_name) { if ((*e)->rule_->name_ == rule_name) { for (vector::iterator out_node = (*e)->outputs_.begin(); out_node != (*e)->outputs_.end(); ++out_node) { - rules.insert((*out_node)->file_->path_); + rules.insert((*out_node)->path()); } } } @@ -314,7 +314,7 @@ int CmdTargetsList(State* state) { for (vector::iterator out_node = (*e)->outputs_.begin(); out_node != (*e)->outputs_.end(); ++out_node) { printf("%s: %s\n", - (*out_node)->file_->path_.c_str(), + (*out_node)->path().c_str(), (*e)->rule_->name_.c_str()); } } diff --git a/src/parsers_test.cc b/src/parsers_test.cc index a99b510..4ef4edb 100644 --- a/src/parsers_test.cc +++ b/src/parsers_test.cc @@ -482,9 +482,9 @@ TEST_F(ParserTest, DefaultStatements) { std::vector nodes = state.DefaultNodes(&err); EXPECT_EQ("", err); ASSERT_EQ(3u, nodes.size()); - EXPECT_EQ("a", nodes[0]->file_->path_); - EXPECT_EQ("b", nodes[1]->file_->path_); - EXPECT_EQ("c", nodes[2]->file_->path_); + EXPECT_EQ("a", nodes[0]->path()); + EXPECT_EQ("b", nodes[1]->path()); + EXPECT_EQ("c", nodes[2]->path()); } TEST(MakefileParser, Basic) { diff --git a/src/stat_cache.cc b/src/stat_cache.cc index 368f545..e414d41 100644 --- a/src/stat_cache.cc +++ b/src/stat_cache.cc @@ -19,25 +19,32 @@ #include "edit_distance.h" #include "graph.h" -FileStat* StatCache::GetFile(const std::string& path) { +Node* StatCache::GetFile(const std::string& path) { + Node* node = LookupFile(path); + if (node) + return node; + node = new Node(path); + paths_[node->path().c_str()] = node; + return node; +} + +Node* StatCache::LookupFile(const std::string& path) { Paths::iterator i = paths_.find(path.c_str()); if (i != paths_.end()) return i->second; - FileStat* file = new FileStat(path); - paths_[file->path_.c_str()] = file; - return file; + return NULL; } -FileStat* StatCache::SpellcheckFile(const std::string& path) { +Node* StatCache::SpellcheckFile(const std::string& path) { const bool kAllowReplacements = true; const int kMaxValidEditDistance = 3; int min_distance = kMaxValidEditDistance + 1; - FileStat* result = NULL; + Node* result = NULL; for (Paths::iterator i = paths_.begin(); i != paths_.end(); ++i) { int distance = EditDistance( i->first, path, kAllowReplacements, kMaxValidEditDistance); - if (distance < min_distance && i->second->node_) { + if (distance < min_distance && i->second) { min_distance = distance; result = i->second; } @@ -47,17 +54,15 @@ FileStat* StatCache::SpellcheckFile(const std::string& path) { void StatCache::Dump() { for (Paths::iterator i = paths_.begin(); i != paths_.end(); ++i) { - FileStat* file = i->second; + Node* node = i->second; printf("%s %s\n", - file->path_.c_str(), - file->status_known() ? (file->node_->dirty_ ? "dirty" : "clean") + node->path().c_str(), + node->status_known() ? (node->dirty() ? "dirty" : "clean") : "unknown"); } } void StatCache::Invalidate() { - for (Paths::iterator i = paths_.begin(); i != paths_.end(); ++i) { - i->second->mtime_ = -1; - i->second->node_->dirty_ = false; - } + for (Paths::iterator i = paths_.begin(); i != paths_.end(); ++i) + i->second->ResetState(); } diff --git a/src/stat_cache.h b/src/stat_cache.h index 2a5b38b..b7d6e8a 100644 --- a/src/stat_cache.h +++ b/src/stat_cache.h @@ -16,23 +16,25 @@ #define NINJA_STAT_CACHE_H_ #include +using namespace std; #include "hash_map.h" #include -struct FileStat; +struct Node; -/// Mapping of path -> FileStat. +/// Mapping of path -> Node. struct StatCache { - FileStat* GetFile(const std::string& path); - FileStat* SpellcheckFile(const std::string& path); + Node* GetFile(const string& path); + Node* LookupFile(const string& path); + Node* SpellcheckFile(const string& path); /// Dump the mapping to stdout (useful for debugging). void Dump(); void Invalidate(); - typedef ExternalStringHashMap::Type Paths; + typedef ExternalStringHashMap::Type Paths; Paths paths_; }; diff --git a/src/state.cc b/src/state.cc index 9519856..bbb2f6a 100644 --- a/src/state.cc +++ b/src/state.cc @@ -46,24 +46,15 @@ Edge* State::AddEdge(const Rule* rule) { } Node* State::GetNode(const string& path) { - FileStat* file = stat_cache_.GetFile(path); - if (!file->node_) - file->node_ = new Node(file); - return file->node_; + return stat_cache_.GetFile(path); } Node* State::LookupNode(const string& path) { - FileStat* file = stat_cache_.GetFile(path); - if (!file->node_) - return NULL; - return file->node_; + return stat_cache_.LookupFile(path); } Node* State::SpellcheckNode(const string& path) { - FileStat* file = stat_cache_.SpellcheckFile(path); - if (!file || !file->node_) - return NULL; - return file->node_; + return stat_cache_.SpellcheckFile(path); } void State::AddIn(Edge* edge, const string& path) { -- 2.7.4