]> git.sesse.net Git - casparcg/blob - core/producer/binding.h
work in progress changes
[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 <map>
28 #include <algorithm>
29
30 namespace caspar { namespace core {
31
32 template <typename T>
33 class binding
34 {
35 private:
36         struct impl_base : std::enable_shared_from_this<impl_base>
37         {
38                 std::vector<std::shared_ptr<impl_base>> dependencies_;
39                 mutable std::vector<std::pair<
40                                 std::weak_ptr<void>,
41                                 std::function<void ()>>> on_change_;
42
43                 virtual ~impl_base()
44                 {
45                 }
46
47                 virtual void evaluate() = 0;
48
49                 void depend_on(const std::shared_ptr<impl_base>& dependency)
50                 {
51                         dependency->on_change(shared_from_this(), [=] { evaluate(); });
52                         dependencies_.push_back(dependency);
53                 }
54
55                 void on_change(
56                                 const std::weak_ptr<void>& dependant,
57                                 const std::function<void ()>& listener) const
58                 {
59                         on_change_.push_back(std::make_pair(dependant, listener));
60                 }
61         };
62
63         struct impl : public impl_base
64         {
65                 T value_;
66                 std::function<T ()> expression_;
67
68                 impl()
69                         : value_()
70                 {
71                 }
72
73                 impl(T value)
74                         : value_(value)
75                 {
76                 }
77
78                 impl(const std::function<T ()>& expression)
79                         : expression_(expression)
80                 {
81                 }
82
83                 T get() const
84                 {
85                         return value_;
86                 }
87
88                 bool bound() const
89                 {
90                         return static_cast<bool>(expression_);
91                 }
92
93                 void set(T value)
94                 {
95                         if (bound())
96                         {
97                                 throw std::exception("Bound value cannot be set");
98                         }
99
100                         if (value == value_)
101                                 return;
102
103                         value_ = value;
104
105                         on_change();
106                 }
107
108                 void evaluate() override
109                 {
110                         if (expression_)
111                         {
112                                 auto new_value = expression_();
113
114                                 if (new_value != value_)
115                                 {
116                                         value_ = new_value;
117                                         on_change();
118                                 }
119                         }
120                 }
121
122                 using impl_base::on_change;
123                 void on_change()
124                 {
125                         auto copy = on_change_;
126
127                         for (int i = static_cast<int>(copy.size()) - 1; i >= 0; --i)
128                         {
129                                 auto strong = copy[i].first.lock();
130
131                                 if (strong)
132                                         copy[i].second();
133                                 else
134                                         on_change_.erase(on_change_.begin() + i);
135                         }
136                 }
137
138                 void bind(const std::shared_ptr<impl>& other)
139                 {
140                         unbind();
141                         depend_on(other);
142                         expression_ = [&]{ return other.get(); }
143                         evaluate();
144                 }
145
146                 void unbind()
147                 {
148                         if (expression_)
149                         {
150                                 expression_ = std::function<T ()>();
151                                 dependencies_.clear();
152                         }
153                 }
154         };
155
156         std::shared_ptr<impl> impl_;
157 public:
158         binding()
159                 : impl_(new impl)
160         {
161         }
162
163         explicit binding(T value)
164                 : impl_(new impl(value))
165         {
166         }
167
168         template<typename T2>
169         binding(const std::function<T ()>& expression, const binding<T2>& dep)
170                 : impl_(new impl(expression))
171         {
172                 depend_on(dep);
173                 impl_->evaluate();
174         }
175
176         template<typename T2, typename T3>
177         binding(
178                         const std::function<T ()>& expression,
179                         const binding<T2>& dep1,
180                         const binding<T3>& dep2)
181                 : impl_(new impl(expression))
182         {
183                 depend_on(dep1);
184                 depend_on(dep2);
185                 impl_->evaluate();
186         }
187
188         T get() const
189         {
190                 return impl_->get();
191         }
192
193         void set(T value)
194         {
195                 impl_->set(value);
196         }
197
198         void bind(const binding<T>& other)
199         {
200                 impl_->bind(other.impl_);
201         }
202
203         bool bound() const
204         {
205                 return impl_->bound();
206         }
207
208         void depend_on(const binding<T>& other)
209         {
210                 impl_->depend_on(other.impl_);
211         }
212
213         binding<T> operator+(T other) const
214         {
215                 auto self = impl_;
216
217                 return binding<T>(
218                                 [other, self] { return other + self->get(); },
219                                 *this);
220         }
221
222         binding<T> operator+(const binding<T>& other) const
223         {
224                 auto self = impl_;
225                 auto o = other.impl_;
226
227                 return binding<T>(
228                                 [self, o] { return o->get() + self->get(); },
229                                 *this,
230                                 other);
231         }
232
233         binding<T> operator-() const
234         {
235                 auto self = impl_;
236
237                 return binding<T>(
238                                 [self] { return -self->get(); },
239                                 *this);
240         }
241
242         binding<T> operator-(const binding<T>& other) const
243         {
244                 return *this + -other;
245         }
246
247         binding<T> operator-(T other) const
248         {
249                 return *this + -other;
250         }
251
252         binding<T> operator*(T other) const
253         {
254                 auto self = impl_;
255
256                 return binding<T>(
257                                 [other, self] { return other * self->get(); },
258                                 *this);
259         }
260
261         binding<T> operator*(const binding<T>& other) const
262         {
263                 auto self = impl_;
264                 auto o = other.impl_;
265
266                 return binding<T>(
267                                 [self, o] { return o->get() * self->get(); },
268                                 *this,
269                                 other);
270         }
271
272         binding<T> operator/(T other) const
273         {
274                 auto self = impl_;
275
276                 return binding<T>(
277                                 [other, self] { return self->get() / other; },
278                                 *this);
279         }
280
281         binding<T> operator/(const binding<T>& other) const
282         {
283                 auto self = impl_;
284                 auto o = other.impl_;
285
286                 return binding<T>(
287                                 [self, o] { return self->get() / o->get(); },
288                                 *this,
289                                 other);
290         }
291
292         binding<bool> operator==(T other) const
293         {
294                 auto self = impl_;
295
296                 return binding<bool>(
297                                 [other, self] { return self->get() == other; },
298                                 *this);
299         }
300
301         binding<bool> operator==(const binding<T>& other) const
302         {
303                 auto self = impl_;
304                 auto o = other.impl_;
305
306                 return binding<bool>(
307                                 [self, o] { return self->get() == o->get(); },
308                                 *this,
309                                 other);
310         }
311
312         binding<bool> operator!=(T other) const
313         {
314                 auto self = impl_;
315
316                 return binding<bool>(
317                                 [other, self] { return self->get() != other; },
318                                 *this);
319         }
320
321         binding<bool> operator!=(const binding<T>& other) const
322         {
323                 auto self = impl_;
324                 auto o = other.impl_;
325
326                 return binding<bool>(
327                                 [self, o] { return self->get() != o->get(); },
328                                 *this,
329                                 other);
330         }
331
332         void unbind()
333         {
334                 impl_->unbind();
335         }
336
337         void on_change(
338                         const std::weak_ptr<void> dependant,
339                         const std::function<void ()>& listener) const
340         {
341                 impl_->on_change(dependant, listener);
342         }
343
344         std::shared_ptr<void> on_change(
345                         const std::function<void ()>& listener) const
346         {
347                 std::shared_ptr<void> subscription(new char);
348
349                 on_change(subscription, listener);
350                 
351                 return subscription;
352         }
353 private:
354         binding(const std::shared_ptr<impl>& self)
355                 : impl_(self)
356         {
357         }
358 };
359
360 }}