DetectorGraph  2.0
graph.hpp
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 #ifndef DETECTORGRAPH_INCLUDE_GRAPH_HPP_
16 #define DETECTORGRAPH_INCLUDE_GRAPH_HPP_
17 
18 
19 #include "subscriberinterface.hpp"
20 #include "vertex.hpp"
22 #include "graphinputdispatcher.hpp"
23 #include "topic.hpp"
24 #include "topicstate.hpp"
25 #include "topicregistry.hpp"
26 #include "graphinputqueue.hpp"
27 
28 #include "errortype.hpp"
29 
30 #if defined(BUILD_FEATURE_DETECTORGRAPH_CONFIG_LITE)
31 // LITE_BEGIN
32 #include "detectorgraphliteconfig.hpp"
35 // LITE_END
36 #else
37 // FULL_BEGIN
38 #include "sharedptr.hpp"
39 #include <list>
40 #include <typeinfo>
41 #include <limits>
42 #include <stdint.h>
43 // FULL_END
44 #endif
45 
46 namespace DetectorGraph
47 {
48 
49 class Detector;
50 
51 /**
52  * @brief Implements a graph of \link Topic Topics\endlink & \link Detector
53  * Detectors\endlink with Input/Output APIs
54  *
55  * Application's Graphs can be built using Aggregation or Composition with this
56  * class.
57  *
58  * Detectors are added to the graph and the graph is responsible for creating
59  * the necessary Topics to satisfy all dependencies.
60  *
61  * Below are a couple of example of how to setup Graph with Detectors:
62  *
63  * - Simple / bare-bones:
64  * @snippet helloworld.cpp Adding to a Graph
65  * This is the simplest way to build graphs and is used throughout unit tests.
66  *
67  * - Aggregation example using automatic storage for graph & detectors:
68  * @code
69 class MyApplication
70 {
71 public:
72  MyApplication() : mGraph(), mFooDetector(&mGraph), mBarDetector(&mGraph)
73  {
74  }
75 
76  Graph mGraph;
77  FooDetector mFooDetector;
78  BarDetector mBarDetector;
79 };
80  * @endcode
81  *
82  * - Composition using dynamic allocation of detectors:
83  * @code
84 class MyApplicationGraph : public DetectorGraph::Graph
85 {
86 public:
87  FooBarGraph()
88  {
89  mFooDetector = new FooDetector(this);
90  mBarDetector = new BarDetector(this);
91  }
92 
93  ~FooBarGraph()
94  {
95  delete mFooDetector;
96  delete mBarDetector;
97  }
98 
99  FooDetector* mFooDetector;
100  BarDetector* mBarDetector;
101 };
102  * @endcode
103  * This option offers a lot of flexibility at construction time and makes graph
104  * ownership of detectors more obvious.
105  *
106  *
107  * Graph:
108  * - Owns all vertices (Topics and Detectors)
109  * - Provides the data input API (@ref PushData<T>) (into topics)
110  * - Provides the data output API (@ref GetOutputList) (from topics)
111  * - Provides an API for graph evaluation (@ref EvaluateGraph)
112  * - Maintains the Graph's topological sort across graph changes topology changes
113  * - Creates Topics as needed to satisfy all Detector's dependencies
114  *
115  * Typical control flow:
116  * - External events/messages/inputs are translated into TopicStates and
117  * passed to PushData().
118  * - EvaluateGraph() running in an event loop until HasDataPending() is false.
119  * - After each call to EvaluateGraph() the list in GetOutputList() is
120  * inspected for TopicStates of interest that must be passed onwards to the
121  * outside.
122  *
123  *
124  * This class also maintains an Inversion of Control container (@ref TopicRegistry)
125  * for Topics. The IoC container is basically a "repository" of singleton topics.
126  */
127 class Graph
128 {
129 public:
130 
131 #if defined(BUILD_FEATURE_DETECTORGRAPH_CONFIG_LITE)
133 #else
134  typedef std::list<Vertex*> VertexPtrContainer;
135 #endif
136 
137  /**
138  * @brief Constructor
139  *
140  * Does nothing really
141  */
142  Graph();
143 
144  /**
145  * @brief Destructor
146  *
147  * When a Graph is destroyed, it deletes all the pending graph dispatchers,
148  * detectors, and topics (even if they're not referred to by any detectors).
149  */
150  virtual ~Graph();
151 
152  /**
153  * @brief Find/add a topic in the detector graph
154  *
155  * If the topic to resolve already exists, return it.
156  * Otherwise, registering a new topic and then return it.
157  *
158  * \return A unique topic of type \p TTopic in this graph.
159  */
160  template<class TTopicState> Topic<TTopicState>* ResolveTopic()
161  {
162  Topic<TTopicState>* tObj = mTopicRegistry.Resolve<TTopicState>();
163 
164  // Creates Topics on demand.
165  if (tObj == NULL)
166  {
167 #if defined(BUILD_FEATURE_DETECTORGRAPH_CONFIG_LITE)
168  tObj = topicAllocator.New<Topic<TTopicState>>();
169 #else
170  tObj = new Topic<TTopicState>();
171 #endif
172  mTopicRegistry.Register<TTopicState>(tObj);
173  AddVertex(tObj);
174  }
175  // FULL_END
176 
177  return tObj;
178  } // LCOV_EXCL_LINE
179 
180  /**
181  * @brief Push data to a specific topic in the graph
182  *
183  * This method is used to input data into the graph and
184  * it's the only API to do so.
185  *
186  */
187  template<class TTopicState> void PushData(const TTopicState& aTopicState)
188  {
189  mGraphInputQueue.Enqueue(*ResolveTopic<TTopicState>(), aTopicState);
190  }
191 
192  /**
193  * @brief Evaluate the whole graph
194  */
196 
197  /**
198  * @brief Returns true if there is data pending evaluation
199  *
200  * This can be useful when implementing a 'flush & evaluate all data'
201  * pattern because calls to \ref EvaluateGraph() remove only single TopicState
202  * from the input queue at a time for each evaluation of the graph.
203  */
204  bool HasDataPending();
205 
206  /**
207  * @brief Evaluates Graph if data is pending and returns true if so.
208  *
209  * This method is a convenience combination of HasDataPending() and
210  * EvaluateGraph() that makes it a bit cleaner to implement simple
211  * evaluation loops.
212  * It assumes that EvaluateGraph() always succeeds; it'll fail a DG_ASSERT
213  * otherwise.
214  */
216 
217  void AddVertex(Vertex* aVertex);
218  void RemoveVertex(Vertex* aVertex);
220 
221  const VertexPtrContainer& GetVertices() const
222  {
223  return mVertices;
224  }
225 
226 private:
227  /**
228  * @ brief Clears @ref VertexSearchState to kVertexClear on all vertices
229  */
230  ErrorType ClearTraverseContexts();
231 
232  /**
233  * @brief Traverse though vertices in the right order and perform computation
234  */
235  ErrorType TraverseVertices();
236 
237 private:
238  TopicRegistry mTopicRegistry;
239  GraphInputQueue mGraphInputQueue;
240  VertexPtrContainer mVertices;
241 
242 
243 #if defined(BUILD_FEATURE_DETECTORGRAPH_CONFIG_LITE)
244  // LITE_BEGIN
245 public:
246  /**
247  * @brief Checks that the vertices are topologically sorted.
248  */
249  bool IsGraphSorted();
250  // LITE_END
251 
252 private:
253  struct GraphTopicAllocatorCtxt {};
255 
256 #else
257  // FULL_BEGIN
258 
259 public:
260  /**
261  * @brief Returns the list of topicstates published in the last Evaluation.
262  *
263  * It returns a list of references (valid only in between evaluations) to
264  * the topicstates that changed during the last call to \ref EvaluateGraph()
265  */
266  const std::list<ptr::shared_ptr<const TopicState> >& GetOutputList() const;
267 
268  /**
269  * @brief Determine the right order to process the vertices by topological sort
270  */
272 
273 private:
274  /**
275  * @brief Pop data out of topics to the output list after evaluation
276  */
277  ErrorType ComposeOutputList();
278 
279  /**
280  * @brief Recursive method used on Depth-First-Search used on topo-sorting
281  */
282  ErrorType DFS_visit(Vertex* v, VertexPtrContainer& sorted);
283 
284 private:
285  bool mNeedsSorting;
286  std::list<ptr::shared_ptr<const TopicState> > mOutputList;
287  // FULL_END
288 #endif
289 };
290 
291 }
292 
293 #endif // DETECTORGRAPH_INCLUDE_GRAPH_HPP_
const VertexPtrContainer & GetVertices() const
Definition: graph.hpp:221
TopicRegistry & GetTopicRegistry()
Definition: graph.cpp:102
Implements a graph of Topics & Detectors with Input/Output APIs.
Definition: graph.hpp:127
Internal - A limited-size Container for Topic<T>s
void PushData(const TTopicState &aTopicState)
Push data to a specific topic in the graph.
Definition: graph.hpp:187
void Enqueue(Topic< TTopicState > &aTopic, const TTopicState &aTopicState)
Manage data and its handler.
Definition: topic.hpp:84
virtual ~Graph()
Destructor.
Definition: graph.cpp:31
void Register(Topic< TTopicState > *obj)
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
Topic< TTopicState > * Resolve()
Graph()
Constructor.
Definition: graph.cpp:23
void AddVertex(Vertex *aVertex)
Definition: graph.cpp:58
Topic< TTopicState > * ResolveTopic()
Find/add a topic in the detector graph.
Definition: graph.hpp:160
bool HasDataPending()
Returns true if there is data pending evaluation.
Definition: graph.cpp:97
Internal - Provides an bare-bones version of GraphInputQueue
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 RemoveVertex(Vertex *aVertex)
Definition: graph.cpp:69
std::list< Vertex * > VertexPtrContainer
Definition: graph.hpp:134
ErrorType EvaluateGraph()
Evaluate the whole graph.
Definition: graph.cpp:133
Define behaviors of a vertex in a graph.
Definition: vertex.hpp:37