// 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_DETAIL_ENGINE_PULSECOUNTENGINE_H_INCLUDED #define REACT_DETAIL_ENGINE_PULSECOUNTENGINE_H_INCLUDED #pragma once #include "react/detail/Defs.h" #include #include #include #include "tbb/task_group.h" #include "tbb/spin_rw_mutex.h" #include "tbb/task.h" #include "react/common/Containers.h" #include "react/common/Types.h" #include "react/detail/EngineBase.h" /***************************************/ REACT_IMPL_BEGIN /**************************************/ namespace pulsecount { using std::atomic; using std::vector; using tbb::task; using tbb::empty_task; using tbb::spin_rw_mutex; using tbb::task_list; /////////////////////////////////////////////////////////////////////////////////////////////////// /// Turn /////////////////////////////////////////////////////////////////////////////////////////////////// class Turn : public TurnBase { public: Turn(TurnIdT id, TransactionFlagsT flags); }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// Node /////////////////////////////////////////////////////////////////////////////////////////////////// enum class ENodeMark { unmarked, visited, should_update }; enum class ENodeState { unchanged, changed, dyn_defer, dyn_repeat }; class Node : public IReactiveNode { public: using ShiftMutexT = spin_rw_mutex; inline void IncCounter() { counter_.fetch_add(1, std::memory_order_relaxed); } inline bool DecCounter() { return counter_.fetch_sub(1, std::memory_order_relaxed) > 1; } inline void SetCounter(int c) { counter_.store(c, std::memory_order_relaxed); } inline ENodeMark Mark() const { return mark_.load(std::memory_order_relaxed); } inline void SetMark(ENodeMark mark) { mark_.store(mark, std::memory_order_relaxed); } inline bool ExchangeMark(ENodeMark mark) { return mark_.exchange(mark, std::memory_order_relaxed) != mark; } ShiftMutexT ShiftMutex; NodeVector Successors; ENodeState State = ENodeState::unchanged; private: atomic counter_ { 0 }; atomic mark_ { ENodeMark::unmarked }; }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// EngineBase /////////////////////////////////////////////////////////////////////////////////////////////////// class EngineBase : public IReactiveEngine { public: using NodeShiftMutexT = Node::ShiftMutexT; using NodeVectT = vector; void OnNodeAttach(Node& node, Node& parent); void OnNodeDetach(Node& node, Node& parent); void OnInputChange(Node& node, Turn& turn); void Propagate(Turn& turn); void OnNodePulse(Node& node, Turn& turn); void OnNodeIdlePulse(Node& node, Turn& turn); void OnDynamicNodeAttach(Node& node, Node& parent, Turn& turn); void OnDynamicNodeDetach(Node& node, Node& parent, Turn& turn); private: NodeVectT changedInputs_; empty_task& rootTask_ = *new(task::allocate_root()) empty_task; task_list spawnList_; }; } // ~namespace pulsecount /****************************************/ REACT_IMPL_END /***************************************/ /*****************************************/ REACT_BEGIN /*****************************************/ template class PulsecountEngine; template <> class PulsecountEngine : public REACT_IMPL::pulsecount::EngineBase {}; /******************************************/ REACT_END /******************************************/ /***************************************/ REACT_IMPL_BEGIN /**************************************/ template <> struct NodeUpdateTimerEnabled> : std::true_type {}; /****************************************/ REACT_IMPL_END /***************************************/ #endif // REACT_DETAIL_ENGINE_PULSECOUNTENGINE_H_INCLUDED