// Copyright Sebastian Jeckel 2014. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef REACT_EVENT_H_INCLUDED #define REACT_EVENT_H_INCLUDED #pragma once #include "react/detail/Defs.h" #include #include #include #include "react/Observer.h" #include "react/TypeTraits.h" #include "react/common/Util.h" #include "react/detail/EventBase.h" /*****************************************/ REACT_BEGIN /*****************************************/ /////////////////////////////////////////////////////////////////////////////////////////////////// /// Forward declarations /////////////////////////////////////////////////////////////////////////////////////////////////// template class Events; template class EventSource; template class TempEvents; enum class Token; template class Signal; template class SignalPack; using REACT_IMPL::WeightHint; /////////////////////////////////////////////////////////////////////////////////////////////////// /// MakeEventSource /////////////////////////////////////////////////////////////////////////////////////////////////// template auto MakeEventSource() -> EventSource { using REACT_IMPL::EventSourceNode; return EventSource( std::make_shared>()); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Merge /////////////////////////////////////////////////////////////////////////////////////////////////// template < typename D, typename TArg1, typename ... TArgs, typename E = TArg1, typename TOp = REACT_IMPL::EventMergeOp, REACT_IMPL::EventStreamNodePtrT ...> > auto Merge(const Events& arg1, const Events& ... args) -> TempEvents { using REACT_IMPL::EventOpNode; static_assert(sizeof...(TArgs) > 0, "Merge: 2+ arguments are required."); return TempEvents( std::make_shared>( GetNodePtr(arg1), GetNodePtr(args) ...)); } template < typename TLeftEvents, typename TRightEvents, typename D = typename TLeftEvents::DomainT, typename TLeftVal = typename TLeftEvents::ValueT, typename TRightVal = typename TRightEvents::ValueT, typename E = TLeftVal, typename TOp = REACT_IMPL::EventMergeOp, REACT_IMPL::EventStreamNodePtrT>, class = typename std::enable_if< IsEvent::value>::type, class = typename std::enable_if< IsEvent::value>::type > auto operator|(const TLeftEvents& lhs, const TRightEvents& rhs) -> TempEvents { using REACT_IMPL::EventOpNode; return TempEvents( std::make_shared>( GetNodePtr(lhs), GetNodePtr(rhs))); } template < typename D, typename TLeftVal, typename TLeftOp, typename TRightVal, typename TRightOp, typename E = TLeftVal, typename TOp = REACT_IMPL::EventMergeOp > auto operator|(TempEvents&& lhs, TempEvents&& rhs) -> TempEvents { using REACT_IMPL::EventOpNode; return TempEvents( std::make_shared>( lhs.StealOp(), rhs.StealOp())); } template < typename D, typename TLeftVal, typename TLeftOp, typename TRightEvents, typename TRightVal = typename TRightEvents::ValueT, typename E = TLeftVal, typename TOp = REACT_IMPL::EventMergeOp>, class = typename std::enable_if< IsEvent::value>::type > auto operator|(TempEvents&& lhs, const TRightEvents& rhs) -> TempEvents { using REACT_IMPL::EventOpNode; return TempEvents( std::make_shared>( lhs.StealOp(), GetNodePtr(rhs))); } template < typename TLeftEvents, typename D, typename TRightVal, typename TRightOp, typename TLeftVal = typename TLeftEvents::ValueT, typename E = TLeftVal, typename TOp = REACT_IMPL::EventMergeOp, TRightOp>, class = typename std::enable_if< IsEvent::value>::type > auto operator|(const TLeftEvents& lhs, TempEvents&& rhs) -> TempEvents { using REACT_IMPL::EventOpNode; return TempEvents( std::make_shared>( GetNodePtr(lhs), rhs.StealOp())); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Filter /////////////////////////////////////////////////////////////////////////////////////////////////// template < typename D, typename E, typename FIn, typename F = typename std::decay::type, typename TOp = REACT_IMPL::EventFilterOp> > auto Filter(const Events& src, FIn&& filter) -> TempEvents { using REACT_IMPL::EventOpNode; return TempEvents( std::make_shared>( std::forward(filter), GetNodePtr(src))); } template < typename D, typename E, typename TOpIn, typename FIn, typename F = typename std::decay::type, typename TOpOut = REACT_IMPL::EventFilterOp > auto Filter(TempEvents&& src, FIn&& filter) -> TempEvents { using REACT_IMPL::EventOpNode; return TempEvents( std::make_shared>( std::forward(filter), src.StealOp())); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Filter - Synced /////////////////////////////////////////////////////////////////////////////////////////////////// template < typename D, typename E, typename FIn, typename ... TDepValues > auto Filter(const Events& source, const SignalPack& depPack, FIn&& func) -> Events { using REACT_IMPL::SyncedEventFilterNode; using F = typename std::decay::type; struct NodeBuilder_ { NodeBuilder_(const Events& source, FIn&& func) : MySource( source ), MyFunc( std::forward(func) ) {} auto operator()(const Signal& ... deps) -> Events { return Events( std::make_shared>( GetNodePtr(MySource), std::forward(MyFunc), GetNodePtr(deps) ...)); } const Events& MySource; FIn MyFunc; }; return REACT_IMPL::apply( NodeBuilder_( source, std::forward(func) ), depPack.Data); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Transform /////////////////////////////////////////////////////////////////////////////////////////////////// template < typename D, typename TIn, typename FIn, typename F = typename std::decay::type, typename TOut = typename std::result_of::type, typename TOp = REACT_IMPL::EventTransformOp> > auto Transform(const Events& src, FIn&& func) -> TempEvents { using REACT_IMPL::EventOpNode; return TempEvents( std::make_shared>( std::forward(func), GetNodePtr(src))); } template < typename D, typename TIn, typename TOpIn, typename FIn, typename F = typename std::decay::type, typename TOut = typename std::result_of::type, typename TOpOut = REACT_IMPL::EventTransformOp > auto Transform(TempEvents&& src, FIn&& func) -> TempEvents { using REACT_IMPL::EventOpNode; return TempEvents( std::make_shared>( std::forward(func), src.StealOp())); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Transform - Synced /////////////////////////////////////////////////////////////////////////////////////////////////// template < typename D, typename TIn, typename FIn, typename ... TDepValues, typename TOut = typename std::result_of::type > auto Transform(const Events& source, const SignalPack& depPack, FIn&& func) -> Events { using REACT_IMPL::SyncedEventTransformNode; using F = typename std::decay::type; struct NodeBuilder_ { NodeBuilder_(const Events& source, FIn&& func) : MySource( source ), MyFunc( std::forward(func) ) {} auto operator()(const Signal& ... deps) -> Events { return Events( std::make_shared>( GetNodePtr(MySource), std::forward(MyFunc), GetNodePtr(deps) ...)); } const Events& MySource; FIn MyFunc; }; return REACT_IMPL::apply( NodeBuilder_( source, std::forward(func) ), depPack.Data); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Process /////////////////////////////////////////////////////////////////////////////////////////////////// using REACT_IMPL::EventRange; using REACT_IMPL::EventEmitter; template < typename TOut, typename D, typename TIn, typename FIn, typename F = typename std::decay::type > auto Process(const Events& src, FIn&& func) -> Events { using REACT_IMPL::EventProcessingNode; return Events( std::make_shared>( GetNodePtr(src), std::forward(func))); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Process - Synced /////////////////////////////////////////////////////////////////////////////////////////////////// template < typename TOut, typename D, typename TIn, typename FIn, typename ... TDepValues > auto Process(const Events& source, const SignalPack& depPack, FIn&& func) -> Events { using REACT_IMPL::SyncedEventProcessingNode; using F = typename std::decay::type; struct NodeBuilder_ { NodeBuilder_(const Events& source, FIn&& func) : MySource( source ), MyFunc( std::forward(func) ) {} auto operator()(const Signal& ... deps) -> Events { return Events( std::make_shared>( GetNodePtr(MySource), std::forward(MyFunc), GetNodePtr(deps) ...)); } const Events& MySource; FIn MyFunc; }; return REACT_IMPL::apply( NodeBuilder_( source, std::forward(func) ), depPack.Data); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Flatten /////////////////////////////////////////////////////////////////////////////////////////////////// template < typename D, typename TInnerValue > auto Flatten(const Signal>& outer) -> Events { return Events( std::make_shared, TInnerValue>>( GetNodePtr(outer), GetNodePtr(outer.Value()))); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Join /////////////////////////////////////////////////////////////////////////////////////////////////// template < typename D, typename ... TArgs > auto Join(const Events& ... args) -> Events> { using REACT_IMPL::EventJoinNode; static_assert(sizeof...(TArgs) > 1, "Join: 2+ arguments are required."); return Events>( std::make_shared>( GetNodePtr(args) ...)); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Token /////////////////////////////////////////////////////////////////////////////////////////////////// enum class Token { value }; struct Tokenizer { template Token operator()(const T&) const { return Token::value; } }; template auto Tokenize(TEvents&& source) -> decltype(Transform(source, Tokenizer{})) { return Transform(source, Tokenizer{}); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Events /////////////////////////////////////////////////////////////////////////////////////////////////// template < typename D, typename E = Token > class Events : public REACT_IMPL::EventStreamBase { private: using NodeT = REACT_IMPL::EventStreamNode; using NodePtrT = std::shared_ptr; public: using ValueT = E; // Default ctor Events() = default; // Copy ctor Events(const Events&) = default; // Move ctor Events(Events&& other) : Events::EventStreamBase( std::move(other) ) {} // Node ctor explicit Events(NodePtrT&& nodePtr) : Events::EventStreamBase( std::move(nodePtr) ) {} // Copy assignment Events& operator=(const Events&) = default; // Move assignment Events& operator=(Events&& other) { Events::EventStreamBase::operator=( std::move(other) ); return *this; } bool Equals(const Events& other) const { return Events::EventStreamBase::Equals(other); } bool IsValid() const { return Events::EventStreamBase::IsValid(); } void SetWeightHint(WeightHint weight) { Events::EventStreamBase::SetWeightHint(weight); } auto Tokenize() const -> decltype(REACT::Tokenize(std::declval())) { return REACT::Tokenize(*this); } template auto Merge(TArgs&& ... args) const -> decltype(REACT::Merge(std::declval(), std::forward(args) ...)) { return REACT::Merge(*this, std::forward(args) ...); } template auto Filter(F&& f) const -> decltype(REACT::Filter(std::declval(), std::forward(f))) { return REACT::Filter(*this, std::forward(f)); } template auto Transform(F&& f) const -> decltype(REACT::Transform(std::declval(), std::forward(f))) { return REACT::Transform(*this, std::forward(f)); } }; // Specialize for references template < typename D, typename E > class Events : public REACT_IMPL::EventStreamBase> { private: using NodeT = REACT_IMPL::EventStreamNode>; using NodePtrT = std::shared_ptr; public: using ValueT = E; // Default ctor Events() = default; // Copy ctor Events(const Events&) = default; // Move ctor Events(Events&& other) : Events::EventStreamBase( std::move(other) ) {} // Node ctor explicit Events(NodePtrT&& nodePtr) : Events::EventStreamBase( std::move(nodePtr) ) {} // Copy assignment Events& operator=(const Events&) = default; // Move assignment Events& operator=(Events&& other) { Events::EventStreamBase::operator=( std::move(other) ); return *this; } bool Equals(const Events& other) const { return Events::EventStreamBase::Equals(other); } bool IsValid() const { return Events::EventStreamBase::IsValid(); } void SetWeightHint(WeightHint weight) { Events::EventStreamBase::SetWeightHint(weight); } auto Tokenize() const -> decltype(REACT::Tokenize(std::declval())) { return REACT::Tokenize(*this); } template auto Merge(TArgs&& ... args) -> decltype(REACT::Merge(std::declval(), std::forward(args) ...)) { return REACT::Merge(*this, std::forward(args) ...); } template auto Filter(F&& f) const -> decltype(REACT::Filter(std::declval(), std::forward(f))) { return REACT::Filter(*this, std::forward(f)); } template auto Transform(F&& f) const -> decltype(REACT::Transform(std::declval(), std::forward(f))) { return REACT::Transform(*this, std::forward(f)); } }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// EventSource /////////////////////////////////////////////////////////////////////////////////////////////////// template < typename D, typename E = Token > class EventSource : public Events { private: using NodeT = REACT_IMPL::EventSourceNode; using NodePtrT = std::shared_ptr; public: // Default ctor EventSource() = default; // Copy ctor EventSource(const EventSource&) = default; // Move ctor EventSource(EventSource&& other) : EventSource::Events( std::move(other) ) {} // Node ctor explicit EventSource(NodePtrT&& nodePtr) : EventSource::Events( std::move(nodePtr) ) {} // Copy assignemnt EventSource& operator=(const EventSource&) = default; // Move assignment EventSource& operator=(EventSource&& other) { EventSource::Events::operator=( std::move(other) ); return *this; } // Explicit emit void Emit(const E& e) const { EventSource::EventStreamBase::emit(e); } void Emit(E&& e) const { EventSource::EventStreamBase::emit(std::move(e)); } void Emit() const { static_assert(std::is_same::value, "Can't emit on non token stream."); EventSource::EventStreamBase::emit(Token::value); } // Function object style void operator()(const E& e) const { EventSource::EventStreamBase::emit(e); } void operator()(E&& e) const { EventSource::EventStreamBase::emit(std::move(e)); } void operator()() const { static_assert(std::is_same::value, "Can't emit on non token stream."); EventSource::EventStreamBase::emit(Token::value); } // Stream style const EventSource& operator<<(const E& e) const { EventSource::EventStreamBase::emit(e); return *this; } const EventSource& operator<<(E&& e) const { EventSource::EventStreamBase::emit(std::move(e)); return *this; } }; // Specialize for references template < typename D, typename E > class EventSource : public Events> { private: using NodeT = REACT_IMPL::EventSourceNode>; using NodePtrT = std::shared_ptr; public: // Default ctor EventSource() = default; // Copy ctor EventSource(const EventSource&) = default; // Move ctor EventSource(EventSource&& other) : EventSource::Events( std::move(other) ) {} // Node ctor explicit EventSource(NodePtrT&& nodePtr) : EventSource::Events( std::move(nodePtr) ) {} // Copy assignment EventSource& operator=(const EventSource&) = default; // Move assignment EventSource& operator=(EventSource&& other) { EventSource::Events::operator=( std::move(other) ); return *this; } // Explicit emit void Emit(std::reference_wrapper e) const { EventSource::EventStreamBase::emit(e); } // Function object style void operator()(std::reference_wrapper e) const { EventSource::EventStreamBase::emit(e); } // Stream style const EventSource& operator<<(std::reference_wrapper e) const { EventSource::EventStreamBase::emit(e); return *this; } }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// TempEvents /////////////////////////////////////////////////////////////////////////////////////////////////// template < typename D, typename E, typename TOp > class TempEvents : public Events { protected: using NodeT = REACT_IMPL::EventOpNode; using NodePtrT = std::shared_ptr; public: // Default ctor TempEvents() = default; // Copy ctor TempEvents(const TempEvents&) = default; // Move ctor TempEvents(TempEvents&& other) : TempEvents::Events( std::move(other) ) {} // Node ctor explicit TempEvents(NodePtrT&& nodePtr) : TempEvents::Events( std::move(nodePtr) ) {} // Copy assignment TempEvents& operator=(const TempEvents&) = default; // Move assignment TempEvents& operator=(TempEvents&& other) { TempEvents::EventStreamBase::operator=( std::move(other) ); return *this; } TOp StealOp() { return std::move(reinterpret_cast(this->ptr_.get())->StealOp()); } template auto Merge(TArgs&& ... args) -> decltype(REACT::Merge(std::declval(), std::forward(args) ...)) { return REACT::Merge(*this, std::forward(args) ...); } template auto Filter(F&& f) const -> decltype(REACT::Filter(std::declval(), std::forward(f))) { return REACT::Filter(*this, std::forward(f)); } template auto Transform(F&& f) const -> decltype(REACT::Transform(std::declval(), std::forward(f))) { return REACT::Transform(*this, std::forward(f)); } }; /******************************************/ REACT_END /******************************************/ /***************************************/ REACT_IMPL_BEGIN /**************************************/ template bool Equals(const Events& lhs, const Events& rhs) { return lhs.Equals(rhs); } /****************************************/ REACT_IMPL_END /***************************************/ #endif // REACT_EVENT_H_INCLUDED