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