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