GitHub Viewer
// 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
>
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,
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,
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(
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 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