DetectorGraph  2.0
graph.cpp
Go to the documentation of this file.
1 // Copyright 2017 Nest Labs, Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "graph.hpp"
16 
17 #include "dglogging.hpp"
18 #include "dgassert.hpp"
19 
20 namespace DetectorGraph
21 {
22 
24 #if !defined(BUILD_FEATURE_DETECTORGRAPH_CONFIG_LITE)
25  : mNeedsSorting(false)
26 #endif
27 {
28  DG_LOG("Graph Initialized");
29 }
30 
32 {
33 #if !defined(BUILD_FEATURE_DETECTORGRAPH_CONFIG_LITE)
34  // Detectors remove themselves from the graph when deleted
35  // so we need a robust deletion process (instead of for (begin,!=end,++))
36  // that is ok with removing items behind the iterator.
37  std::list<Vertex*>::iterator vertexIt = mVertices.begin();
38  while (vertexIt != mVertices.end())
39  {
40  Vertex* tmp = *vertexIt;
41  vertexIt++;
43  {
44  delete tmp;
45  }
46  }
47 
48  vertexIt = mVertices.begin();
49  while (vertexIt != mVertices.end())
50  {
51  Vertex* tmp = *vertexIt;
52  vertexIt++;
53  delete tmp;
54  }
55 #endif
56 }
57 
58 void Graph::AddVertex(Vertex* aVertex)
59 {
60  mVertices.push_back(aVertex);
61 #if !defined(BUILD_FEATURE_DETECTORGRAPH_CONFIG_LITE)
62  mNeedsSorting = true;
63 #endif
64 #if defined(BUILD_FEATURE_DETECTORGRAPH_CONFIG_INSTRUMENT_RESOURCE_USAGE)
65  DG_LOG("Added Vertex (total=%u)", mVertices.size());
66 #endif
67 }
68 
70 {
71 #if defined(BUILD_FEATURE_DETECTORGRAPH_CONFIG_LITE)
72  // TODO(cscotti): Assert? Destructor? Linear remove?
73  DG_LOG("dummy RemoveVertex called for %p.", (void*)aVertex);
74 #else
75  mVertices.remove(aVertex);
76  mNeedsSorting = true;
77 #endif
78 }
79 
81 {
82  if (HasDataPending())
83  {
85  r = EvaluateGraph();
86  if (r != ErrorType_Success) // LCOV_EXCL_START
87  {
88  DG_LOG("Evaluation failed with %d.", (int)r);
89  DG_ASSERT(false);
90  } // LCOV_EXCL_STOP
91  return true;
92  }
93 
94  return false;
95 }
96 
98 {
99  return !mGraphInputQueue.IsEmpty();
100 }
101 
103 {
104  return mTopicRegistry;
105 }
106 
107 ErrorType Graph::ClearTraverseContexts()
108 {
110  for (VertexPtrContainer::iterator vertexIt = mVertices.begin();
111  vertexIt != mVertices.end();
112  ++vertexIt)
113  {
114  (*vertexIt)->SetState(Vertex::kVertexClear);
115  }
116  return r;
117 }
118 
119 ErrorType Graph::TraverseVertices()
120 {
122 
123  for (VertexPtrContainer::iterator it = mVertices.begin();
124  it != mVertices.end();
125  ++it)
126  {
127  (*it)->ProcessVertex();
128  }
129 
130  return r;
131 }
132 
134 {
136 
137 #if !defined(BUILD_FEATURE_DETECTORGRAPH_CONFIG_LITE)
138  if (mNeedsSorting)
139  {
140  r = TopoSortGraph();
141  if (r != ErrorType_Success)
142  {
143  DG_LOG("Graph::TopoSortGraph() failed");
144  return r;
145  }
146  }
147 #endif
148 
149  ClearTraverseContexts();
150 
151  mGraphInputQueue.DequeueAndDispatch();
152 
153  r = TraverseVertices();
154  if (r != ErrorType_Success) // LCOV_EXCL_START // Dead code for future-proofness
155  {
156  DG_LOG("Graph::TraverseVertices() failed");
157  return r;
158  } // LCOV_EXCL_STOP
159 
160 #if !defined(BUILD_FEATURE_DETECTORGRAPH_CONFIG_LITE)
161  r = ComposeOutputList();
162  if (r != ErrorType_Success) // LCOV_EXCL_START // Dead code for future-proofness
163  {
164  DG_LOG("Graph::ComposeOutputList() failed");
165  return r;
166  } // LCOV_EXCL_STOP
167 #endif
168 
169  return r;
170 }
171 
172 #if defined(BUILD_FEATURE_DETECTORGRAPH_CONFIG_LITE)
173 bool Graph::IsGraphSorted()
174 {
175  ClearTraverseContexts();
176  int processingNodes = 0;
177  for (VertexPtrContainer::iterator vertexIt = mVertices.begin();
178  vertexIt != mVertices.end();
179  ++vertexIt)
180  {
181  Vertex* v = *vertexIt;
182  if (v->GetState() == Vertex::kVertexDone)
183  {
184  return false;
185  }
186  else if (v->GetState() == Vertex::kVertexClear)
187  {
188  processingNodes++;
190  }
191  for (VertexPtrContainer::iterator outEdgeIt = v->GetOutEdges().begin();
192  outEdgeIt != v->GetOutEdges().end();
193  ++outEdgeIt)
194  {
195  Vertex* outVertex = *outEdgeIt;
196  if (outVertex->GetState() == Vertex::kVertexDone)
197  {
198  return false;
199  }
200  else if (outVertex->GetState() == Vertex::kVertexClear)
201  {
202  processingNodes++;
204  }
205  }
206 
208  processingNodes--;
209  }
210 
211  if (processingNodes != 0)
212  {
213  DG_LOG("---------%d Out of Bounds edge --------", processingNodes);
214  return false;
215  }
216 
217  return true;
218 }
219 #else
220 // FULL_BEGIN
221 
223 {
225  // SORT
226 
227  // Clean graph-search context
228  ClearTraverseContexts();
229 
230  std::list<Vertex*> sorted;
231 
232  size_t numVertices = mVertices.size();
233 
234  // cout << "--- TOPOSORT START ---" << endl;
235  // DFS starting on any random vertex and repeating for other undiscovered
236  // vertices
237  for (std::list<Vertex*>::iterator vertexIt = mVertices.begin();
238  vertexIt != mVertices.end();
239  ++vertexIt)
240  {
241  if ((*vertexIt)->GetState() == Vertex::kVertexClear)
242  {
243  // cout << "TOP DFS_visit" << endl;
244  r = DFS_visit(*vertexIt, sorted);
245  if (r != ErrorType_Success)
246  {
247  return r;
248  }
249  }
250  }
251  // cout << "--- TOPOSORT END ---" << endl;
252 
253  if (sorted.size() != numVertices)
254  {
255  // Tree structure is inconsistent.
256  // This probably means that a vertex 'm' pointed to
257  // a vertex 'n' outside of the graph. This can happen
258  // if you have a bug in the insertion/removal of detectors.
259  DG_LOG("--------------------------------------");
260  DG_LOG("------------- BAD GRAPH --------------");
261  DG_LOG("---------- Out of Bounds edge --------");
262  DG_LOG("--------------------------------------");
264  return r;
265  }
266 
267  // Save sorted vertices
268  mVertices = sorted;
269  mNeedsSorting = false;
270 
271  return r;
272 }
273 
274 ErrorType Graph::DFS_visit(Vertex* v, std::list<Vertex*>& sorted)
275 {
277 
278  // cout << "---> Starting at " << v->GetName() << " that has " << v->GetOutEdges().size() << " out edges " << endl;
280  for (std::list<Vertex*>::iterator vIt = v->GetOutEdges().begin();
281  vIt != v->GetOutEdges().end();
282  ++vIt)
283  {
284  // cout << "Examining edge from " << v->GetName() << " to " << (*vIt)->GetName() << endl;
285  if ((*vIt)->GetState() == Vertex::kVertexClear)
286  {
287  r = DFS_visit(*vIt, sorted);
288  if (r != ErrorType_Success)
289  {
290  return r;
291  }
292  }
293  else if ((*vIt)->GetState() == Vertex::kVertexProcessing)
294  {
295  DG_LOG("--------------------------------------");
296  DG_LOG("------------CYCLE DETECTED------------");
297  DG_LOG("---------- Will Ignore edge ----------");
298  DG_LOG("--------------------------------------");
299  DG_LOG("Cycle at: %s", (*vIt)->GetName());
301  if (r != ErrorType_Success)
302  {
303  return r;
304  }
305  } // LCOV_EXCL_LINE
306  //v2 - do nothing.
307  }
308  // cout << "<--- Finished at " << v->GetName() << endl;
310  sorted.push_front(v);
311 
312  return r;
313 }
314 
315 ErrorType Graph::ComposeOutputList()
316 {
318 
319  mOutputList.clear();
320 
321  for (std::list< Vertex* >::iterator it = mVertices.begin();
322  it != mVertices.end();
323  ++it)
324  {
325  if ( (*it)->GetVertexType() == Vertex::kTopicVertex)
326  {
327  BaseTopic* tTopic = static_cast<BaseTopic*>(*it);
328  std::list< ptr::shared_ptr<const TopicState> > tTopicStates = tTopic->GetCurrentTopicStates();
329 
330  //Pushes back entire list
331  mOutputList.insert(mOutputList.end(), tTopicStates.begin(), tTopicStates.end());
332  }
333  }
334 
335  return r;
336 } // LCOV_EXCL_LINE
337 
338 const std::list< ptr::shared_ptr<const TopicState> >& Graph::GetOutputList() const
339 {
340  return mOutputList;
341 }
342 
343 // FULL_END
344 #endif
345 
346 }
TopicRegistry & GetTopicRegistry()
Definition: graph.cpp:102
Internal - A limited-size Container for Topic<T>s
virtual ~Graph()
Destructor.
Definition: graph.cpp:31
void DG_LOG(const char *aLogString,...)
Definition: dglogging.cpp:22
ErrorType TopoSortGraph()
Determine the right order to process the vertices by topological sort.
Definition: graph.cpp:222
bool EvaluateIfHasDataPending()
Evaluates Graph if data is pending and returns true if so.
Definition: graph.cpp:80
VertexPtrContainer & GetOutEdges()
Definition: vertex.hpp:100
VertexSearchState GetState() const
Definition: vertex.hpp:71
Graph()
Constructor.
Definition: graph.cpp:23
Provide interface for a topic.
Definition: topic.hpp:46
virtual VertexType GetVertexType() const =0
void AddVertex(Vertex *aVertex)
Definition: graph.cpp:58
bool HasDataPending()
Returns true if there is data pending evaluation.
Definition: graph.cpp:97
const std::list< ptr::shared_ptr< const TopicState > > & GetOutputList() const
Returns the list of topicstates published in the last Evaluation.
Definition: graph.cpp:338
void SetState(VertexSearchState aNewState)
Definition: vertex.hpp:76
void RemoveVertex(Vertex *aVertex)
Definition: graph.cpp:69
ErrorType EvaluateGraph()
Evaluate the whole graph.
Definition: graph.cpp:133
#define DG_ASSERT(condition)
Definition: dgassert.hpp:20
virtual std::list< ptr::shared_ptr< const TopicState > > GetCurrentTopicStates() const =0
Define behaviors of a vertex in a graph.
Definition: vertex.hpp:37