]> git.sesse.net Git - casparcg/blob - core/producer/binding.h
Refactored to use range based for instead of BOOST_FOREACH
[casparcg] / core / producer / binding.h
1 /*
2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
3 *
4 * This file is part of CasparCG (www.casparcg.com).
5 *
6 * CasparCG is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * CasparCG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author: Helge Norberg, helge.norberg@svt.se
20 */
21
22 #pragma once
23
24 #include <functional>
25 #include <memory>
26 #include <vector>
27 #include <string>
28 #include <map>
29 #include <algorithm>
30 #include <type_traits>
31
32 #include <boost/lexical_cast.hpp>
33
34 namespace caspar { namespace core {
35
36 namespace detail {
37
38 struct impl_base : std::enable_shared_from_this<impl_base>
39 {
40         std::vector<std::shared_ptr<impl_base>> dependencies_;
41         mutable std::vector<std::pair<
42                         std::weak_ptr<void>,
43                         std::function<void ()>>> on_change_;
44
45         virtual ~impl_base()
46         {
47         }
48
49         virtual void evaluate() = 0;
50
51         void depend_on(const std::shared_ptr<impl_base>& dependency)
52         {
53                 auto self = shared_from_this();
54
55                 if (dependency->depends_on(self))
56                         throw std::exception("Can't have circular dependencies between bindings");
57
58                 dependency->on_change(self, [=] { evaluate(); });
59                 dependencies_.push_back(dependency);
60         }
61
62         bool depends_on(const std::shared_ptr<impl_base>& other) const
63         {
64                 for (auto& dependency : dependencies_)
65                 {
66                         if (dependency == other)
67                                 return true;
68                         
69                         if (dependency->depends_on(other))
70                                 return true;            
71                 }
72
73                 return false;
74         }
75
76         void on_change(
77                         const std::weak_ptr<void>& dependant,
78                         const std::function<void ()>& listener) const
79         {
80                 on_change_.push_back(std::make_pair(dependant, listener));
81         }
82 };
83
84 }
85
86 template <typename T>
87 class binding
88 {
89 private:
90
91         struct impl : public detail::impl_base
92         {
93                 T value_;
94                 std::function<T ()> expression_;
95
96                 impl()
97                         : value_()
98                 {
99                 }
100
101                 impl(T value)
102                         : value_(value)
103                 {
104                 }
105
106                 template<typename Expr>
107                 impl(const Expr& expression)
108                         : expression_(expression)
109                 {
110                 }
111
112                 T get() const
113                 {
114                         return value_;
115                 }
116
117                 bool bound() const
118                 {
119                         return static_cast<bool>(expression_);
120                 }
121
122                 void set(T value)
123                 {
124                         if (bound())
125                         {
126                                 throw std::exception("Bound value cannot be set");
127                         }
128
129                         if (value == value_)
130                                 return;
131
132                         value_ = value;
133
134                         on_change();
135                 }
136
137                 void evaluate() override
138                 {
139                         if (expression_)
140                         {
141                                 auto new_value = expression_();
142
143                                 if (new_value != value_)
144                                 {
145                                         value_ = new_value;
146                                         on_change();
147                                 }
148                         }
149                 }
150
151                 using impl_base::on_change;
152                 void on_change()
153                 {
154                         auto copy = on_change_;
155
156                         for (int i = static_cast<int>(copy.size()) - 1; i >= 0; --i)
157                         {
158                                 auto strong = copy[i].first.lock();
159
160                                 if (strong)
161                                         copy[i].second();
162                                 else
163                                         on_change_.erase(on_change_.begin() + i);
164                         }
165                 }
166
167                 void bind(const std::shared_ptr<impl>& other)
168                 {
169                         unbind();
170                         depend_on(other);
171                         expression_ = [other]{ return other->get(); };
172                         evaluate();
173                 }
174
175                 void unbind()
176                 {
177                         if (expression_)
178                         {
179                                 expression_ = std::function<T ()>();
180                                 dependencies_.clear();
181                         }
182                 }
183         };
184
185         template<typename> friend class binding;
186
187         std::shared_ptr<impl> impl_;
188 public:
189         binding()
190                 : impl_(new impl)
191         {
192         }
193
194         explicit binding(T value)
195                 : impl_(new impl(value))
196         {
197         }
198
199         // Expr -> T ()
200         template<typename Expr>
201         explicit binding(const Expr& expression)
202                 : impl_(new impl(expression))
203         {
204                 impl_->evaluate();
205         }
206
207         // Expr -> T ()
208         template<typename Expr, typename T2>
209         binding(const Expr& expression, const binding<T2>& dep)
210                 : impl_(new impl(expression))
211         {
212                 depend_on(dep);
213                 impl_->evaluate();
214         }
215
216         // Expr -> T ()
217         template<typename Expr, typename T2, typename T3>
218         binding(
219                         const Expr& expression,
220                         const binding<T2>& dep1,
221                         const binding<T3>& dep2)
222                 : impl_(new impl(expression))
223         {
224                 depend_on(dep1);
225                 depend_on(dep2);
226                 impl_->evaluate();
227         }
228
229         void* identity() const
230         {
231                 return impl_.get();
232         }
233
234         T get() const
235         {
236                 return impl_->get();
237         }
238
239         void set(T value)
240         {
241                 impl_->set(value);
242         }
243
244         void bind(const binding<T>& other)
245         {
246                 impl_->bind(other.impl_);
247         }
248
249         bool bound() const
250         {
251                 return impl_->bound();
252         }
253
254         template<typename T2>
255         void depend_on(const binding<T2>& other)
256         {
257                 impl_->depend_on(other.impl_);
258         }
259
260         binding<T> operator+(T other) const
261         {
262                 return transformed([other](T self) { return self + other; });
263         }
264
265         binding<T> operator+(const binding<T>& other) const
266         {
267                 return composed(other, [](T self, T o) { return self + o; });
268         }
269
270         binding<T>& operator++()
271         {
272                 T new_value = get();
273                 ++new_value;
274
275                 set(new_value);
276
277                 return *this;
278         }
279
280         binding<T> operator++(int)
281         {
282                 binding<T> pre_val(get());
283                 ++*this;
284
285                 return pre_val;
286         }
287
288         binding<T> operator-() const
289         {
290                 return transformed([](T self) { return -self; });
291         }
292
293         binding<T> operator-(const binding<T>& other) const
294         {
295                 return *this + -other;
296         }
297
298         binding<T> operator-(T other) const
299         {
300                 return *this + -other;
301         }
302
303         binding<T>& operator--()
304         {
305                 T new_value = get();
306                 --new_value;
307
308                 set(new_value);
309
310                 return *this;
311         }
312
313         binding<T> operator--(int)
314         {
315                 binding<T> pre_val(get());
316                 --*this;
317
318                 return pre_val;
319         }
320
321         binding<T> operator*(T other) const
322         {
323                 return transformed([other](T self) { return self * other; });
324         }
325
326         binding<T> operator*(const binding<T>& other) const
327         {
328                 return composed(other, [](T self, T o) { return self * o; });
329         }
330
331         binding<T> operator/(T other) const
332         {
333                 return transformed([other](T self) { return self / other; });
334         }
335
336         binding<T> operator/(const binding<T>& other) const
337         {
338                 return composed(other, [](T self, T o) { return self / o; });
339         }
340
341         binding<T> operator%(T other) const
342         {
343                 return transformed([other](T self) { return self % other; });
344         }
345
346         binding<T> operator%(const binding<T>& other) const
347         {
348                 return composed(other, [](T self, T o) { return self % o; });
349         }
350
351         binding<bool> operator==(T other) const
352         {
353                 return transformed([other](T self) { return self == other; });
354         }
355
356         binding<bool> operator==(const binding<T>& other) const
357         {
358                 return composed(other, [](T self, T o) { return self == o; });
359         }
360
361         binding<bool> operator!=(T other) const
362         {
363                 return transformed([other](T self) { return self != other; });
364         }
365
366         binding<bool> operator!=(const binding<T>& other) const
367         {
368                 return composed(other, [](T self, T o) { return self != o; });
369         }
370
371         binding<bool> operator<(T other) const
372         {
373                 return transformed([other](T self) { return self < other; });
374         }
375
376         binding<bool> operator<(const binding<T>& other) const
377         {
378                 return composed(other, [](T self, T o) { return self < o; });
379         }
380
381         binding<bool> operator>(T other) const
382         {
383                 return transformed([other](T self) { return self > other; });
384         }
385
386         binding<bool> operator>(const binding<T>& other) const
387         {
388                 return composed(other, [](T self, T o) { return self > o; });
389         }
390
391         binding<bool> operator<=(T other) const
392         {
393                 return transformed([other](T self) { return self <= other; });
394         }
395
396         binding<bool> operator<=(const binding<T>& other) const
397         {
398                 return composed(other, [](T self, T o) { return self <= o; });
399         }
400
401         binding<bool> operator>=(T other) const
402         {
403                 return transformed([other](T self) { return self >= other; });
404         }
405
406         binding<bool> operator>=(const binding<T>& other) const
407         {
408                 return composed(other, [](T self, T o) { return self >= o; });
409         }
410
411         template<typename T2>
412         typename std::enable_if<
413                         std::is_same<T, T2>::value,
414                         binding<T2>
415                 >::type as() const
416         {
417                 return *this;
418         }
419
420         template<typename T2>
421         typename std::enable_if<
422                         (std::is_arithmetic<T>::value || std::is_same<bool, T>::value) && (std::is_arithmetic<T2>::value || std::is_same<bool, T2>::value) && !std::is_same<T, T2>::value,
423                         binding<T2>
424                 >::type as() const
425         {
426                 return transformed([](T val) { return static_cast<T2>(val); });
427         }
428
429         template<typename T2>
430         typename std::enable_if<
431                         (std::is_same<std::wstring, T>::value || std::is_same<std::wstring, T2>::value) && !std::is_same<T, T2>::value,
432                         binding<T2>
433                 >::type as() const
434         {
435                 return transformed([](T val) { return boost::lexical_cast<T2>(val); });
436         }
437
438         // Func -> R (T self_val)
439         // Returns binding<R>
440         template<typename Func>
441         auto transformed(const Func& func) const -> binding<decltype(func(impl_->value_))>
442         {
443                 typedef decltype(func(impl_->value_)) R;
444                 auto self = impl_;
445
446                 return binding<R>(
447                                 [self, func] { return func(self->get()); },
448                                 *this);
449         }
450
451         // Func -> R (T self_val, T2 other_val)
452         // Returns binding<R>
453         template<typename Func, typename T2>
454         auto composed(const binding<T2> other, const Func& func) const -> binding<decltype(func(impl_->value_, other.impl_->value_))>
455         {
456                 typedef decltype(func(impl_->value_, other.impl_->value_)) R;
457                 auto self = impl_;
458                 auto o = other.impl_;
459
460                 return binding<R>(
461                                 [self, o, func] { return func(self->get(), o->get()); },
462                                 *this,
463                                 other);
464         }
465
466         void unbind()
467         {
468                 impl_->unbind();
469         }
470
471         void on_change(
472                         const std::weak_ptr<void>& dependant,
473                         const std::function<void ()>& listener) const
474         {
475                 impl_->on_change(dependant, listener);
476         }
477
478         std::shared_ptr<void> on_change(
479                         const std::function<void ()>& listener) const
480         {
481                 std::shared_ptr<void> subscription(new char);
482
483                 on_change(subscription, listener);
484                 
485                 return subscription;
486         }
487 private:
488         binding(const std::shared_ptr<impl>& self)
489                 : impl_(self)
490         {
491         }
492 };
493
494 static binding<bool> operator||(const binding<bool>& lhs, const binding<bool>& rhs)
495 {
496         return lhs.composed(rhs, [](bool lhs, bool rhs) { return lhs || rhs; });
497 }
498
499 static binding<bool> operator||(const binding<bool>& lhs, bool rhs)
500 {
501         return lhs.transformed([rhs](bool lhs) { return lhs || rhs; });
502 }
503
504 static binding<bool> operator&&(const binding<bool>& lhs, const binding<bool>& rhs)
505 {
506         return lhs.composed(rhs, [](bool lhs, bool rhs) { return lhs && rhs; });
507 }
508
509 static binding<bool> operator&&(const binding<bool>& lhs, bool rhs)
510 {
511         return lhs.transformed([rhs](bool lhs) { return lhs && rhs; });
512 }
513
514 static binding<bool> operator!(const binding<bool>& self)
515 {
516         return self.transformed([](bool self) { return !self; });
517 }
518
519 template<typename T>
520 class ternary_builder
521 {
522         binding<bool> condition_;
523         binding<T> true_result_;
524 public:
525         ternary_builder(
526                         const binding<bool>& condition, const binding<T>& true_result)
527                 : condition_(condition)
528                 , true_result_(true_result)
529         {
530         }
531
532         binding<T> otherwise(const binding<T>& false_result)
533         {
534                 auto condition = condition_;
535                 auto true_result = true_result_;
536
537                 binding<T> result([condition, true_result, false_result]()
538                 {
539                         return condition.get() ? true_result.get() : false_result.get();                
540                 });
541
542                 result.depend_on(condition);
543                 result.depend_on(true_result);
544                 result.depend_on(false_result);
545
546                 return result;
547         }
548
549         binding<T> otherwise(T false_result)
550         {
551                 return otherwise(binding<T>(false_result));
552         }
553 };
554
555 class when
556 {
557         binding<bool> condition_;
558 public:
559         when(const binding<bool>& condition)
560                 : condition_(condition)
561         {
562         }
563
564         template<typename T>
565         ternary_builder<T> then(const binding<T>& true_result)
566         {
567                 return ternary_builder<T>(condition_, true_result);
568         }
569
570         template<typename T>
571         ternary_builder<T> then(T true_result)
572         {
573                 return then(binding<T>(true_result));
574         }
575 };
576
577 template<typename T, typename T2>
578 binding<T> add_tween(
579                 const binding<T>& to_tween,
580                 const binding<T2>& counter,
581                 T destination_value,
582                 T2 duration,
583                 const std::wstring& easing)
584 {
585         tweener tween(easing);
586         
587         double start_val = to_tween.as<double>().get();
588         double destination_val = static_cast<double>(destination_value);
589         double start_time = counter.as<double>().get();
590         double dur = static_cast<double>(duration);
591
592         return when(counter < duration)
593                 .then(counter.as<double>().transformed([=](double t)
594                 {
595                         return tween(t - start_time, start_val, destination_val, dur);
596                 }).as<T>())
597                 .otherwise(destination_value);
598 }
599
600 template<typename T, typename T2>
601 binding<T> delay(
602                 const binding<T>& to_delay,
603                 const binding<T>& after_delay,
604                 const binding<T2>& counter,
605                 T2 duration)
606 {
607         return when(counter < duration)
608                         .then(to_delay)
609                         .otherwise(after_delay);
610 }
611
612 }}