Live Cells C++
Reactive Programming for C++
Loading...
Searching...
No Matches
watcher.hpp
1/*
2 * live_cells_cpp
3 * Copyright (C) 2024 Alexander Gutev <alex.gutev@gmail.com>
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License"); you
6 * may not use this file except in compliance with the License. You
7 * may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * permissions and limitations under the License.
16 */
17
18#ifndef LIVE_CELLS_WATCHER_HPP
19#define LIVE_CELLS_WATCHER_HPP
20
21#include <utility>
22#include <memory>
23#include <unordered_set>
24
25#include "keys.hpp"
26#include "observable.hpp"
27#include "tracker.hpp"
28
29namespace live_cells {
30
38 class watcher : public std::enable_shared_from_this<watcher> {
39 public:
40
52 template <typename F>
53 watcher(F callback) :
55 std::static_pointer_cast<base_observer>(
56 std::make_shared<watch_observer<F>>(callback)
57 )
58 ) {
59 observer->init();
60 }
61
62 watcher(const watcher &) = delete;
63
68 stop();
69 }
70
71 watcher &operator=(const watcher &) = delete;
72
79 void stop() {
80 observer->stop();
81 }
82
83 private:
84
88 struct base_observer : public observer, public std::enable_shared_from_this<base_observer> {
89
91 std::unordered_set<cell> arguments;
92
93 virtual ~base_observer() = default;
94
98 virtual void init() = 0;
99
106 void stop() {
107 for (auto arg : arguments) {
108 arg.remove_observer(
109 std::static_pointer_cast<observer>(this->shared_from_this())
110 );
111 }
112
113 arguments.clear();
114 }
115 };
116
121 template <typename F>
122 struct watch_observer : public base_observer {
124 const F callback;
125
126 watch_observer(F callback) : callback(callback) {}
127
128 watch_observer(const watch_observer &) = delete;
129
130 void init() override {
131 call_with_tracker();
132 }
133
138 bool is_updating = false;
139
144 bool waiting_for_change = false;
145
146
147 /* observer methods */
148
149 void will_update(const key_ref &k) override {
150 if (!is_updating) {
151 is_updating = true;
152 waiting_for_change = false;
153 }
154 }
155
156 void update(const key_ref &k, bool changed) override {
157 if (is_updating || (changed && waiting_for_change)) {
158 is_updating = false;
159 waiting_for_change = !changed;
160
161 if (changed) {
162 call_with_tracker();
163 }
164 }
165 }
166
171 void call_with_tracker() {
172 auto t = argument_tracker::global().with_tracker([this] (auto cell) {
173 if (!this->arguments.count(cell)) {
174 this->arguments.emplace(cell);
175 cell.add_observer(
176 std::static_pointer_cast<observer>(this->shared_from_this())
177 );
178 }
179 });
180
181 try {
182 callback();
183 }
184 catch (...) {
185 // TODO: Log exception to stderr in debug mode
186 // Prevent exception from being propagated to caller
187 }
188 }
189 };
190
192 std::shared_ptr<base_observer> observer;
193 };
194
211 template <typename F>
212 std::shared_ptr<watcher> watch(F fn) {
213 auto w = std::make_shared<watcher>(fn);
214
215 return w;
216 }
217
218} // live_cells
219
220#endif /* LIVE_CELLS_WATCHER_HPP */
static argument_tracker & global()
Definition tracker.hpp:99
A computed cell which determines its argument cells at runtime.
Definition dynamic_compute_cell.hpp:153
Defines the interface for observing changes to the value of a Cell.
Definition types.hpp:32
Handle for a cell watch function.
Definition watcher.hpp:38
void stop()
Remove the watch function.
Definition watcher.hpp:79
watcher(F callback)
Register the cell watch function callback.
Definition watcher.hpp:53
~watcher()
Remove the registered cell watch function.
Definition watcher.hpp:67
Definition boolean.hpp:26
std::shared_ptr< watcher > watch(F fn)
Register a cell watch function.
Definition watcher.hpp:212