DetectorGraph  2.0
graphinputqueue-lite.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_GRAPHINPUTQUEUE_LITE_HPP_
16 #define DETECTORGRAPH_INCLUDE_GRAPHINPUTQUEUE_LITE_HPP_
17 
18 #include "graphinputdispatcher.hpp"
19 
20 #include "dgassert.hpp"
21 
22 namespace DetectorGraph
23 {
24 /**
25  * @brief _Internal_ - Provides an bare-bones version of GraphInputQueue
26  */
28 {
29 private:
30  struct InputQueueNode
31  {
32  InputQueueNode(uint8_t* aDispatcherStorage)
33  : dispatcherStorage(aDispatcherStorage), dispatcher(NULL)
34  , next(NULL), busy(false)
35  {
36  }
37 
38  uint8_t* dispatcherStorage;
40  InputQueueNode* next;
41  bool busy;
42  };
43 
44 public:
45  GraphInputQueue() : mHeadNode(NULL), mTailNode(NULL) {}
46 
47  template<class TTopicState>
48  void Enqueue(Topic<TTopicState>& aTopic, const TTopicState& aTopicState)
49  {
50  InputQueueNode* node = GetQueueNode<TTopicState>();
51 
52  DG_ASSERT(!node->busy);
53  // WARNING: Give how we keep the storage of GraphInputDispatcher and
54  // nodes it's impossible to, for a given TTopicState, have two nodes
55  // enqueued at the same time. Here we're choosing to assert if we
56  // encounter this scenario. In practice this would happen if a
57  // TopicState is being FuturePublished faster than it's being consumed
58  // - and the only way to achieve that is by calling it twice for the
59  // same topic in a single evaluation pass or if two FuturePublished
60  // topics are competing for the next evaluation pass and they cause one
61  // another to be re-published - this is very contrived and deep.
62  //
63  // In the weird world where the above is a problem we could clobber the
64  // dispatcher with the new data and just not enqueue it. This is not
65  // necessarily wrong but violates the current rules, would be
66  // unnecessary complexity and would certainly hide graph design bugs.
67 
68  node->dispatcher =
69  new(node->dispatcherStorage) GraphInputDispatcher<TTopicState>(
70  aTopic, aTopicState);
71 
72  node->busy = true;
73  EnqueueNode(node);
74  }
75 
77  {
78  InputQueueNode* nextNode = DequeueNode();
79  if (nextNode)
80  {
81  GraphInputDispatcherInterface* nextInput = nextNode->dispatcher;
82 
83  // Will call Topic->Publish(aTopicState)
84  nextInput->Dispatch();
85 
86  nextNode->busy = false;
87 
88  return true;
89  }
90  else
91  {
92  return false;
93  }
94  }
95 
96  bool IsEmpty() const
97  {
98  return mHeadNode == NULL;
99  }
100 
102  {
103  InputQueueNode* nextNode = DequeueNode();
104 
105  while(nextNode != NULL)
106  {
107  nextNode->busy = false;
108  nextNode = DequeueNode();
109  }
110  }
111 
112 private:
113  void EnqueueNode(InputQueueNode* node)
114  {
115  if (mTailNode == NULL)
116  {
117  mHeadNode = node;
118  mTailNode = node;
119  mTailNode->next = NULL;
120  }
121  else
122  {
123  mTailNode->next = node;
124  mTailNode = node;
125  mTailNode->next = NULL;
126  }
127  }
128 
129  InputQueueNode* DequeueNode()
130  {
131  InputQueueNode* tmp = mHeadNode;
132  if (mHeadNode)
133  {
134  if (mHeadNode->next == NULL)
135  {
136  mTailNode = NULL;
137  }
138  mHeadNode = mHeadNode->next;
139  }
140  return tmp;
141  }
142 
143 private:
144  InputQueueNode* mHeadNode;
145  InputQueueNode* mTailNode;
146 
147  template<class TTopicState>
148  InputQueueNode* GetQueueNode()
149  {
150  static uint8_t mInputDispatcherStorage[sizeof(GraphInputDispatcher<TTopicState>)];
151  static InputQueueNode node = InputQueueNode(mInputDispatcherStorage);
152  return &node;
153  }
154 };
155 
156 } // namespace DetectorGraph
157 
158 #endif // DETECTORGRAPH_INCLUDE_GRAPHINPUTQUEUE_LITE_HPP_
Internal - Provide interface for a GraphInputDispatcher
void Enqueue(Topic< TTopicState > &aTopic, const TTopicState &aTopicState)
Manage data and its handler.
Definition: topic.hpp:84
Internal - Provides an bare-bones version of GraphInputQueue
Internal - Push data to the graph
#define DG_ASSERT(condition)
Definition: dgassert.hpp:20