expression_tree  3.2
 All Classes Files Functions Variables Typedefs Pages
expression_tree.h
Go to the documentation of this file.
1 /*
2  (C) Copyright Thierry Seegers 2010-2011. Distributed under the following license:
3 
4  Boost Software License - Version 1.0 - August 17th, 2003
5 
6  Permission is hereby granted, free of charge, to any person or organization
7  obtaining a copy of the software and accompanying documentation covered by
8  this license (the "Software") to use, reproduce, display, distribute,
9  execute, and transmit the Software, and to prepare derivative works of the
10  Software, and to permit third-parties to whom the Software is furnished to
11  do so, all subject to the following:
12 
13  The copyright notices in the Software and this entire statement, including
14  the above license grant, this restriction and the following disclaimer,
15  must be included in all copies of the Software, in whole or in part, and
16  all derivative works of the Software, unless such copies or derivative
17  works are solely in the form of machine-executable object code generated by
18  a source language processor.
19 
20  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
23  SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
24  FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
25  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  DEALINGS IN THE SOFTWARE.
27 */
28 
29 #if !defined(EXPRESSION_TREE_H)
30  #define EXPRESSION_TREE_H
31 
32 #include <functional>
33 #include <future>
34 #include <memory>
35 
36 namespace expression_tree
37 {
38 
39 template<typename T, template<typename, typename> class CachingPolicy, class ThreadingPolicy>
40 class node;
41 
42 namespace detail
43 {
44 
48 template<typename T>
49 struct operation
50 {
51  typedef typename std::function<T (const T&, const T&)> t;
52 };
53 
54 }
55 
57 struct parallel
58 {
60  template<typename T, template<typename, typename> class C, class E>
61  static T evaluate(const typename detail::operation<T>::t& o, const node<T, C, E>& l, const node<T, C, E>& r)
62  {
63  std::future<T> f = std::async(&node<T, C, E>::evaluate, &l);
64 
65  // Let's not rely on any assumption of parameter evaluation order...
66  T t = r.evaluate();
67 
68  f.wait(); // Workaround GCC bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52988
69 
70  return o(f.get(), t);
71  }
72 };
73 
75 struct sequential
76 {
78  template<typename T, template<typename, typename> class C, class E>
79  static T evaluate(const typename detail::operation<T>::t& o, const node<T, C, E>& l, const node<T, C, E>& r)
80  {
81  return o(l.evaluate(), r.evaluate());
82  }
83 };
84 
85 namespace detail
86 {
87 
89 template<typename T>
90 class node_impl
91 {
92 public:
93  virtual ~node_impl() {}
94 
98  virtual std::unique_ptr<node_impl<T>> clone() const = 0;
99 
104  virtual bool constant() const = 0;
105 
110  virtual T evaluate() const = 0;
111 };
112 
116 template<typename T>
117 class leaf : public node_impl<T>
118 {
119  const T value;
120 
121 public:
125  leaf(const T& value) : value(value) {}
126 
128  leaf(const leaf<T>& other) : value(other.value) {}
129 
130  virtual ~leaf() {}
131 
133  virtual std::unique_ptr<node_impl<T>> clone() const
134  {
135  return std::unique_ptr<leaf<T>>(new leaf<T>(*this));
136  }
137 
139  virtual bool constant() const
140  {
141  return true;
142  }
143 
145  virtual T evaluate() const
146  {
147  return value;
148  }
149 };
150 
154 template<typename T>
155 class leaf<T*> : public node_impl<T>
156 {
157  const T *p;
158 
159 public:
163  leaf(const T* p) : p(p) {}
164 
166  leaf(const leaf<T*>& other) : p(other.p) {}
167 
168  virtual ~leaf() {}
169 
171  virtual std::unique_ptr<node_impl<T>> clone() const
172  {
173  return std::unique_ptr<leaf<T*>>(new leaf<T*>(*this));
174  }
175 
177  virtual bool constant() const
178  {
179  return false;
180  }
181 
183  virtual T evaluate() const
184  {
185  return *p;
186  }
187 };
188 
193 template<typename T, template<typename, typename> class CachingPolicy, class ThreadingPolicy>
194 class default_branch : public node_impl<T>
195 {
196 public:
199  typename operation<T>::t f;
200 
207 
209  default_branch(const default_branch<T, CachingPolicy, ThreadingPolicy>& other) : l(other.l), r(other.r) , f(other.f) {}
210 
211  virtual ~default_branch() {}
212 
214  virtual std::unique_ptr<node_impl<T>> clone() const
215  {
216  return std::unique_ptr<default_branch<T, CachingPolicy, ThreadingPolicy>>(new default_branch<T, CachingPolicy, ThreadingPolicy>(*this));
217  }
218 
220  virtual bool constant() const
221  {
222  return l.constant() && r.constant();
223  }
224 
226  virtual T evaluate() const
227  {
228  return ThreadingPolicy::evaluate(f, l, r);
229  }
230 
233  {
234  return l;
235  }
236 
239  {
240  return r;
241  }
242 
245  virtual void grow()
246  {
247  return;
248  }
249 };
250 
251 }
252 
253 template<typename T, class ThreadingPolicy>
254 struct no_caching;
255 
260 template<typename T, template<typename, typename> class CachingPolicy = no_caching, class ThreadingPolicy = sequential>
261 class node
262 {
263  std::unique_ptr<detail::node_impl<T>> impl;
265 
266 public:
270  node(node<T, CachingPolicy, ThreadingPolicy> *parent = 0) : impl(nullptr), parent(parent) {}
271 
273  node(const node<T, CachingPolicy, ThreadingPolicy>& other) : impl(other.impl ? other.impl->clone() : nullptr), parent(other.parent) {}
274 
277  {
278  if(this != &other)
279  {
280  impl = other.impl->clone();
281  parent = other.parent;
282 
283  if(parent)
284  {
285  parent->grow();
286  }
287  }
288 
289  return *this;
290  }
291 
292  virtual ~node()
293  {}
294 
300  {
301  impl.reset(new detail::leaf<T>(t));
302 
303  if(parent)
304  {
305  parent->grow();
306  }
307 
308  return *this;
309  }
310 
316  {
317  impl.reset(new detail::leaf<T*>(t));
318 
319  if(parent)
320  {
321  parent->grow();
322  }
323 
324  return *this;
325  }
326 
332  {
333  // Create a new branch with the passed operation and two nodes with this node as their parent.
334  impl.reset(new typename CachingPolicy<T, ThreadingPolicy>::branch(f, node<T, CachingPolicy, ThreadingPolicy>(this), node<T, CachingPolicy, ThreadingPolicy>(this)));
335 
336  if(parent)
337  {
338  parent->grow();
339  }
340 
341  return *this;
342  }
343 
348  {
349  return dynamic_cast<typename CachingPolicy<T, ThreadingPolicy>::branch*>(impl.get())->left();
350  }
351 
356  {
357  return dynamic_cast<typename CachingPolicy<T, ThreadingPolicy>::branch*>(impl.get())->right();
358  }
359 
361  bool constant() const
362  {
363  return impl ? impl->constant() : false;
364  }
365 
367  T evaluate() const
368  {
369  return impl->evaluate();
370  }
371 
375  void grow()
376  {
377  dynamic_cast<typename CachingPolicy<T, ThreadingPolicy>::branch*>(impl.get())->grow();
378 
379  if(parent)
380  {
381  parent->grow();
382  }
383  }
384 };
385 
387 template<typename T, class ThreadingPolicy>
389 {
394  class branch : public detail::default_branch<T, expression_tree::no_caching, ThreadingPolicy>
395  {
396  public:
399  : detail::default_branch<T, expression_tree::no_caching, ThreadingPolicy>(f, l, r) {}
400 
402  branch(const branch& o) : detail::default_branch<T, expression_tree::no_caching, ThreadingPolicy>(o) {}
403 
404  virtual ~branch() {}
405  };
406 };
407 
409 template<typename T, class ThreadingPolicy>
411 {
416  class branch : public detail::default_branch<T, expression_tree::cache_on_evaluation, ThreadingPolicy>
417  {
418  mutable bool cached;
419  mutable T value;
420 
425 
426  public:
429  : detail::default_branch<T, expression_tree::cache_on_evaluation, ThreadingPolicy>(f, l, r), cached(false) {}
430 
432  branch(const branch& o) : detail::default_branch<T, expression_tree::cache_on_evaluation, ThreadingPolicy>(o), cached(o.cached), value(o.value) {}
433 
434  virtual ~branch() {}
435 
439  virtual T evaluate() const
440  {
441  if(cached) return value;
442 
443  value = ThreadingPolicy::evaluate(f, l, r);
444 
445  if(constant())
446  {
447  cached = true;
448  }
449 
450  return value;
451  }
452 
454  virtual void grow()
455  {
456  cached = false;
457  }
458  };
459 };
460 
462 template<typename T, class ThreadingPolicy>
464 {
469  class branch : public detail::default_branch<T, expression_tree::cache_on_assignment, ThreadingPolicy>
470  {
471  mutable bool cached;
472  mutable T value;
473 
478 
479  public:
482  : detail::default_branch<T, expression_tree::cache_on_assignment, ThreadingPolicy>(f, l, r), cached(false) {}
483 
485  branch(const branch& o) : detail::default_branch<T, expression_tree::cache_on_assignment, ThreadingPolicy>(o), cached(o.cached), value(o.value) {}
486 
487  virtual ~branch() {}
488 
490  virtual T evaluate() const
491  {
492  if(cached) return value;
493 
494  return value = ThreadingPolicy::evaluate(f, l, r);
495  }
496 
499  virtual void grow()
500  {
501  if(constant())
502  {
503  // If this node is constant, cache its value now.
504  cached = true;
505  value = ThreadingPolicy::evaluate(f, l, r);
506  }
507  else
508  {
509  // One or both children are not constant. This node is then not constant.
510  cached = false;
511  }
512  }
513  };
514 };
515 
526 template<typename T, template<typename, typename> class CachingPolicy = no_caching, class ThreadingPolicy = sequential>
527 class tree : public node<T, CachingPolicy, ThreadingPolicy>
528 {
529 public:
530  virtual ~tree() {}
531 
534  {
535  return *this;
536  }
537 };
538 
539 }
540 
541 #endif
542