aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md19
-rw-r--r--cells-impl.hpp63
-rw-r--r--cells-test.cpp37
-rw-r--r--cells.hpp20
4 files changed, 69 insertions, 70 deletions
diff --git a/README.md b/README.md
index 776431e..ff2777d 100644
--- a/README.md
+++ b/README.md
@@ -48,14 +48,13 @@ wherever your compiler can find them and `#include <cells.hpp>`.
The API primarily consists of the `cell<T>` and `formula_cell<T>`
class templates. Using a `formula_cell<T>` is easy: simply construct
-one using `formula_cell<T>::make()` and use the `reset` method to set
-a formula to compute the value of the cell:
+one and use the `reset` method to set a formula to compute the value
+of the cell:
typedef formula_cell<double> fcell;
- typedef shared_ptr<fcell> sfcell;
- sfcell x = fcell::make();
- x->reset([=](){ return 5; });
+ fcell x;
+ x.reset([](){ return 5; });
For convenience, you can also just write something like `x->reset(5);`
for setting a constant value.
@@ -63,8 +62,8 @@ for setting a constant value.
In order to create a dependent cell, simply make use of the other
cell's value in the formula:
- sfcell double_x = fcell::make();
- double_x->reset([=](){ return 2 * x->get(); });
+ fcell double_x;
+ double_x.reset([&](){ return 2 * x.get(); });
From now on, whenever `x` changes, `double_x` will be updated
accordingly.
@@ -72,9 +71,9 @@ accordingly.
You can create change event observers by writing formulas that make
use of an observed cell and return a dummy value:
- sfcell simple_observer = fcell::make();
- simple_observer->reset([=]() -> double {
- (void)double_x->get();
+ fcell simple_observer;
+ simple_observer.reset([&]() -> double {
+ (void)double_x.get();
std::cout << "double_x has changed!" << std::endl;
return 0;
});
diff --git a/cells-impl.hpp b/cells-impl.hpp
index 1a9d644..86d7c98 100644
--- a/cells-impl.hpp
+++ b/cells-impl.hpp
@@ -45,43 +45,45 @@ namespace cells {
using namespace dynvars;
struct dag_node {
- dag_node(std::shared_ptr<observer> item_) : item(item_) { }
- std::shared_ptr<observer> item;
+ dag_node(observer* item_) : item(item_) { }
+ observer* item;
std::unordered_set<dag_node*> incoming_edges;
std::unordered_set<dag_node*> outgoing_edges;
};
struct transaction {
- std::unordered_map<std::shared_ptr<observer>, std::shared_ptr<dag_node>> dag;
+ std::unordered_map<observer*, dag_node*> dag;
};
- static thread_local dynvar<std::forward_list<std::shared_ptr<observer>>> current_dependencies;
+ static thread_local dynvar<std::forward_list<observer*>> current_dependencies;
static thread_local dynvar<transaction> current_transaction;
inline void observer::clear_dependencies() {
for (auto const& dep : dependencies) {
- dep->remove_dependent(this);
+ std::shared_ptr<observer*> sdep = dep.lock();
+ if (sdep) {
+ (*sdep)->remove_dependent(this);
+ }
}
dependencies = {};
}
- inline void observer::add_dependent(std::shared_ptr<observer> dependent) {
- dependents.push_front(dependent);
+ inline void observer::add_dependent(observer* dependent) {
+ dependents.push_front(dependent->self);
}
inline void observer::remove_dependent(observer* dependent) {
- dependents.remove_if([&](std::weak_ptr<observer> const& other) -> bool {
- std::shared_ptr<observer> other2 = other.lock();
- // note: this should also work for empty other
- return (other2.get() == dependent);
+ dependents.remove_if([&](std::weak_ptr<observer*> const& other) -> bool {
+ std::shared_ptr<observer*> other2 = other.lock();
+ return (!other2 || *other2 == dependent);
});
}
- inline void observer::reset_dependencies(std::forward_list<std::shared_ptr<observer>> const& newdeps) {
+ inline void observer::reset_dependencies(std::forward_list<observer*> const& newdeps) {
clear_dependencies();
- dependencies = newdeps;
for (auto const& dep : newdeps) {
- dep->add_dependent(shared_from_this());
+ dependencies.push_front(dep->self);
+ dep->add_dependent(this);
}
}
@@ -90,20 +92,23 @@ namespace cells {
with_transaction([&]() { this->mark(); });
return;
}
- std::shared_ptr<observer> self = shared_from_this();
- if (current_transaction->dag.find(self) ==
+ if (current_transaction->dag.find(this) ==
current_transaction->dag.end()) {
std::unordered_set<dag_node*> incoming_edges;
std::unordered_set<dag_node*> outgoing_edges;
- std::shared_ptr<dag_node> node = std::make_shared<dag_node>(self);
- current_transaction->dag[self] = std::shared_ptr<dag_node>(node);
- for (std::weak_ptr<observer> x : dependents) {
- std::shared_ptr<observer> px = x.lock();
+ dag_node* node = new dag_node(this);
+ current_transaction->dag[this] = node;
+ for (auto e = dependents.cbegin(); e != dependents.end(); e++) {
+ std::weak_ptr<observer*> const& x = *e;
+ std::shared_ptr<observer*> px = x.lock();
if (px) {
- px->mark();
- std::shared_ptr<dag_node> xn = current_transaction->dag[px];
- xn->incoming_edges.insert(node.get());
- node->outgoing_edges.insert(xn.get());
+ (*px)->mark();
+ dag_node* xn = current_transaction->dag[*px];
+ xn->incoming_edges.insert(node);
+ node->outgoing_edges.insert(xn);
+ } else {
+ // Purge dead nodes.
+ dependents.erase(e);
}
}
}
@@ -120,9 +125,9 @@ namespace cells {
template <typename T>
void cell<T>::update() {
T oldval = current_value;
- with<std::forward_list<std::shared_ptr<observer>>, void>
+ with<std::forward_list<observer*>, void>
(current_dependencies,
- std::forward_list<std::shared_ptr<observer>>(),
+ std::forward_list<observer*>(),
[=]{
current_value = recompute(current_value);
reset_dependencies(*current_dependencies);
@@ -132,7 +137,7 @@ namespace cells {
template <typename T>
T& cell<T>::get() {
if (current_dependencies) {
- current_dependencies->push_front(shared_from_this());
+ current_dependencies->push_front(this);
return current_value;
} else {
return current_value;
@@ -188,7 +193,7 @@ namespace cells {
thunk();
//cerr << "; number of affected nodes: " << current_transaction->dag.size() << endl;
- std::deque<std::shared_ptr<observer>> nodes;
+ std::deque<observer*> nodes;
// topological sort
std::forward_list<dag_node*> independent_nodes;
@@ -197,7 +202,7 @@ namespace cells {
for (auto const& o_and_n : current_transaction->dag) {
auto node = o_and_n.second;
if (node->incoming_edges.size() == 0) {
- independent_nodes.push_front(node.get());
+ independent_nodes.push_front(node);
}
}
while (!independent_nodes.empty()) {
diff --git a/cells-test.cpp b/cells-test.cpp
index 1b9147b..a88fe5b 100644
--- a/cells-test.cpp
+++ b/cells-test.cpp
@@ -27,35 +27,28 @@ using std::cout;
using std::endl;
typedef formula_cell<double> fcell;
-typedef shared_ptr<fcell> sfcell;
typedef formula_cell<unit> ucell;
-typedef shared_ptr<ucell> sucell;
int main(int argc, char** argv) {
- sfcell x0 = fcell::make();
- sfcell x1 = fcell::make();
- sfcell x2 = fcell::make();
- sfcell y = fcell::make();
- sfcell z = fcell::make();
- sucell a = ucell::make();
- sucell b = ucell::make();
+ fcell x0, x1, x2, y, z;
+ ucell a, b;
- with_transaction([=](){
- x0->reset(10);
- x1->reset([=](){ return *x0 + 5; });
- x2->reset([=](){ return *x0 * 2; });
- y->reset([=](){ return *x1 * *x2; });
- z->reset([=](){ return *x0 * *y; });
- a->reset([=]() -> unit { cout << "z is now " << *z << "." << endl; return unit(); });
- b->reset([=]() -> unit { cout << "x2 is now " << *x2 << "." << endl; return unit(); });
+ with_transaction([&](){
+ x0.reset(10);
+ x1.reset([&](){ return *x0 + 5; });
+ x2.reset([&](){ return *x0 * 2; });
+ y.reset([&](){ return *x1 * *x2; });
+ z.reset([&](){ return *x0 * *y; });
+ a.reset([&]() -> unit { cout << "z is now " << *z << "." << endl; return unit(); });
+ b.reset([&]() -> unit { cout << "x2 is now " << *x2 << "." << endl; return unit(); });
});
- x0->reset(15);
- x0->reset(-20);
- y->reset(-3);
- x1->reset([=]() { return (double)*x0; });
- y->reset([=]() { return *x1 + *x2; });
+ x0.reset(15);
+ x0.reset(-20);
+ y.reset(-3);
+ x1.reset([&]() { return (double)*x0; });
+ y.reset([&]() { return *x1 + *x2; });
return EXIT_SUCCESS;
}
diff --git a/cells.hpp b/cells.hpp
index efa3f09..4799e69 100644
--- a/cells.hpp
+++ b/cells.hpp
@@ -22,14 +22,16 @@
#include <functional>
#include <memory>
#include <forward_list>
+#include <list>
#include <algorithm>
namespace cells {
- class observer : public virtual std::enable_shared_from_this<observer> {
+ class observer {
private:
- std::forward_list<std::weak_ptr<observer>> dependents;
- std::forward_list<std::shared_ptr<observer>> dependencies;
+ std::shared_ptr<observer*> self;
+ std::list<std::weak_ptr<observer*>> dependents;
+ std::forward_list<std::weak_ptr<observer*>> dependencies;
void clear_dependencies();
void mark_dependents();
@@ -38,9 +40,11 @@ namespace cells {
void mark();
public:
- void add_dependent(std::shared_ptr<observer> dependent);
+ observer() : self(std::make_shared<observer*>(this)) { };
+
+ void add_dependent(observer* dependent);
void remove_dependent(observer* dependent);
- void reset_dependencies(std::forward_list<std::shared_ptr<observer>> const& newdeps);
+ void reset_dependencies(std::forward_list<observer*> const& newdeps);
virtual void update() = 0;
@@ -63,7 +67,7 @@ namespace cells {
T& get();
T& operator *() { return get(); }
//T operator ()() { return get(); }
- operator T() { return get(); }
+ //operator T() { return get(); }
virtual ~cell();
};
@@ -78,13 +82,11 @@ namespace cells {
std::function<T (T old)> alt_formula;
protected:
- formula_cell() { }
virtual T recompute(T);
virtual T init();
public:
- //static std::shared_ptr<formula_cell<T>> make() { return std::make_shared<formula_cell<T>>(); }
- static std::shared_ptr<formula_cell<T>> make() { return std::shared_ptr<formula_cell<T>>(new formula_cell()); }
+ formula_cell() { }
void reset(T value);
void reset(std::function<T ()>);