Live Cells C++
Reactive Programming for C++
Loading...
Searching...
No Matches
observable.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_OBSERVABLE_H
19#define LIVE_CELLS_OBSERVABLE_H
20
21#include <concepts>
22
23#include "keys.hpp"
24#include "types.hpp"
25
26namespace live_cells {
27
28 namespace internal {
29
33 struct ref_base {
34 virtual ~ref_base() = default;
35
36 virtual void add_observer(observer::ref obs) = 0;
37 virtual void remove_observer(observer::ref obs) = 0;
38
39 virtual key_ref key() const = 0;
40 };
41
45 template <typename T>
46 struct typed_ref_base : ref_base {
47 virtual T value() const = 0;
48 virtual T operator()() const = 0;
49 };
50
54 template <typename T>
55 struct mutable_cell_ref {
56 virtual ~mutable_cell_ref() = default;
57 virtual void value(T value) = 0;
58 };
59
63 template <Cell O>
64 struct typed_ref : typed_ref_base<typename O::value_type> {
65 O observable;
66
67 typed_ref(O obs) : observable(obs) {}
68
69 void add_observer(observer::ref obs) override {
70 observable.add_observer(obs);
71 }
72
73 void remove_observer(observer::ref obs) override {
74 observable.remove_observer(obs);
75 }
76
77 key_ref key() const override {
78 return observable.key();
79 }
80
81 typename O::value_type value() const override {
82 return observable.value();
83 }
84
85 typename O::value_type operator()() const override {
86 return observable();
87 }
88 };
89
90 template <MutableCell C>
91 struct typed_ref<C> : typed_ref_base<typename C::value_type>, mutable_cell_ref<typename C::value_type> {
92 C observable;
93
94 typed_ref(C obs) : observable(obs) {}
95
96 void add_observer(observer::ref obs) override {
97 observable.add_observer(obs);
98 }
99
100 void remove_observer(observer::ref obs) override {
101 observable.remove_observer(obs);
102 }
103
104 key_ref key() const override {
105 return observable.key();
106 }
107
108 typename C::value_type value() const override {
109 return observable.value();
110 }
111
112 void value(typename C::value_type value) override {
113 observable.value(value);
114 }
115
116 typename C::value_type operator()() const override {
117 return observable();
118 }
119 };
120
121 } // internal
122
123 template <typename T>
124 class typed_cell;
125
133 class cell {
134 public:
140 template <Cell O>
142 obs_ref(std::static_pointer_cast<internal::ref_base>(std::make_shared<internal::typed_ref<O>>(o))) {}
143
149 template <typename T>
151 obs_ref(std::static_pointer_cast<internal::ref_base>(c.ref)) {
152 }
153
162
175
182 key_ref key() const {
183 return obs_ref->key();
184 }
185
196 template <typename T>
197 T value() const {
198 auto &base = *obs_ref;
199 auto &typed = dynamic_cast<internal::typed_ref_base<T>&>(base);
200
201 return typed.value();
202 }
203
214 template <typename T>
215 void value(T value) {
216 auto &base = *obs_ref;
217 auto &typed = dynamic_cast<internal::mutable_cell_ref<T>&>(base);
218
219 typed.value(value);
220 }
221
233 template <typename T>
234 T operator()() const {
235 auto &base = *obs_ref;
236 auto &typed = dynamic_cast<internal::typed_ref_base<T>&>(base);
237
238 return typed();
239 }
240
241 protected:
242
247 std::shared_ptr<internal::ref_base> obs_ref;
248
249 template <typename T>
250 friend class typed_cell;
251 };
252
258 struct bad_typed_cell_cast : std::exception {
259 const char *what() const noexcept override {
260 return "Attempt to cast a `cell` to a `typed_cell<>` with a value type"
261 " that is incompatible with the cell's value type.";
262 }
263 };
264
275 template <typename T>
277 public:
283 template <TypedCell<T> C>
285 ref(std::static_pointer_cast<internal::typed_ref_base<T>>(std::make_shared<internal::typed_ref<C>>(cell))) {
286 }
287
298 ref(std::dynamic_pointer_cast<internal::typed_ref_base<T>>(c.obs_ref)) {
299
300 if (!ref) {
301 throw bad_typed_cell_cast();
302 }
303 }
304
311 ref->add_observer(obs);
312 }
313
324 ref->remove_observer(obs);
325 }
326
333 key_ref key() const {
334 return ref->key();
335 }
336
342 T value() const {
343 return ref->value();
344 }
345
354 void value(T value) {
355 auto &base = *ref;
356 auto &typed = dynamic_cast<internal::mutable_cell_ref<T>&>(base);
357
358 typed.value(value);
359 }
360
367 T operator()() const {
368 return ref();
369 }
370
371 private:
376 std::shared_ptr<internal::typed_ref_base<T>> ref;
377
378 friend class cell;
379 };
380
391 inline bool operator==(const cell &a, const cell &b) {
392 return a.key() == b.key();
393 }
394
406 inline bool operator!=(const cell &a, const cell &b) {
407 return !(a == b);
408 }
409
410
421 template <typename T1, typename T2>
422 inline bool operator==(const typed_cell<T1> &a, const typed_cell<T2> &b) {
423 return a.key() == b.key();
424 }
425
437 template <typename T1, typename T2>
438 inline bool operator!=(const typed_cell<T1> &a, const typed_cell<T2> &b) {
439 return !(a == b);
440 }
441
442} // live_cells
443
444
445template<>
446struct std::hash<live_cells::cell> {
447 std::size_t operator()(const live_cells::cell &a) const noexcept {
448 return a.key()->hash();
449 }
450};
451
452template<typename T>
453struct std::hash<live_cells::typed_cell<T>> {
454 std::size_t operator()(const live_cells::typed_cell<T> &a) const noexcept {
455 return a.key()->hash();
456 }
457};
458
459#endif /* LIVE_CELLS_OBSERVABLE_H */
Dynamically typed Cell container.
Definition observable.hpp:133
T value() const
Get the value held by the underlying Cell.
Definition observable.hpp:197
void value(T value)
Set the value of the underlying Cell.
Definition observable.hpp:215
cell(O o)
Create a container holding the Cell o.
Definition observable.hpp:141
void remove_observer(observer::ref obs)
Remove an observer from the underlying Cell.
Definition observable.hpp:172
bool operator!=(const cell &a, const cell &b)
Compare two cell's by their keys.
Definition observable.hpp:406
bool operator==(const cell &a, const cell &b)
Compare two cell's by their keys.
Definition observable.hpp:391
void add_observer(observer::ref obs)
Add an observer to the underlying Cell.
Definition observable.hpp:159
std::shared_ptr< internal::ref_base > obs_ref
Pointer to the container holding the underlying cell.
Definition observable.hpp:247
T operator()() const
Get the value held by the underlying Cell and track it as a dependency.
Definition observable.hpp:234
cell(typed_cell< T > c)
Create a container holding the Cell held in c.
Definition observable.hpp:150
key_ref key() const
Get the key that uniquely identifies the underlying Cell.
Definition observable.hpp:182
A computed cell which determines its argument cells at runtime.
Definition dynamic_compute_cell.hpp:153
Dynamically type key container.
Definition keys.hpp:76
std::shared_ptr< observer > ref
Shared pointer to an observer.
Definition types.hpp:37
void add_observer(observer::ref o) const
Add an observer to the cell.
Definition stateful_cell.hpp:83
key_ref key() const
Get the key identifying the cell.
Definition stateful_cell.hpp:74
void remove_observer(observer::ref o) const
Remove an observer from the cell.
Definition stateful_cell.hpp:92
Dynamically typed Cell container with a static value type.
Definition observable.hpp:276
typed_cell(cell c)
Create a container holding the Cell held in c.
Definition observable.hpp:297
typed_cell(C cell)
Create a container holding the Cell cell.
Definition observable.hpp:284
void value(T value)
Set the value of the underlying Cell.
Definition observable.hpp:354
void add_observer(observer::ref obs)
Add an observer to the underlying Cell.
Definition observable.hpp:310
void remove_observer(observer::ref obs)
Remove an observer from the underlying Cell.
Definition observable.hpp:323
bool operator==(const typed_cell< T1 > &a, const typed_cell< T2 > &b)
Compare two typed_cell's by their keys.
Definition observable.hpp:422
T value() const
Get the value held by the underlying Cell.
Definition observable.hpp:342
key_ref key() const
Get the key that uniquely identifies the underlying Cell.
Definition observable.hpp:333
bool operator!=(const typed_cell< T1 > &a, const typed_cell< T2 > &b)
Compare two typed_cell's by their keys.
Definition observable.hpp:438
T operator()() const
Get the value held by the underlying Cell and track it as a dependency.
Definition observable.hpp:367
Definition boolean.hpp:26
constant_cell< T > value(const T &value)
Definition constant_cell.hpp:132
Exception thrown when attempting to cast a cell to a typed_cell with a value type that is incompatibl...
Definition observable.hpp:258