// 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_OBSERVER_H_INCLUDED #define REACT_OBSERVER_H_INCLUDED #pragma once #include "react/detail/Defs.h" #include #include #include "react/common/Util.h" #include "react/detail/IReactiveNode.h" #include "react/detail/ObserverBase.h" #include "react/detail/graph/ObserverNodes.h" /*****************************************/ REACT_BEGIN /*****************************************/ /////////////////////////////////////////////////////////////////////////////////////////////////// /// Forward declarations /////////////////////////////////////////////////////////////////////////////////////////////////// template class Signal; template class SignalPack; template class Events; using REACT_IMPL::ObserverAction; using REACT_IMPL::WeightHint; /////////////////////////////////////////////////////////////////////////////////////////////////// /// Observer /////////////////////////////////////////////////////////////////////////////////////////////////// template class Observer { private: using SubjectPtrT = std::shared_ptr>; using NodeT = REACT_IMPL::ObserverNode; public: // Default ctor Observer() : nodePtr_( nullptr ), subjectPtr_( nullptr ) {} // Move ctor Observer(Observer&& other) : nodePtr_( other.nodePtr_ ), subjectPtr_( std::move(other.subjectPtr_) ) { other.nodePtr_ = nullptr; other.subjectPtr_.reset(); } // Node ctor Observer(NodeT* nodePtr, const SubjectPtrT& subjectPtr) : nodePtr_( nodePtr ), subjectPtr_( subjectPtr ) {} // Move assignment Observer& operator=(Observer&& other) { nodePtr_ = other.nodePtr_; subjectPtr_ = std::move(other.subjectPtr_); other.nodePtr_ = nullptr; other.subjectPtr_.reset(); return *this; } // Deleted copy ctor and assignment Observer(const Observer&) = delete; Observer& operator=(const Observer&) = delete; void Detach() { assert(IsValid()); subjectPtr_->UnregisterObserver(nodePtr_); } bool IsValid() const { return nodePtr_ != nullptr; } void SetWeightHint(WeightHint weight) { assert(IsValid()); nodePtr_->SetWeightHint(weight); } private: // Owned by subject NodeT* nodePtr_; // While the observer handle exists, the subject is not destroyed SubjectPtrT subjectPtr_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// ScopedObserver /////////////////////////////////////////////////////////////////////////////////////////////////// template class ScopedObserver { public: // Move ctor ScopedObserver(ScopedObserver&& other) : obs_( std::move(other.obs_) ) {} // Construct from observer ScopedObserver(Observer&& obs) : obs_( std::move(obs) ) {} // Move assignment ScopedObserver& operator=(ScopedObserver&& other) { obs_ = std::move(other.obs_); } // Deleted default ctor, copy ctor and assignment ScopedObserver() = delete; ScopedObserver(const ScopedObserver&) = delete; ScopedObserver& operator=(const ScopedObserver&) = delete; ~ScopedObserver() { obs_.Detach(); } bool IsValid() const { return obs_.IsValid(); } void SetWeightHint(WeightHint weight) { obs_.SetWeightHint(weight); } private: Observer obs_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// Observe - Signals /////////////////////////////////////////////////////////////////////////////////////////////////// template < typename D, typename FIn, typename S > auto Observe(const Signal& subject, FIn&& func) -> Observer { using REACT_IMPL::IObserver; using REACT_IMPL::ObserverNode; using REACT_IMPL::SignalObserverNode; using REACT_IMPL::AddDefaultReturnValueWrapper; using F = typename std::decay::type; using R = typename std::result_of::type; using WrapperT = AddDefaultReturnValueWrapper; // If return value of passed function is void, add ObserverAction::next as // default return value. using NodeT = typename std::conditional< std::is_same::value, SignalObserverNode, SignalObserverNode >::type; const auto& subjectPtr = GetNodePtr(subject); std::unique_ptr> nodePtr( new NodeT(subjectPtr, std::forward(func)) ); ObserverNode* rawNodePtr = nodePtr.get(); subjectPtr->RegisterObserver(std::move(nodePtr)); return Observer( rawNodePtr, subjectPtr ); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Observe - Events /////////////////////////////////////////////////////////////////////////////////////////////////// template < typename D, typename FIn, typename E > auto Observe(const Events& subject, FIn&& func) -> Observer { using REACT_IMPL::IObserver; using REACT_IMPL::ObserverNode; using REACT_IMPL::EventObserverNode; using REACT_IMPL::AddDefaultReturnValueWrapper; using REACT_IMPL::AddObserverRangeWrapper; using REACT_IMPL::IsCallableWith; using REACT_IMPL::EventRange; using F = typename std::decay::type; using WrapperT = typename std::conditional< IsCallableWith>::value, F, typename std::conditional< IsCallableWith::value, AddObserverRangeWrapper, typename std::conditional< IsCallableWith>::value, AddDefaultReturnValueWrapper, typename std::conditional< IsCallableWith::value, AddObserverRangeWrapper>, void >::type >::type >::type >::type; static_assert( ! std::is_same::value, "Observe: Passed function does not match any of the supported signatures."); using NodeT = EventObserverNode; const auto& subjectPtr = GetNodePtr(subject); std::unique_ptr> nodePtr( new NodeT(subjectPtr, std::forward(func)) ); ObserverNode* rawNodePtr = nodePtr.get(); subjectPtr->RegisterObserver(std::move(nodePtr)); return Observer( rawNodePtr, subjectPtr ); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Observe - Synced /////////////////////////////////////////////////////////////////////////////////////////////////// template < typename D, typename FIn, typename E, typename ... TDepValues > auto Observe(const Events& subject, const SignalPack& depPack, FIn&& func) -> Observer { using REACT_IMPL::IObserver; using REACT_IMPL::ObserverNode; using REACT_IMPL::SyncedObserverNode; using REACT_IMPL::AddDefaultReturnValueWrapper; using REACT_IMPL::AddObserverRangeWrapper; using REACT_IMPL::IsCallableWith; using REACT_IMPL::EventRange; using F = typename std::decay::type; using WrapperT = typename std::conditional< IsCallableWith, TDepValues ...>::value, F, typename std::conditional< IsCallableWith::value, AddObserverRangeWrapper, typename std::conditional< IsCallableWith, TDepValues ...>::value, AddDefaultReturnValueWrapper, typename std::conditional< IsCallableWith::value, AddObserverRangeWrapper, TDepValues...>, void >::type >::type >::type >::type; static_assert( ! std::is_same::value, "Observe: Passed function does not match any of the supported signatures."); using NodeT = SyncedObserverNode; struct NodeBuilder_ { NodeBuilder_(const Events& subject, FIn&& func) : MySubject( subject ), MyFunc( std::forward(func) ) {} auto operator()(const Signal& ... deps) -> ObserverNode* { return new NodeT( GetNodePtr(MySubject), std::forward(MyFunc), GetNodePtr(deps) ... ); } const Events& MySubject; FIn MyFunc; }; const auto& subjectPtr = GetNodePtr(subject); std::unique_ptr> nodePtr( REACT_IMPL::apply( NodeBuilder_( subject, std::forward(func) ), depPack.Data) ); ObserverNode* rawNodePtr = nodePtr.get(); subjectPtr->RegisterObserver(std::move(nodePtr)); return Observer( rawNodePtr, subjectPtr ); } /******************************************/ REACT_END /******************************************/ #endif // REACT_OBSERVER_H_INCLUDED