MT Showcase SDK
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Pages
GraphGenerators.hpp
1 #pragma once
2 
3 #include "Export.hpp"
4 
5 #include "BackendComponents.hpp"
6 #include "Events.hpp"
7 
8 #include <folly/MoveWrapper.h>
9 
10 #include <queue>
11 
12 namespace Showcase
13 {
14 
17  class SHOWCASE_API GraphGenerator : public Generator<NodeEvent>
18  {
19  public:
21 
26  virtual QString protocol() const = 0;
27 
33  virtual bool init(const GraphNode& n);
34 
35  const GraphNode& node() const;
36 
37  private:
38  GraphNode m_node;
39  };
40  typedef std::shared_ptr<GraphGenerator> GraphGeneratorPtr;
41 
42 
43  // --------------------------------------------------------------------
44 
45 
47  class SHOWCASE_API PropertyGenerator : public Generator<PropertyEvent>
48  {
49  public:
51 
52  virtual QString protocol() const = 0;
53 
59  virtual bool init(const GraphNode& n);
60 
66  virtual bool init(const GraphEdge& e);
67 
74  virtual bool init(const PropertyEvent&) { return false; }
75 
76  bool isEdgeGenerator() const;
77  const NodeId& sourceNode() const;
78  const NodeId& targetNode() const;
79  const EdgeId& edgeId() const;
80 
81  private:
82  EdgeId m_targetId;
83  bool m_isEdgeGenerator;
84  };
85  typedef std::shared_ptr<PropertyGenerator> PropertyGeneratorPtr;
86 
87  // --------------------------------------------------------------------
88 
92  template <typename EventGenerator>
93  class EmptyEventGenerator : public EventGenerator
94  {
95  public:
96  typedef typename EventGenerator::ValueType Event;
97 
98  EmptyEventGenerator() : m_eventsSent(0) {}
99 
100  virtual QString protocol() const override { return QString(); }
101 
102  virtual folly::Future<typename EventGenerator::ValueType>
103  next(folly::Executor* executor = nullptr) override
104  {
105  int sent = m_eventsSent++;
106  if(sent == 0) {
107  if(executor) {
108  return folly::via(executor, [] { return Event(); });
109  } else {
110  return folly::makeFuture(Event());
111  }
112  } else {
113  if(sent > 1) {
114  m_promise.setValue(Event());
115  }
116  m_promise = folly::Promise<typename EventGenerator::ValueType>();
117  return m_promise.getFuture();
118  }
119  }
120 
121  private:
122  int m_eventsSent;
123  folly::Promise<typename EventGenerator::ValueType> m_promise;
124  };
125 
128 
129  // --------------------------------------------------------------------
130 
131  class Notifiable
132  {
133  public:
134  virtual void changeObserved() = 0;
135  virtual ~Notifiable() = default;
136  };
137 
154  template <typename GeneratorType>
155  class CachingGenerator : public GeneratorType, public Notifiable
156  {
157  public:
158  static_assert(IsGenerator<GeneratorType>::value,
159  "Need to use Generator or its subclass as a type "
160  "parameter for SynchronousGenerator.");
161  typedef typename GeneratorType::ValueType ValueType;
162 
163  virtual folly::Future<ValueType> next(folly::Executor* executor = nullptr) override;
164  virtual void changeObserved() override;
165 
166  protected:
167  virtual bool hasEventsInCache() const = 0;
168  virtual ValueType nextEvent() = 0;
169  virtual void updateCache() = 0;
170 
171  private:
172  std::mutex m_mutex;
173 
174  class Promised
175  {
176  public:
177  Promised(folly::Promise<ValueType>&& p, folly::Executor* exec)
178  : promise(std::move(p)), executor(exec) {}
179  Promised(Promised&& other) = default;
180  folly::Promise<ValueType> promise;
181  folly::Executor* executor = nullptr;
182  };
183  std::queue<Promised> m_promises;
184 
185  bool m_pendingCacheUpdate = true;
186  };
187 
188  // --------------------------------------------------------------------
189 
190  template <typename GeneratorType>
191  folly::Future<typename GeneratorType::ValueType>
192  CachingGenerator<GeneratorType>::next(folly::Executor* executor)
193  {
195  auto ptr = this->shared_from_this();
196 
197  std::shared_ptr<Me> me = std::dynamic_pointer_cast<Me>(ptr);
198 
199  if(!me) {
200  if(executor)
201  return folly::via(executor, [] { return ValueType(); });
202  else
203  return folly::makeFuture<ValueType>(ValueType());
204  }
205 
206  std::weak_ptr<Me> weak = me;
207 
208  auto f = [weak] {
209  std::shared_ptr<Me> me = weak.lock();
210  if(!me)
211  return;
212 
213  std::unique_lock<std::mutex> lck(me->m_mutex);
214 
215  if(!me->hasEventsInCache() && me->m_pendingCacheUpdate) {
216  me->m_pendingCacheUpdate = false;
217  me->updateCache();
218  }
219 
220  if(me->hasEventsInCache() && !me->m_promises.empty()) {
221  auto promised = std::move(me->m_promises.front());
222  me->m_promises.pop();
223 
225 
226  auto val = me->nextEvent();
227  lck.unlock();
228  promised.promise.setValue(val);
229  }
230  };
231 
232 
233  folly::Future<ValueType> fut(folly::exception_wrapper(std::runtime_error("empty")));
234  {
235  std::lock_guard<std::mutex> g(m_mutex);
236  folly::Promise<ValueType> promise;
237  fut = promise.getFuture();
238  Promised p(std::move(promise), executor);
239  m_promises.emplace(std::move(p));
240  }
241 
242  if(executor) {
243  executor->add(f);
244  } else {
245  f();
246  }
247  return fut;
248  }
249 
250  template <typename GeneratorType>
252  {
253  std::vector<Promised> promisesToFulfill;
254  std::vector<ValueType> valuesForPromises;
255 
256  {
257  std::unique_lock<std::mutex> lck(m_mutex);
258  m_pendingCacheUpdate = true;
259 
265  if(!hasEventsInCache() && !m_promises.empty()) {
266  updateCache();
267 
268  while(hasEventsInCache() && !m_promises.empty()) {
269  auto promised = std::move(m_promises.front());
270  m_promises.pop();
271  promisesToFulfill.emplace_back(std::move(promised));
272  valuesForPromises.emplace_back(std::move(nextEvent()));
273  }
274  }
275  }
276 
277  for(size_t i = 0; i < promisesToFulfill.size(); ++i) {
278  Promised p = std::move(promisesToFulfill[i]);
279  ValueType val = std::move(valuesForPromises[i]);
280  if(!p.executor) {
281  p.promise.setValue(std::move(val));
282  } else {
283  folly::MoveWrapper<folly::Promise<ValueType>> promise = folly::makeMoveWrapper(std::move(p.promise));
284  folly::MoveWrapper<ValueType> v = folly::makeMoveWrapper(std::move(val));
285  folly::via(p.executor, [promise, v] () mutable {
286  auto& unwrapped = *promise;
287  unwrapped.setValue(v.move());
288  });
289  }
290  }
291  }
292 
293 }