summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEvan Martin <martine@danga.com>2011-12-07 16:45:16 (GMT)
committerEvan Martin <martine@danga.com>2011-12-07 16:47:38 (GMT)
commitc6144ccfe366b694bf034bdafa07e7c47ac8bf30 (patch)
treee373660d4da9ba0b55a05cf719e28d6dd91f5a68 /src
parent276f2b319188ea905ebfc39ebaab684a2255c012 (diff)
downloadNinja-c6144ccfe366b694bf034bdafa07e7c47ac8bf30.zip
Ninja-c6144ccfe366b694bf034bdafa07e7c47ac8bf30.tar.gz
Ninja-c6144ccfe366b694bf034bdafa07e7c47ac8bf30.tar.bz2
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.
Diffstat (limited to 'src')
-rw-r--r--src/build.cc22
-rw-r--r--src/build_log.cc2
-rw-r--r--src/build_test.cc20
-rw-r--r--src/clean.cc6
-rw-r--r--src/disk_interface_test.cc8
-rw-r--r--src/graph.cc36
-rw-r--r--src/graph.h48
-rw-r--r--src/graph_test.cc2
-rw-r--r--src/graphviz.cc2
-rw-r--r--src/ninja.cc16
-rw-r--r--src/parsers_test.cc6
-rw-r--r--src/stat_cache.cc33
-rw-r--r--src/stat_cache.h12
-rw-r--r--src/state.cc15
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<Node*>* 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<Node*>* stack, string* err) {
for (vector<Node*>::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<Node*>::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<Node*>::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<Node*>::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<Node*>::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<Node*>::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<Node*>::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<Node*>::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<Node*>::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<Node*>::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<Node*>::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<Node*>::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<Node*>::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<Node*>::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<Node*>::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<Node*>::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<Edge*> 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<Edge*> 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<Node*> 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<Node*>::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<Edge*>::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<Node*>::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<Node*>& 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<Node*>::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<Node*>::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<Node*> 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 <string>
+using namespace std;
#include "hash_map.h"
#include <string.h>
-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<FileStat*>::Type Paths;
+ typedef ExternalStringHashMap<Node*>::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) {