Line data Source code
1 : /**
2 : Copyright (c) 2021 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : #ifndef XENOLITH_SCENE_DIRECTOR_XLSCHEDULER_H_
25 : #define XENOLITH_SCENE_DIRECTOR_XLSCHEDULER_H_
26 :
27 : #include "XLNodeInfo.h"
28 : #include "SPPriorityList.h"
29 : #include "SPSubscription.h"
30 :
31 : namespace STAPPLER_VERSIONIZED stappler::xenolith {
32 :
33 : using SchedulerFunc = Function<void(const UpdateTime &)>;
34 :
35 : struct SchedulerCallback {
36 : SchedulerFunc callback = nullptr;
37 : bool paused = false;
38 : bool removed = false;
39 :
40 1149 : SchedulerCallback() = default;
41 :
42 2535 : SchedulerCallback(SchedulerFunc &&fn, bool p)
43 2535 : : callback(move(fn)), paused(p) { }
44 : };
45 :
46 : class Scheduler : public Ref {
47 : public:
48 : Scheduler();
49 : virtual ~Scheduler();
50 :
51 : bool init();
52 :
53 : void unschedule(const void *);
54 : void unscheduleAll();
55 :
56 : template <typename T>
57 : void scheduleUpdate(T *, int32_t p = 0, bool paused = false);
58 :
59 : void schedulePerFrame(SchedulerFunc &&callback, void *target, int32_t priority, bool paused);
60 :
61 : void update(const UpdateTime &);
62 :
63 : bool isPaused(void *) const;
64 : void resume(void *);
65 : void pause(void *);
66 :
67 : bool empty() const;
68 :
69 : protected:
70 : struct ScheduledTemporary {
71 : SchedulerFunc callback;
72 : void *target;
73 : int32_t priority;
74 : bool paused;
75 : };
76 :
77 : bool _locked = false;
78 : const void *_currentTarget = nullptr;
79 : SchedulerCallback *_currentNode = nullptr;
80 : PriorityList<SchedulerCallback> _list;
81 : Vector<ScheduledTemporary> _tmp;
82 : };
83 :
84 : template <class T = Subscription>
85 : class SchedulerListener {
86 : public:
87 : using Callback = Function<void(Subscription::Flags)>;
88 :
89 : SchedulerListener(Scheduler *s = nullptr, const Callback &cb = nullptr, T *sub = nullptr);
90 : ~SchedulerListener();
91 :
92 : SchedulerListener(const SchedulerListener<T> &);
93 : SchedulerListener &operator= (const SchedulerListener<T> &);
94 :
95 : SchedulerListener(SchedulerListener<T> &&);
96 : SchedulerListener &operator= (SchedulerListener<T> &&);
97 :
98 : SchedulerListener &operator= (T *);
99 :
100 : inline operator T * () { return get(); }
101 : inline operator T * () const { return get(); }
102 : inline operator bool () const { return _binding; }
103 :
104 : inline T * operator->() { return get(); }
105 : inline const T * operator->() const { return get(); }
106 :
107 : void set(T *sub);
108 : T *get() const;
109 :
110 : void setScheduler(Scheduler *);
111 : Scheduler *getScheduler() const;
112 :
113 : void setCallback(const Callback &cb);
114 : const Callback &getCallback() const;
115 :
116 : void setDirty();
117 : void update(const UpdateTime &time);
118 :
119 : void check();
120 :
121 : protected:
122 : void updateScheduler();
123 : void schedule();
124 : void unschedule();
125 :
126 : Scheduler *_scheduler = nullptr;
127 : Binding<T> _binding;
128 : Callback _callback;
129 : bool _dirty = false;
130 : bool _scheduled = false;
131 : };
132 :
133 : template <typename T, typename Enable = void>
134 : class SchedulerUpdate {
135 : public:
136 : static void scheduleUpdate(Scheduler *scheduler, T *target, int32_t p, bool paused) {
137 : scheduler->schedulePerFrame([target] (const UpdateTime &time) {
138 : target->update(time);
139 : }, target, p, paused);
140 : }
141 : };
142 :
143 : template<class T>
144 : class SchedulerUpdate<T, typename std::enable_if<std::is_base_of<Ref, T>::value>::type> {
145 : public:
146 2409 : static void scheduleUpdate(Scheduler *scheduler, T *t, int32_t p, bool paused) {
147 2409 : auto ref = static_cast<Ref *>(t);
148 2409 : auto target = Rc<Ref>(ref);
149 :
150 542011 : scheduler->schedulePerFrame([target = move(target)] (const UpdateTime &time) {
151 269801 : ((T *)target.get())->update(time);
152 : }, t, p, paused);
153 2409 : }
154 : };
155 :
156 : template <typename T>
157 2409 : void Scheduler::scheduleUpdate(T *target, int32_t p, bool paused) {
158 2409 : SchedulerUpdate<T>::scheduleUpdate(this, target, p, paused);
159 2409 : }
160 :
161 :
162 : template <class T>
163 : SchedulerListener<T>::SchedulerListener(Scheduler *s, const Callback &cb, T *sub)
164 : : _scheduler(s), _binding(sub), _callback(cb) {
165 : static_assert(std::is_convertible<T *, Subscription *>::value, "Invalid Type for DataListener<T>!");
166 : updateScheduler();
167 : }
168 :
169 : template <class T>
170 : SchedulerListener<T>::~SchedulerListener() {
171 : unschedule();
172 : }
173 :
174 : template <class T>
175 : SchedulerListener<T>::SchedulerListener(const SchedulerListener<T> &other) : _binding(other._binding), _callback(other._callback) {
176 : updateScheduler();
177 : }
178 :
179 : template <class T>
180 : SchedulerListener<T> &SchedulerListener<T>::operator= (const SchedulerListener<T> &other) {
181 : _binding = other._binding;
182 : _callback = other._callback;
183 : updateScheduler();
184 : return *this;
185 : }
186 :
187 : template <class T>
188 : SchedulerListener<T>::SchedulerListener(SchedulerListener<T> &&other) : _binding(std::move(other._binding)), _callback(std::move(other._callback)) {
189 : other.updateScheduler();
190 : updateScheduler();
191 : }
192 :
193 : template <class T>
194 : SchedulerListener<T> &SchedulerListener<T>::operator= (SchedulerListener<T> &&other) {
195 : _binding = std::move(other._binding);
196 : _callback = std::move(other._callback);
197 : other.updateScheduler();
198 : updateScheduler();
199 : return *this;
200 : }
201 :
202 : template <class T>
203 : void SchedulerListener<T>::set(T *sub) {
204 : if (_binding != sub) {
205 : _binding = Binding<T>(sub);
206 : updateScheduler();
207 : }
208 : }
209 :
210 : template <class T>
211 : SchedulerListener<T> &SchedulerListener<T>::operator= (T *sub) {
212 : set(sub);
213 : return *this;
214 : }
215 :
216 : template <class T>
217 : T *SchedulerListener<T>::get() const {
218 : return _binding;
219 : }
220 :
221 : template <class T>
222 : void SchedulerListener<T>::setScheduler(Scheduler *s) {
223 : unschedule();
224 : _scheduler = s;
225 : updateScheduler();
226 : }
227 :
228 : template <class T>
229 : Scheduler *SchedulerListener<T>::getScheduler() const {
230 : return _scheduler;
231 : }
232 :
233 : template <class T>
234 : void SchedulerListener<T>::setCallback(const Callback &cb) {
235 : _callback = cb;
236 : }
237 :
238 : template <class T>
239 : const Function<void(Subscription::Flags)> &SchedulerListener<T>::getCallback() const {
240 : return _callback;
241 : }
242 :
243 : template <class T>
244 : void SchedulerListener<T>::setDirty() {
245 : _dirty = true;
246 : }
247 :
248 : template <class T>
249 : void SchedulerListener<T>::update(const UpdateTime &time) {
250 : if (_callback && _binding) {
251 : auto val = _binding.check();
252 : if (!val.empty() || _dirty) {
253 : _dirty = false;
254 : _callback(val);
255 : }
256 : }
257 : }
258 :
259 : template <class T>
260 : void SchedulerListener<T>::check() {
261 : update(UpdateTime());
262 : }
263 :
264 : template <class T>
265 : void SchedulerListener<T>::updateScheduler() {
266 : if (_binding && !_scheduled) {
267 : schedule();
268 : } else if (!_binding && _scheduled) {
269 : unschedule();
270 : }
271 : }
272 :
273 : template <class T>
274 : void SchedulerListener<T>::schedule() {
275 : if (_scheduler && _binding && !_scheduled) {
276 : _scheduler->scheduleUpdate(this, 0, false);
277 : _scheduled = true;
278 : }
279 : }
280 :
281 : template <class T>
282 : void SchedulerListener<T>::unschedule() {
283 : if (_scheduled) {
284 : _scheduler->unschedule(this);
285 : _scheduled = false;
286 : }
287 : }
288 :
289 : }
290 :
291 : #endif /* XENOLITH_SCENE_DIRECTOR_XLSCHEDULER_H_ */
|