summaryrefslogtreecommitdiff
path: root/src/frp.cpp
diff options
context:
space:
mode:
authorRoman Smrž <roman.smrz@seznam.cz>2021-04-18 22:25:17 +0200
committerRoman Smrž <roman.smrz@seznam.cz>2021-04-18 22:28:59 +0200
commit9aaba1211c95dc7e08437a7cca73452181e296d6 (patch)
treeb11cb72c1515fb7b284e98708d6b6f4a8fbae3ab /src/frp.cpp
parentc3d6046b25ef0786b8d2919dfa9db4eb05114501 (diff)
Initial support for FRP behaviors
Diffstat (limited to 'src/frp.cpp')
-rw-r--r--src/frp.cpp133
1 files changed, 133 insertions, 0 deletions
diff --git a/src/frp.cpp b/src/frp.cpp
new file mode 100644
index 0000000..142fcd4
--- /dev/null
+++ b/src/frp.cpp
@@ -0,0 +1,133 @@
+#include <erebos/frp.h>
+
+#include <condition_variable>
+#include <mutex>
+
+using namespace erebos;
+
+using std::condition_variable;
+using std::move;
+using std::mutex;
+using std::nullopt;
+using std::unique_lock;
+using std::weak_ptr;
+
+mutex bhvTimeMutex;
+condition_variable bhvTimeCond;
+bool bhvTimeRunning = false;
+uint64_t bhvTimeLast = 0;
+
+BhvCurTime::BhvCurTime()
+{
+ unique_lock lock(bhvTimeMutex);
+ bhvTimeCond.wait(lock, []{ return !bhvTimeRunning; });
+
+ bhvTimeRunning = true;
+ t = BhvTime(++bhvTimeLast);
+}
+
+BhvCurTime::~BhvCurTime()
+{
+ if (t) {
+ unique_lock lock(bhvTimeMutex);
+ bhvTimeRunning = false;
+ lock.unlock();
+ bhvTimeCond.notify_one();
+ }
+}
+
+BhvCurTime::BhvCurTime(BhvCurTime && other)
+{
+ t = other.t;
+ other.t = nullopt;
+}
+
+BhvCurTime & BhvCurTime::operator=(BhvCurTime && other)
+{
+ t = other.t;
+ other.t = nullopt;
+ return *this;
+}
+
+
+BhvImplBase::~BhvImplBase() = default;
+
+void BhvImplBase::dependsOn(shared_ptr<BhvImplBase> other)
+{
+ depends.push_back(other);
+ other->rdepends.push_back(shared_from_this());
+}
+
+void BhvImplBase::updated(const BhvCurTime & ctime)
+{
+ vector<shared_ptr<BhvImplBase>> toUpdate;
+ markDirty(ctime, toUpdate);
+
+ for (auto & bhv : toUpdate)
+ bhv->updateDirty(ctime);
+}
+
+void BhvImplBase::markDirty(const BhvCurTime & ctime, vector<shared_ptr<BhvImplBase>> & toUpdate)
+{
+ if (dirty)
+ return;
+
+ if (!needsUpdate(ctime))
+ return;
+
+ dirty = true;
+ toUpdate.push_back(shared_from_this());
+
+ bool prune = false;
+ for (const auto & w : rdepends) {
+ if (auto b = w.lock())
+ b->markDirty(ctime, toUpdate);
+ else
+ prune = true;
+ }
+
+ if (prune) {
+ decltype(rdepends) pruned;
+ for (const auto & w : rdepends)
+ if (!w.expired())
+ pruned.push_back(move(w));
+ rdepends = move(pruned);
+ }
+}
+
+void BhvImplBase::updateDirty(const BhvCurTime & ctime)
+{
+ if (!dirty)
+ return;
+
+ for (auto & d : depends)
+ d->updateDirty(ctime);
+
+ doUpdate(ctime);
+ dirty = false;
+
+ bool prune = false;
+ for (const auto & wcb : watchers) {
+ if (auto cb = wcb.lock())
+ (*cb)(ctime);
+ else
+ prune = true;
+ }
+
+ if (prune) {
+ decltype(watchers) pruned;
+ for (const auto & w : watchers)
+ if (!w.expired())
+ pruned.push_back(move(w));
+ watchers = move(pruned);
+ }
+}
+
+bool BhvImplBase::needsUpdate(const BhvCurTime &) const
+{
+ return true;
+}
+
+void BhvImplBase::doUpdate(const BhvCurTime &)
+{
+}