7
7
8
8
namespace rime {
9
9
10
+ enum DependencyPriority {
11
+ kPendingChild = 0 ,
12
+ kInclude = 1 ,
13
+ kPatch = 2 ,
14
+ };
15
+
10
16
struct Dependency {
11
17
an<ConfigItemRef> target;
12
18
13
- virtual bool blocking () const = 0;
19
+ virtual DependencyPriority priority () const = 0;
20
+ bool blocking () const {
21
+ return priority () > kPendingChild ;
22
+ }
14
23
virtual string repr () const = 0;
15
24
virtual bool Resolve (ConfigCompiler* compiler) = 0;
16
25
};
17
26
18
27
template <class StreamT >
19
28
StreamT& operator << (StreamT& stream, const Dependency& dep) {
20
- return stream << dep.repr () << (dep. blocking () ? " (blocking) " : " " ) ;
29
+ return stream << dep.repr ();
21
30
}
22
31
23
32
struct PendingChild : Dependency {
@@ -27,8 +36,8 @@ struct PendingChild : Dependency {
27
36
PendingChild (const string& path, const an<ConfigItemRef>& ref)
28
37
: child_path(path), child_ref(ref) {
29
38
}
30
- bool blocking () const override {
31
- return false ;
39
+ DependencyPriority priority () const override {
40
+ return kPendingChild ;
32
41
}
33
42
string repr () const override {
34
43
return " PendingChild(" + child_path + " )" ;
@@ -48,8 +57,8 @@ StreamT& operator<< (StreamT& stream, const Reference& reference) {
48
57
struct IncludeReference : Dependency {
49
58
IncludeReference (const Reference& r) : reference(r) {
50
59
}
51
- bool blocking () const override {
52
- return true ;
60
+ DependencyPriority priority () const override {
61
+ return kInclude ;
53
62
}
54
63
string repr () const override {
55
64
return " Include(" + reference.repr () + " )" ;
@@ -62,8 +71,8 @@ struct IncludeReference : Dependency {
62
71
struct PatchReference : Dependency {
63
72
PatchReference (const Reference& r) : reference(r) {
64
73
}
65
- bool blocking () const override {
66
- return true ;
74
+ DependencyPriority priority () const override {
75
+ return kPatch ;
67
76
}
68
77
string repr () const override {
69
78
return " Patch(" + reference.repr () + " )" ;
@@ -78,8 +87,8 @@ struct PatchLiteral : Dependency {
78
87
79
88
PatchLiteral (an<ConfigMap> map) : patch(map) {
80
89
}
81
- bool blocking () const override {
82
- return true ;
90
+ DependencyPriority priority () const override {
91
+ return kPatch ;
83
92
}
84
93
string repr () const override {
85
94
return " Patch(<literal>)" ;
@@ -91,7 +100,7 @@ struct ConfigDependencyGraph {
91
100
map<string, of<ConfigResource>> resources;
92
101
vector<of<ConfigItemRef>> node_stack;
93
102
vector<string> key_stack;
94
- map<string, list <of<Dependency>>> deps;
103
+ map<string, vector <of<Dependency>>> deps;
95
104
96
105
void Add (an<Dependency> dependency);
97
106
@@ -162,21 +171,34 @@ bool PatchLiteral::Resolve(ConfigCompiler* compiler) {
162
171
return success;
163
172
}
164
173
174
+ static void InsertByPriority (vector<of<Dependency>>& list,
175
+ const an<Dependency>& value) {
176
+ auto upper = std::upper_bound (
177
+ list.begin (), list.end (), value,
178
+ [](const an<Dependency>& lhs, const an<Dependency>& rhs) {
179
+ return lhs->priority () < rhs->priority ();
180
+ });
181
+ list.insert (upper, value);
182
+ }
183
+
165
184
void ConfigDependencyGraph::Add (an<Dependency> dependency) {
166
- LOG (INFO) << " ConfigDependencyGraph::Add(), node_stack.size() = " << node_stack.size ();
185
+ LOG (INFO) << " ConfigDependencyGraph::Add(), node_stack.size() = "
186
+ << node_stack.size ();
167
187
if (node_stack.empty ()) return ;
168
188
const auto & target = node_stack.back ();
169
189
dependency->target = target;
170
190
auto target_path = ConfigData::JoinPath (key_stack);
171
191
auto & target_deps = deps[target_path];
172
192
bool target_was_pending = !target_deps.empty ();
173
- target_deps.push_back (dependency);
174
- LOG (INFO) << " target_path = " << target_path << " , #deps = " << target_deps.size ();
193
+ InsertByPriority (target_deps, dependency);
194
+ LOG (INFO) << " target_path = " << target_path
195
+ << " , #deps = " << target_deps.size ();
175
196
if (target_was_pending || // so was all ancestors
176
197
key_stack.size () == 1 ) { // this is the progenitor
177
198
return ;
178
199
}
179
- // The current pending node becomes a prioritized dependency of parent node
200
+ // The current pending node becomes a prioritized non-blocking dependency of
201
+ // its parent node; spread the pending state to its non-pending ancestors
180
202
auto keys = key_stack;
181
203
for (auto child = node_stack.rbegin (); child != node_stack.rend (); ++child) {
182
204
auto last_key = keys.back ();
@@ -185,8 +207,10 @@ void ConfigDependencyGraph::Add(an<Dependency> dependency) {
185
207
auto & parent_deps = deps[parent_path];
186
208
bool parent_was_pending = !parent_deps.empty ();
187
209
// Pending children should be resolved before applying __include or __patch
188
- parent_deps.push_front (New<PendingChild>(parent_path + " /" + last_key, *child));
189
- LOG (INFO) << " parent_path = " << parent_path << " , #deps = " << parent_deps.size ();
210
+ InsertByPriority (parent_deps,
211
+ New<PendingChild>(parent_path + " /" + last_key, *child));
212
+ LOG (INFO) << " parent_path = " << parent_path
213
+ << " , #deps = " << parent_deps.size ();
190
214
if (parent_was_pending || // so was all ancestors
191
215
keys.size () == 1 ) { // this parent is the progenitor
192
216
return ;
@@ -418,10 +442,10 @@ bool ConfigCompiler::ResolveDependencies(const string& path) {
418
442
auto & deps = graph_->deps [path];
419
443
for (auto iter = deps.begin (); iter != deps.end (); ) {
420
444
if (!(*iter)->Resolve (this )) {
421
- LOG (ERROR) << " unesolved dependency:" << **iter;
445
+ LOG (ERROR) << " unresolved dependency: " << **iter;
422
446
return false ;
423
447
}
424
- LOG (INFO) << " resolved " << **iter;
448
+ LOG (INFO) << " resolved: " << **iter;
425
449
iter = deps.erase (iter);
426
450
}
427
451
LOG (INFO) << " all dependencies resolved." ;
0 commit comments