]> git.lyx.org Git - lyx.git/blob - src/Graph.cpp
* add PreBabelPreamble to Language definition (fixes #4786).
[lyx.git] / src / Graph.cpp
1 /**
2  * \file Graph.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Dekel Tsur (original code)
7  * \author Richard Heck (re-implementation)
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "Graph.h"
15 #include "Format.h"
16
17 #include "support/debug.h"
18 #include "support/lassert.h"
19
20 #include <algorithm>
21
22 using namespace std;
23
24 namespace lyx {
25
26
27 bool Graph::bfs_init(int s, bool clear_visited)
28 {
29         if (s < 0)
30                 return false;
31
32         Q_ = queue<int>();
33
34         if (clear_visited) {
35                 vector<Vertex>::iterator it = vertices_.begin();
36                 vector<Vertex>::iterator en = vertices_.end();
37                 for (; it != en; ++it)
38                         it->visited = false;
39         }
40         if (!vertices_[s].visited) {
41                 Q_.push(s);
42                 vertices_[s].visited = true;
43         }
44         return true;
45 }
46
47
48 void Graph::clearPaths()
49 {
50         vector<Vertex>::iterator it = vertices_.begin();
51         vector<Vertex>::iterator en = vertices_.end();
52         for (; it != en; ++it)
53                 it->path.clear();
54 }
55
56
57 vector<int> const
58         Graph::getReachableTo(int target, bool clear_visited)
59 {
60         vector<int> result;
61         if (!bfs_init(target, clear_visited))
62                 return result;
63
64         // Here's the logic, which is shared by the other routines.
65         // Q_ holds a list of nodes we have been able to reach (in this
66         // case, reach backwards). It is initialized to the current node
67         // by bfs_init, and then we recurse, adding the nodes we can reach
68         // from the current node as we go. That makes it a breadth-first
69         // search.
70         while (!Q_.empty()) {
71                 int const current = Q_.front();
72                 Q_.pop();
73                 if (current != target || formats.get(target).name() != "lyx")
74                         result.push_back(current);
75
76                 vector<Arrow *>::iterator it = vertices_[current].in_arrows.begin();
77                 vector<Arrow *>::iterator const end = vertices_[current].in_arrows.end();
78                 for (; it != end; ++it) {
79                         const int cv = (*it)->from;
80                         if (!vertices_[cv].visited) {
81                                 vertices_[cv].visited = true;
82                                 Q_.push(cv);
83                         }
84                 }
85         }
86
87         return result;
88 }
89
90
91 vector<int> const
92         Graph::getReachable(int from, bool only_viewable,
93                 bool clear_visited)
94 {
95         vector<int> result;
96         if (!bfs_init(from, clear_visited))
97                 return result;
98
99         while (!Q_.empty()) {
100                 int const current = Q_.front();
101                 Q_.pop();
102                 Format const & format = formats.get(current);
103                 if (!only_viewable || !format.viewer().empty())
104                         result.push_back(current);
105                 else if (format.isChildFormat()) {
106                         Format const * const parent =
107                                 formats.getFormat(format.parentFormat());
108                         if (parent && !parent->viewer().empty())
109                                 result.push_back(current);
110                 }
111
112                 vector<Arrow *>::const_iterator cit =
113                         vertices_[current].out_arrows.begin();
114                 vector<Arrow *>::const_iterator end =
115                         vertices_[current].out_arrows.end();
116                 for (; cit != end; ++cit) {
117                         int const cv = (*cit)->to;
118                         if (!vertices_[cv].visited) {
119                                 vertices_[cv].visited = true;
120                                 Q_.push(cv);
121                         }
122                 }
123         }
124
125         return result;
126 }
127
128
129 bool Graph::isReachable(int from, int to)
130 {
131         if (from == to)
132                 return true;
133
134         if (to < 0 || !bfs_init(from))
135                 return false;
136
137         while (!Q_.empty()) {
138                 int const current = Q_.front();
139                 Q_.pop();
140                 if (current == to)
141                         return true;
142
143                 vector<Arrow *>::const_iterator cit =
144                         vertices_[current].out_arrows.begin();
145                 vector<Arrow *>::const_iterator end =
146                         vertices_[current].out_arrows.end();
147                 for (; cit != end; ++cit) {
148                         int const cv = (*cit)->to;
149                         if (!vertices_[cv].visited) {
150                                 vertices_[cv].visited = true;
151                                 Q_.push(cv);
152                         }
153                 }
154         }
155
156         return false;
157 }
158
159
160 Graph::EdgePath const Graph::getPath(int from, int to)
161 {
162         static const EdgePath path;
163         if (from == to)
164                 return path;
165
166         if (to < 0 || !bfs_init(from))
167                 return path;
168
169         clearPaths();
170         while (!Q_.empty()) {
171                 int const current = Q_.front();
172                 Q_.pop();
173
174                 vector<Arrow *>::const_iterator cit =
175                         vertices_[current].out_arrows.begin();
176                 vector<Arrow *>::const_iterator end =
177                         vertices_[current].out_arrows.end();
178                 for (; cit != end; ++cit) {
179                         int const cv = (*cit)->to;
180                         if (!vertices_[cv].visited) {
181                                 vertices_[cv].visited = true;
182                                 Q_.push(cv);
183                                 // NOTE If we wanted to collect all the paths, then
184                                 // we just need to collect them here and not worry
185                                 // about "visited".
186                                 EdgePath lastpath = vertices_[(*cit)->from].path;
187                                 lastpath.push_back((*cit)->id);
188                                 vertices_[cv].path = lastpath;
189                         }
190                         if (cv == to) {
191                                 return vertices_[cv].path;
192                         }
193                 }
194         }
195         // failure
196         return path;
197 }
198
199
200 void Graph::init(int size)
201 {
202         vertices_ = vector<Vertex>(size);
203         arrows_.clear();
204         numedges_ = 0;
205 }
206
207
208 void Graph::addEdge(int from, int to)
209 {
210         arrows_.push_back(Arrow(from, to, numedges_));
211         numedges_++;
212         Arrow * ar = &(arrows_.back());
213         vertices_[to].in_arrows.push_back(ar);
214         vertices_[from].out_arrows.push_back(ar);
215 }
216
217
218 // At present, we do not need this debugging code, but
219 // I am going to leave it here in case we need it again.
220 #if 0
221 void Graph::dumpGraph() const
222 {
223         vector<Vertex>::const_iterator it = vertices_.begin();
224         vector<Vertex>::const_iterator en = vertices_.end();
225         for (; it != en; ++it) {
226                 LYXERR0("Next vertex...");
227                 LYXERR0("In arrows...");
228                 std::vector<Arrow *>::const_iterator iit = it->in_arrows.begin();
229                 std::vector<Arrow *>::const_iterator ien = it->in_arrows.end();
230                 for (; iit != ien; ++iit)
231                         LYXERR0("From " << (*iit)->from << " to " << (*iit)->to);
232                 LYXERR0("Out arrows...");
233                 iit = it->out_arrows.begin();
234                 ien = it->out_arrows.end();
235                 for (; iit != ien; ++iit)
236                         LYXERR0("From " << (*iit)->from << " to " << (*iit)->to);
237         }
238 }
239 #endif
240
241
242 } // namespace lyx