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