// 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_DOMAIN_H_INCLUDED
#define REACT_DOMAIN_H_INCLUDED
#pragma once
#include "react/detail/Defs.h"
#include
#include
#include "react/detail/DomainBase.h"
#include "react/detail/ReactiveInput.h"
#include "react/detail/graph/ContinuationNodes.h"
#ifdef REACT_ENABLE_LOGGING
#include "react/logging/EventLog.h"
#include "react/logging/EventRecords.h"
#endif //REACT_ENABLE_LOGGING
/*****************************************/ REACT_BEGIN /*****************************************/
///////////////////////////////////////////////////////////////////////////////////////////////////
/// Forward declarations
///////////////////////////////////////////////////////////////////////////////////////////////////
template
class Signal;
template
class VarSignal;
template
class TempSignal;
template
class Events;
template
class EventSource;
template
class TempEvents;
enum class Token;
template
class Observer;
template
class ScopedObserver;
template
class Reactor;
template
class SignalPack;
///////////////////////////////////////////////////////////////////////////////////////////////////
/// Common types & constants
///////////////////////////////////////////////////////////////////////////////////////////////////
using REACT_IMPL::TransactionFlagsT;
// ETransactionFlags
using REACT_IMPL::ETransactionFlags;
using REACT_IMPL::allow_merging;
#ifdef REACT_ENABLE_LOGGING
using REACT_IMPL::EventLog;
#endif //REACT_ENABLE_LOGGING
// Domain modes
using REACT_IMPL::EDomainMode;
using REACT_IMPL::sequential;
using REACT_IMPL::sequential_concurrent;
using REACT_IMPL::parallel;
using REACT_IMPL::parallel_concurrent;
// Expose enum type so aliases for engines can be declared, but don't
// expose the actual enum values as they are reserved for internal use.
using REACT_IMPL::EPropagationMode;
using REACT_IMPL::WeightHint;
///////////////////////////////////////////////////////////////////////////////////////////////////
/// TransactionStatus
///////////////////////////////////////////////////////////////////////////////////////////////////
class TransactionStatus
{
using StateT = REACT_IMPL::SharedWaitingState;
using PtrT = REACT_IMPL::WaitingStatePtrT;
public:
// Default ctor
inline TransactionStatus() :
statePtr_( StateT::Create() )
{}
// Move ctor
inline TransactionStatus(TransactionStatus&& other) :
statePtr_( std::move(other.statePtr_) )
{
other.statePtr_ = StateT::Create();
}
// Move assignment
inline TransactionStatus& operator=(TransactionStatus&& other)
{
if (this != &other)
{
statePtr_ = std::move(other.statePtr_);
other.statePtr_ = StateT::Create();
}
return *this;
}
// Deleted copy ctor & assignment
TransactionStatus(const TransactionStatus&) = delete;
TransactionStatus& operator=(const TransactionStatus&) = delete;
inline void Wait()
{
assert(statePtr_.Get() != nullptr);
statePtr_->Wait();
}
private:
PtrT statePtr_;
template
friend void AsyncTransaction(TransactionStatus& status, F&& func);
template
friend void AsyncTransaction(TransactionFlagsT flags, TransactionStatus& status, F&& func);
};
///////////////////////////////////////////////////////////////////////////////////////////////////
/// Continuation
///////////////////////////////////////////////////////////////////////////////////////////////////
template
<
typename D,
typename D2 = D
>
class Continuation : public REACT_IMPL::ContinuationBase
{
private:
using NodePtrT = REACT_IMPL::NodeBasePtrT;
public:
using SourceDomainT = D;
using TargetDomainT = D2;
// Default ctor
Continuation() = default;
// Move ctor
Continuation(Continuation&& other) :
Continuation::ContinuationBase( std::move(other) )
{}
// Node ctor
explicit Continuation(NodePtrT&& nodePtr) :
Continuation::ContinuationBase( std::move(nodePtr) )
{}
// Move assignment
Continuation& operator=(Continuation&& other)
{
Continuation::ContinuationBase::operator=( std::move(other) );
return *this;
}
// Deleted copy ctor & assignment
Continuation(const Continuation&) = delete;
Continuation& operator=(const Continuation&) = delete;
};
///////////////////////////////////////////////////////////////////////////////////////////////////
/// MakeContinuation - Signals
///////////////////////////////////////////////////////////////////////////////////////////////////
template
<
typename D,
typename DOut = D,
typename S,
typename FIn
>
auto MakeContinuation(TransactionFlagsT flags, const Signal& trigger, FIn&& func)
-> Continuation
{
static_assert(DOut::is_concurrent,
"MakeContinuation: Target domain does not support concurrent input.");
using REACT_IMPL::SignalContinuationNode;
using F = typename std::decay::type;
return Continuation(
std::make_shared(
flags, GetNodePtr(trigger), std::forward(func)));
}
template
<
typename D,
typename DOut = D,
typename S,
typename FIn
>
auto MakeContinuation(const Signal& trigger, FIn&& func)
-> Continuation
{
return MakeContinuation(0, trigger, std::forward(func));
}
///////////////////////////////////////////////////////////////////////////////////////////////////
/// MakeContinuation - Events
///////////////////////////////////////////////////////////////////////////////////////////////////
template
<
typename D,
typename DOut = D,
typename E,
typename FIn
>
auto MakeContinuation(TransactionFlagsT flags, const Events& trigger, FIn&& func)
-> Continuation
{
static_assert(DOut::is_concurrent,
"MakeContinuation: Target domain does not support concurrent input.");
using REACT_IMPL::EventContinuationNode;
using REACT_IMPL::AddContinuationRangeWrapper;
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,
AddContinuationRangeWrapper,
void
>::type
>::type;
static_assert(! std::is_same::value,
"MakeContinuation: Passed function does not match any of the supported signatures.");
return Continuation(
std::make_shared(
flags, GetNodePtr(trigger), std::forward(func)));
}
template
<
typename D,
typename DOut = D,
typename E,
typename FIn
>
auto MakeContinuation(const Events& trigger, FIn&& func)
-> Continuation
{
return MakeContinuation(0, trigger, std::forward(func));
}
///////////////////////////////////////////////////////////////////////////////////////////////////
/// MakeContinuation - Synced
///////////////////////////////////////////////////////////////////////////////////////////////////
template
<
typename D,
typename DOut = D,
typename E,
typename FIn,
typename ... TDepValues
>
auto MakeContinuation(TransactionFlagsT flags, const Events& trigger,
const SignalPack& depPack, FIn&& func)
-> Continuation
{
static_assert(DOut::is_concurrent,
"MakeContinuation: Target domain does not support concurrent input.");
using REACT_IMPL::SyncedContinuationNode;
using REACT_IMPL::AddContinuationRangeWrapper;
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,
AddContinuationRangeWrapper,
void
>::type
>::type;
static_assert(! std::is_same::value,
"MakeContinuation: Passed function does not match any of the supported signatures.");
struct NodeBuilder_
{
NodeBuilder_(TransactionFlagsT flags, const Events& trigger, FIn&& func) :
MyFlags( flags ),
MyTrigger( trigger ),
MyFunc( std::forward(func) )
{}
auto operator()(const Signal& ... deps)
-> Continuation
{
return Continuation(
std::make_shared(
MyFlags,
GetNodePtr(MyTrigger),
std::forward(MyFunc), GetNodePtr(deps) ...));
}
TransactionFlagsT MyFlags;
const Events& MyTrigger;
FIn MyFunc;
};
return REACT_IMPL::apply(
NodeBuilder_( flags, trigger, std::forward(func) ),
depPack.Data);
}
template
<
typename D,
typename DOut = D,
typename E,
typename FIn,
typename ... TDepValues
>
auto MakeContinuation(const Events& trigger,
const SignalPack& depPack, FIn&& func)
-> Continuation
{
return MakeContinuation(0, trigger, depPack, std::forward(func));
}
///////////////////////////////////////////////////////////////////////////////////////////////
/// DoTransaction
///////////////////////////////////////////////////////////////////////////////////////////////
template
void DoTransaction(F&& func)
{
using REACT_IMPL::DomainSpecificInputManager;
DomainSpecificInputManager::Instance().DoTransaction(0, std::forward(func));
}
template
void DoTransaction(TransactionFlagsT flags, F&& func)
{
using REACT_IMPL::DomainSpecificInputManager;
DomainSpecificInputManager::Instance().DoTransaction(flags, std::forward(func));
}
///////////////////////////////////////////////////////////////////////////////////////////////
/// AsyncTransaction
///////////////////////////////////////////////////////////////////////////////////////////////
template
void AsyncTransaction(F&& func)
{
static_assert(D::is_concurrent,
"AsyncTransaction: Domain does not support concurrent input.");
using REACT_IMPL::DomainSpecificInputManager;
DomainSpecificInputManager::Instance()
.AsyncTransaction(0, nullptr, std::forward(func));
}
template
void AsyncTransaction(TransactionFlagsT flags, F&& func)
{
static_assert(D::is_concurrent,
"AsyncTransaction: Domain does not support concurrent input.");
using REACT_IMPL::DomainSpecificInputManager;
DomainSpecificInputManager::Instance()
.AsyncTransaction(flags, nullptr, std::forward(func));
}
template
void AsyncTransaction(TransactionStatus& status, F&& func)
{
static_assert(D::is_concurrent,
"AsyncTransaction: Domain does not support concurrent input.");
using REACT_IMPL::DomainSpecificInputManager;
DomainSpecificInputManager::Instance()
.AsyncTransaction(0, status.statePtr_, std::forward(func));
}
template
void AsyncTransaction(TransactionFlagsT flags, TransactionStatus& status, F&& func)
{
static_assert(D::is_concurrent,
"AsyncTransaction: Domain does not support concurrent input.");
using REACT_IMPL::DomainSpecificInputManager;
DomainSpecificInputManager::Instance()
.AsyncTransaction(flags, status.statePtr_, std::forward(func));
}
/******************************************/ REACT_END /******************************************/
///////////////////////////////////////////////////////////////////////////////////////////////////
/// Domain definition macro
///////////////////////////////////////////////////////////////////////////////////////////////////
#define REACTIVE_DOMAIN(name, ...) \
struct name : \
public REACT_IMPL::DomainBase> {}; \
REACT_IMPL::DomainInitializer name ## _initializer_;
///////////////////////////////////////////////////////////////////////////////////////////////////
/// Define type aliases for given domain
///////////////////////////////////////////////////////////////////////////////////////////////////
#define USING_REACTIVE_DOMAIN(name) \
template \
using SignalT = Signal; \
\
template \
using VarSignalT = VarSignal; \
\
template \
using EventsT = Events; \
\
template \
using EventSourceT = EventSource; \
\
using ObserverT = Observer; \
\
using ScopedObserverT = ScopedObserver; \
\
using ReactorT = Reactor;
#endif // REACT_DOMAIN_H_INCLUDED