diff options
author | Roman Smrž <roman.smrz@seznam.cz> | 2021-04-18 22:25:17 +0200 |
---|---|---|
committer | Roman Smrž <roman.smrz@seznam.cz> | 2021-04-18 22:28:59 +0200 |
commit | 9aaba1211c95dc7e08437a7cca73452181e296d6 (patch) | |
tree | b11cb72c1515fb7b284e98708d6b6f4a8fbae3ab /include/erebos/frp.h | |
parent | c3d6046b25ef0786b8d2919dfa9db4eb05114501 (diff) |
Initial support for FRP behaviors
Diffstat (limited to 'include/erebos/frp.h')
-rw-r--r-- | include/erebos/frp.h | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/include/erebos/frp.h b/include/erebos/frp.h new file mode 100644 index 0000000..587d2b6 --- /dev/null +++ b/include/erebos/frp.h @@ -0,0 +1,230 @@ +#pragma once + +#include <functional> +#include <memory> +#include <optional> +#include <functional> +#include <type_traits> +#include <tuple> +#include <variant> + +namespace erebos { + +using std::enable_if_t; +using std::function; +using std::is_same_v; +using std::make_shared; +using std::monostate; +using std::optional; +using std::shared_ptr; +using std::static_pointer_cast; +using std::tuple; +using std::vector; +using std::weak_ptr; + +class BhvTime +{ + BhvTime(uint64_t t): t(t) {} + friend class BhvCurTime; +public: + +private: + uint64_t t; +}; + +class BhvCurTime +{ +public: + BhvCurTime(); + ~BhvCurTime(); + BhvCurTime(const BhvCurTime &) = delete; + BhvCurTime(BhvCurTime &&); + + BhvCurTime & operator=(const BhvCurTime &) = delete; + BhvCurTime & operator=(BhvCurTime &&); + +private: + optional<BhvTime> t; +}; + +template<typename T> +class Watched +{ +public: + Watched(shared_ptr<function<void(const BhvCurTime &)>> && cb): + cb(move(cb)) {} + ~Watched(); + +private: + shared_ptr<function<void(const BhvCurTime &)>> cb; +}; + +template<typename T> +Watched<T>::~Watched() +{ + BhvCurTime ctime; + cb.reset(); +} + +class BhvImplBase : public std::enable_shared_from_this<BhvImplBase> +{ +public: + virtual ~BhvImplBase(); + +protected: + void dependsOn(shared_ptr<BhvImplBase> other); + void updated(const BhvCurTime &); + virtual bool needsUpdate(const BhvCurTime &) const; + virtual void doUpdate(const BhvCurTime &); + + vector<weak_ptr<function<void(const BhvCurTime &)>>> watchers; +private: + void markDirty(const BhvCurTime &, vector<shared_ptr<BhvImplBase>> &); + void updateDirty(const BhvCurTime &); + + bool dirty = false; + vector<shared_ptr<BhvImplBase>> depends; + vector<weak_ptr<BhvImplBase>> rdepends; + + template<typename A, typename B> friend class BhvFun; +}; + +template<typename A, typename B> +class BhvImpl : public BhvImplBase +{ +public: + virtual B get(const BhvCurTime &, const A &) const = 0; +}; + +template<typename A> +using BhvSource = BhvImpl<monostate, A>; + +template<typename A, typename B> +class BhvFun +{ +public: + BhvFun(shared_ptr<BhvImpl<A, B>> impl): + impl(move(impl)) {} + + template<typename T> BhvFun(shared_ptr<T> impl): + BhvFun(static_pointer_cast<BhvImpl<A, B>>(impl)) {} + + B get(const A & x) const + { + BhvCurTime ctime; + return impl->get(ctime, x); + } + + const shared_ptr<BhvImpl<A, B>> impl; +}; + +template<typename A> +class BhvFun<monostate, A> +{ +public: + BhvFun(shared_ptr<BhvSource<A>> impl): + impl(move(impl)) {} + + template<typename T> BhvFun(shared_ptr<T> impl): + BhvFun(static_pointer_cast<BhvSource<A>>(impl)) {} + + A get() const + { + BhvCurTime ctime; + return impl->get(ctime, monostate()); + } + Watched<A> watch(function<void(const A &)>); + + const shared_ptr<BhvSource<A>> impl; +}; + +template<typename A> +using Bhv = BhvFun<monostate, A>; + +template<typename A> +Watched<A> Bhv<A>::watch(function<void(const A &)> f) +{ + auto cb = make_shared<function<void(const BhvCurTime &)>>( + [impl = BhvFun<monostate, A>::impl, f] (const BhvCurTime & ctime) { + f(impl->get(ctime, monostate())); + }); + BhvFun<monostate, A>::impl->watchers.push_back(cb); + return Watched<A>(move(cb)); +} + + +template<typename A, typename B> +class BhvLambda : public BhvImpl<A, B> +{ +public: + BhvLambda(function<B(const A &)> f): f(f) {} + + B get(const BhvCurTime &, const A & x) const override + { return f(x); } + +private: + function<B(const A &)> f; +}; + +template<typename A, typename B> +BhvFun<A, B> bfun(function<B(const A &)> f) +{ + return make_shared<BhvLambda<A, B>>(f); +} + + +template<typename A, typename B, typename C> class BhvComp; +template<typename A, typename B, typename C> +BhvFun<A, C> operator>>(const BhvFun<A, B> & f, const BhvFun<B, C> & g); + +template<typename A, typename B, typename C> +class BhvComp : public BhvImpl<A, C> +{ +public: + BhvComp(const BhvFun<A, B> & f, const BhvFun<B, C>): + f(f), g(g) {} + + C get(const BhvCurTime & ctime, const A & x) const override + { return g.impl.get(ctime, f.impl.get(ctime, x)); } + +private: + BhvFun<A, B> f; + BhvFun<B, C> g; + + friend BhvFun<A, C> operator>> <A, B, C>(const BhvFun<A, B> &, const BhvFun<B, C> &); +}; + +template<typename B, typename C> +class BhvComp<monostate, B, C> : public BhvSource<C> +{ +public: + BhvComp(const BhvFun<monostate, B> & f, const BhvFun<B, C> & g): + f(f), g(g) {} + + bool needsUpdate(const BhvCurTime & ctime) const override + { return !x || g.impl->get(ctime, f.impl->get(ctime, monostate())) != x.value(); } + + void doUpdate(const BhvCurTime & ctime) override + { x = g.impl->get(ctime, f.impl->get(ctime, monostate())); } + + C get(const BhvCurTime & ctime, const monostate & m) const override + { return x ? x.value() : g.impl->get(ctime, f.impl->get(ctime, m)); } + +private: + BhvFun<monostate, B> f; + BhvFun<B, C> g; + optional<C> x; + + friend BhvFun<monostate, C> operator>> <monostate, B, C>(const BhvFun<monostate, B> &, const BhvFun<B, C> &); +}; + +template<typename A, typename B, typename C> +BhvFun<A, C> operator>>(const BhvFun<A, B> & f, const BhvFun<B, C> & g) +{ + auto impl = make_shared<BhvComp<A, B, C>>(f, g); + impl->dependsOn(f.impl); + impl->dependsOn(g.impl); + return impl; +} + +} |