[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/lineCode/cpp.react/master/include/react/Signal.h [Back]  [Original]

//          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_SIGNAL_H_INCLUDED
#define REACT_SIGNAL_H_INCLUDED

#pragma once

#if _MSC_VER && !__INTEL_COMPILER
    #pragma warning(disable : 4503)
#endif

#include "react/detail/Defs.h"

#include 
#include 
#include 
#include 

#include "react/Observer.h"
#include "react/TypeTraits.h"
#include "react/detail/SignalBase.h"

/*****************************************/ REACT_BEGIN /*****************************************/

///////////////////////////////////////////////////////////////////////////////////////////////////
/// Forward declarations
///////////////////////////////////////////////////////////////////////////////////////////////////
template 
class Signal;

template 
class VarSignal;

template 
class TempSignal;

///////////////////////////////////////////////////////////////////////////////////////////////////
/// SignalPack - Wraps several nodes in a tuple. Create with comma operator.
///////////////////////////////////////////////////////////////////////////////////////////////////
template
<
    typename D,
    typename ... TValues
>
class SignalPack
{
public:
    SignalPack(const Signal&  ... deps) :
        Data( std::tie(deps ...) )
    {}

    template 
    SignalPack(const SignalPack& curArgs, const Signal& newArg) :
        Data( std::tuple_cat(curArgs.Data, std::tie(newArg)) )
    {}

    std::tuple Data;
};

///////////////////////////////////////////////////////////////////////////////////////////////////
/// With - Utility function to create a SignalPack
///////////////////////////////////////////////////////////////////////////////////////////////////
template
<
    typename D,
    typename ... TValues
>
auto With(const Signal&  ... deps)
    -> SignalPack
{
    return SignalPack(deps ...);
}

///////////////////////////////////////////////////////////////////////////////////////////////////
/// MakeVar
///////////////////////////////////////////////////////////////////////////////////////////////////
template
<
    typename D,
    typename V,
    typename S = typename std::decay::type,
    class = typename std::enable_if<
        ! IsSignal::value>::type,
    class = typename std::enable_if<
        ! IsEvent::value>::type
>
auto MakeVar(V&& value)
    -> VarSignal
{
    return VarSignal(
        std::make_shared(
            std::forward(value)));
}

template
<
    typename D,
    typename S
>
auto MakeVar(std::reference_wrapper value)
    -> VarSignal
{
    return VarSignal(
        std::make_shared(value));
}

///////////////////////////////////////////////////////////////////////////////////////////////////
/// MakeVar (higher order reactives)
///////////////////////////////////////////////////////////////////////////////////////////////////
template
<
    typename D,
    typename V,
    typename S = typename std::decay::type,
    typename TInner = typename S::ValueT,
    class = typename std::enable_if<
        IsSignal::value>::type
>
auto MakeVar(V&& value)
    -> VarSignal
{
    return VarSignal(
        std::make_shared(
            std::forward(value)));
}

template
<
    typename D,
    typename V,
    typename S = typename std::decay::type,
    typename TInner = typename S::ValueT,
    class = typename std::enable_if<
        IsEvent::value>::type
>
auto MakeVar(V&& value)
    -> VarSignal
{
    return VarSignal(
        std::make_shared(
            std::forward(value)));
}

///////////////////////////////////////////////////////////////////////////////////////////////////
/// MakeSignal
///////////////////////////////////////////////////////////////////////////////////////////////////
// Single arg
template
<
    typename D,
    typename TValue,
    typename FIn,
    typename F = typename std::decay::type,
    typename S = typename std::result_of::type,
    typename TOp = REACT_IMPL::FunctionOp
>
auto MakeSignal(const Signal& arg, FIn&& func)
    -> TempSignal
{
    return TempSignal(
        std::make_shared(
            std::forward(func), GetNodePtr(arg)));
}

// Multiple args
template
<
    typename D,
    typename ... TValues,
    typename FIn,
    typename F = typename std::decay::type,
    typename S = typename std::result_of::type,
    typename TOp = REACT_IMPL::FunctionOp
>
auto MakeSignal(const SignalPack& argPack, FIn&& func)
    -> TempSignal
{
    using REACT_IMPL::SignalOpNode;

    struct NodeBuilder_
    {
        NodeBuilder_(FIn&& func) :
            MyFunc( std::forward(func) )
        {}

        auto operator()(const Signal& ... args)
            -> TempSignal
        {
            return TempSignal(
                std::make_shared(
                    std::forward(MyFunc), GetNodePtr(args) ...));
        }

        FIn     MyFunc;
    };

    return REACT_IMPL::apply(
        NodeBuilder_( std::forward(func) ),
        argPack.Data);
}

///////////////////////////////////////////////////////////////////////////////////////////////////
/// Unary operators
///////////////////////////////////////////////////////////////////////////////////////////////////
#define REACT_DECLARE_OP(op,name)                                                   \
template                                                                \
struct name ## OpFunctor                                                            \
{                                                                                   \
    T operator()(const T& v) const { return op v; }                                 \
};                                                                                  \
                                                                                    \
template                                                                            \
<                                                                                   \
    typename TSignal,                                                               \
    typename D = typename TSignal::DomainT,                                         \
    typename TVal = typename TSignal::ValueT,                                       \
    class = typename std::enable_if<                                                \
        IsSignal::value>::type,                                            \
    typename F = name ## OpFunctor,                                           \
    typename S = typename std::result_of::type,                            \
    typename TOp = REACT_IMPL::FunctionOp   \
>                                                                                   \
auto operator op(const TSignal& arg)                                                \
    -> TempSignal                                                          \
{                                                                                   \
    return TempSignal(                                                     \
        std::make_shared(                        \
            F(), GetNodePtr(arg)));                                                 \
}                                                                                   \
                                                                                    \
template                                                                            \
<                                                                                   \
    typename D,                                                                     \
    typename TVal,                                                                  \
    typename TOpIn,                                                                 \
    typename F = name ## OpFunctor,                                           \
    typename S = typename std::result_of::type,                            \
    typename TOp = REACT_IMPL::FunctionOp                                \
>                                                                                   \
auto operator op(TempSignal&& arg)                                    \
    -> TempSignal                                                          \
{                                                                                   \
    return TempSignal(                                                     \
        std::make_shared(                        \
            F(), arg.StealOp()));                                                   \
}

REACT_DECLARE_OP(+, UnaryPlus)
REACT_DECLARE_OP(-, UnaryMinus)
REACT_DECLARE_OP(!, LogicalNegation)
REACT_DECLARE_OP(~, BitwiseComplement)
REACT_DECLARE_OP(++, Increment)
REACT_DECLARE_OP(--, Decrement)

#undef REACT_DECLARE_OP                                                                      

///////////////////////////////////////////////////////////////////////////////////////////////////
/// Binary operators
///////////////////////////////////////////////////////////////////////////////////////////////////
#define REACT_DECLARE_OP(op,name)                                                   \
template                                                    \
struct name ## OpFunctor                                                            \
{                                                                                   \
    auto operator()(const L& lhs, const R& rhs) const                               \
        -> decltype(std::declval() op std::declval())                         \
    {                                                                               \
        return lhs op rhs;                                                          \
    }                                                                               \
};                                                                                  \
                                                                                    \
template                                                    \
struct name ## OpRFunctor                                                           \
{                                                                                   \
    name ## OpRFunctor(name ## OpRFunctor&& other) :                                \
        LeftVal( std::move(other.LeftVal) )                                         \
    {}                                                                              \
                                                                                    \
    template                                                            \
    name ## OpRFunctor(T&& val) :                                                   \
        LeftVal( std::forward(val) )                                             \
    {}                                                                              \
                                                                                    \
    name ## OpRFunctor(const name ## OpRFunctor& other) = delete;                   \
                                                                                    \
    auto operator()(const R& rhs) const                                             \
        -> decltype(std::declval() op std::declval())                         \
    {                                                                               \
        return LeftVal op rhs;                                                      \
    }                                                                               \
                                                                                    \
    L LeftVal;                                                                      \
};                                                                                  \
                                                                                    \
template                                                    \
struct name ## OpLFunctor                                                           \
{                                                                                   \
    name ## OpLFunctor(name ## OpLFunctor&& other) :                                \
        RightVal( std::move(other.RightVal) )                                       \
    {}                                                                              \
                                                                                    \
    template                                                            \
    name ## OpLFunctor(T&& val) :                                                   \
        RightVal( std::forward(val) )                                            \
    {}                                                                              \
                                                                                    \
    name ## OpLFunctor(const name ## OpLFunctor& other) = delete;                   \
                                                                                    \
    auto operator()(const L& lhs) const                                             \
        -> decltype(std::declval() op std::declval())                         \
    {                                                                               \
        return lhs op RightVal;                                                     \
    }                                                                               \
                                                                                    \
    R RightVal;                                                                     \
};                                                                                  \
                                                                                    \
template                                                                            \
<                                                                                   \
    typename TLeftSignal,                                                           \
    typename TRightSignal,                                                          \
    typename D = typename TLeftSignal::DomainT,                                     \
    typename TLeftVal = typename TLeftSignal::ValueT,                               \
    typename TRightVal = typename TRightSignal::ValueT,                             \
    class = typename std::enable_if<                                                \
        IsSignal::value>::type,                                        \
    class = typename std::enable_if<                                                \
        IsSignal::value>::type,                                       \
    typename F = name ## OpFunctor,                             \
    typename S = typename std::result_of::type,              \
    typename TOp = REACT_IMPL::FunctionOp                                    \
>                                                                                   \
auto operator op(const TLeftSignal& lhs, const TRightSignal& rhs)                   \
    -> TempSignal                                                          \
{                                                                                   \
    return TempSignal(                                                     \
        std::make_shared(                        \
            F(), GetNodePtr(lhs), GetNodePtr(rhs)));                                \
}                                                                                   \
                                                                                    \
template                                                                            \
<                                                                                   \
    typename TLeftSignal,                                                           \
    typename TRightValIn,                                                           \
    typename D = typename TLeftSignal::DomainT,                                     \
    typename TLeftVal = typename TLeftSignal::ValueT,                               \
    typename TRightVal = typename std::decay::type,                    \
    class = typename std::enable_if<                                                \
        IsSignal::value>::type,                                        \
    class = typename std::enable_if<                                                \
        ! IsSignal::value>::type,                                        \
    typename F = name ## OpLFunctor,                            \
    typename S = typename std::result_of::type,                        \
    typename TOp = REACT_IMPL::FunctionOp                                     \
>                                                                                   \
auto operator op(const TLeftSignal& lhs, TRightValIn&& rhs)                         \
    -> TempSignal                                                          \
{                                                                                   \
    return TempSignal(                                                     \
        std::make_shared(                        \
            F( std::forward(rhs) ), GetNodePtr(lhs)));                 \
}                                                                                   \
                                                                                    \
template                                                                            \
<                                                                                   \
    typename TLeftValIn,                                                            \
    typename TRightSignal,                                                          \
    typename D = typename TRightSignal::DomainT,                                    \
    typename TLeftVal = typename std::decay::type,                      \
    typename TRightVal = typename TRightSignal::ValueT,                             \
    class = typename std::enable_if<                                                \
        ! IsSignal::value>::type,                                         \
    class = typename std::enable_if<                                                \
        IsSignal::value>::type,                                       \
    typename F = name ## OpRFunctor,                            \
    typename S = typename std::result_of::type,                       \
    typename TOp = REACT_IMPL::FunctionOp                                    \
>                                                                                   \
auto operator op(TLeftValIn&& lhs, const TRightSignal& rhs)                         \
    -> TempSignal                                                          \
{                                                                                   \
    return TempSignal(                                                     \
        std::make_shared(                        \
            F( std::forward(lhs) ), GetNodePtr(rhs)));                  \
}                                                                                   \
template                                                                            \
<                                                                                   \
    typename D,                                                                     \
    typename TLeftVal,                                                              \
    typename TLeftOp,                                                               \
    typename TRightVal,                                                             \
    typename TRightOp,                                                              \
    typename F = name ## OpFunctor,                             \
    typename S = typename std::result_of::type,              \
    typename TOp = REACT_IMPL::FunctionOp                     \
>                                                                                   \
auto operator op(TempSignal&& lhs,                              \
                 TempSignal&& rhs)                            \
    -> TempSignal                                                          \
{                                                                                   \
    return TempSignal(                                                     \
        std::make_shared(                        \
            F(), lhs.StealOp(), rhs.StealOp()));                                    \
}                                                                                   \
                                                                                    \
template                                                                            \
<                                                                                   \
    typename D,                                                                     \
    typename TLeftVal,                                                              \
    typename TLeftOp,                                                               \
    typename TRightSignal,                                                          \
    typename TRightVal = typename TRightSignal::ValueT,                             \
    class = typename std::enable_if<                                                \
        IsSignal::value>::type,                                       \
    typename F = name ## OpFunctor,                             \
    typename S = typename std::result_of::type,              \
    typename TOp = REACT_IMPL::FunctionOp                                    \
>                                                                                   \
auto operator op(TempSignal&& lhs,                              \
                 const TRightSignal& rhs)                                           \
    -> TempSignal                                                          \
{                                                                                   \
    return TempSignal(                                                     \
        std::make_shared(                        \
            F(), lhs.StealOp(), GetNodePtr(rhs)));                                  \
}                                                                                   \
                                                                                    \
template                                                                            \
<                                                                                   \
    typename TLeftSignal,                                                           \
    typename D,                                                                     \
    typename TRightVal,                                                             \
    typename TRightOp,                                                              \
    typename TLeftVal = typename TLeftSignal::ValueT,                               \
    class = typename std::enable_if<                                                \
        IsSignal::value>::type,                                        \
    typename F = name ## OpFunctor,                             \
    typename S = typename std::result_of::type,              \
    typename TOp = REACT_IMPL::FunctionOp                                                                   \
>                                                                                   \
auto operator op(const TLeftSignal& lhs, TempSignal&& rhs)    \
    -> TempSignal                                                          \
{                                                                                   \
    return TempSignal(                                                     \
        std::make_shared(                        \
            F(), GetNodePtr(lhs), rhs.StealOp()));                                  \
}                                                                                   \
                                                                                    \
template                                                                            \
<                                                                                   \
    typename D,                                                                     \
    typename TLeftVal,                                                              \
    typename TLeftOp,                                                               \
    typename TRightValIn,                                                           \
    typename TRightVal = typename std::decay::type,                    \
    class = typename std::enable_if<                                                \
        ! IsSignal::value>::type,                                        \
    typename F = name ## OpLFunctor,                            \
    typename S = typename std::result_of::type,                        \
    typename TOp = REACT_IMPL::FunctionOp                              \
>                                                                                   \
auto operator op(TempSignal&& lhs, TRightValIn&& rhs)           \
    -> TempSignal                                                          \
{                                                                                   \
    return TempSignal(                                                     \
        std::make_shared(                        \
            F( std::forward(rhs) ), lhs.StealOp()));                   \
}                                                                                   \
                                                                                    \
template                                                                            \
<                                                                                   \
    typename TLeftValIn,                                                            \
    typename D,                                                                     \
    typename TRightVal,                                                             \
    typename TRightOp,                                                              \
    typename TLeftVal = typename std::decay::type,                      \
    class = typename std::enable_if<                                                \
        ! IsSignal::value>::type,                                         \
    typename F = name ## OpRFunctor,                            \
    typename S = typename std::result_of::type,                       \
    typename TOp = REACT_IMPL::FunctionOp                             \
>                                                                                   \
auto operator op(TLeftValIn&& lhs, TempSignal&& rhs)          \
    -> TempSignal                                                          \
{                                                                                   \
    return TempSignal(                                                     \
        std::make_shared(                        \
            F( std::forward(lhs) ), rhs.StealOp()));                    \
}                                                                                   

REACT_DECLARE_OP(+, Addition)
REACT_DECLARE_OP(-, Subtraction)
REACT_DECLARE_OP(*, Multiplication)
REACT_DECLARE_OP(/, Division)
REACT_DECLARE_OP(%, Modulo)

REACT_DECLARE_OP(==, Equal)
REACT_DECLARE_OP(!=, NotEqual)
REACT_DECLARE_OP(=, GreaterEqual)

REACT_DECLARE_OP(&&, LogicalAnd)
REACT_DECLARE_OP(||, LogicalOr)

REACT_DECLARE_OP(&, BitwiseAnd)
REACT_DECLARE_OP(|, BitwiseOr)
REACT_DECLARE_OP(^, BitwiseXor)
//REACT_DECLARE_OP(, BitwiseRightShift);

#undef REACT_DECLARE_OP 

///////////////////////////////////////////////////////////////////////////////////////////////////
/// Comma operator overload to create signal pack from 2 signals.
///////////////////////////////////////////////////////////////////////////////////////////////////
template
<
    typename D,
    typename TLeftVal,
    typename TRightVal
>
auto operator,(const Signal& a, const Signal& b)
    -> SignalPack
{
    return SignalPack(a, b);
}

///////////////////////////////////////////////////////////////////////////////////////////////////
/// Comma operator overload to append node to existing signal pack.
///////////////////////////////////////////////////////////////////////////////////////////////////
template
<
    typename D,
    typename ... TCurValues,
    typename TAppendValue
>
auto operator,(const SignalPack& cur, const Signal& append)
    -> SignalPack
{
    return SignalPack(cur, append);
}

///////////////////////////////////////////////////////////////////////////////////////////////////
/// operator->* overload to connect signals to a function and return the resulting signal.
///////////////////////////////////////////////////////////////////////////////////////////////////
// Single arg
template
<
    typename D,
    typename F,
    template  class TSignal,
    typename TValue,
    class = typename std::enable_if<
        IsSignal::value>::type
>
auto operator->*(const TSignal& arg, F&& func)
    -> Signal
{
    return REACT::MakeSignal(arg, std::forward(func));
}

// Multiple args
template
<
    typename D,
    typename F,
    typename ... TValues
>
auto operator->*(const SignalPack& argPack, F&& func)
    -> Signal
{
    return REACT::MakeSignal(argPack, std::forward(func));
}

///////////////////////////////////////////////////////////////////////////////////////////////////
/// Flatten
///////////////////////////////////////////////////////////////////////////////////////////////////
template
<
    typename D,
    typename TInnerValue
>
auto Flatten(const Signal& outer)
    -> Signal
{
    return Signal(
        std::make_shared(
            GetNodePtr(outer), GetNodePtr(outer.Value())));
}

///////////////////////////////////////////////////////////////////////////////////////////////////
/// Signal
///////////////////////////////////////////////////////////////////////////////////////////////////
template
<
    typename D,
    typename S
>
class Signal : public REACT_IMPL::SignalBase
{
private:
    using NodeT     = REACT_IMPL::SignalNode;
    using NodePtrT  = std::shared_ptr;

public:
    using ValueT = S;

    // Default ctor
    Signal() = default;

    // Copy ctor
    Signal(const Signal&) = default;

    // Move ctor
    Signal(Signal&& other) :
        Signal::SignalBase( std::move(other) )
    {}

    // Node ctor
    explicit Signal(NodePtrT&& nodePtr) :
        Signal::SignalBase( std::move(nodePtr) )
    {}

    // Copy assignment
    Signal& operator=(const Signal&) = default;

    // Move assignment
    Signal& operator=(Signal&& other)
    {
        Signal::SignalBase::operator=( std::move(other) );
        return *this;
    }

    const S& Value() const      { return Signal::SignalBase::getValue(); }
    const S& operator()() const { return Signal::SignalBase::getValue(); }

    bool Equals(const Signal& other) const
    {
        return Signal::SignalBase::Equals(other);
    }

    bool IsValid() const
    {
        return Signal::SignalBase::IsValid();
    }

    void SetWeightHint(WeightHint weight)
    {
        Signal::SignalBase::SetWeightHint(weight);
    }

    S Flatten() const
    {
        static_assert(IsSignal::value || IsEvent::value,
            "Flatten requires a Signal or Events value type.");
        return REACT::Flatten(*this);
    }
};

// Specialize for references
template
<
    typename D,
    typename S
>
class Signal : public REACT_IMPL::SignalBase
{
private:
    using NodeT     = REACT_IMPL::SignalNode;
    using NodePtrT  = std::shared_ptr;

public:
    using ValueT = S;

    // Default ctor
    Signal() = default;

    // Copy ctor
    Signal(const Signal&) = default;

    // Move ctor
    Signal(Signal&& other) :
        Signal::SignalBase( std::move(other) )
    {}

    // Node ctor
    explicit Signal(NodePtrT&& nodePtr) :
        Signal::SignalBase( std::move(nodePtr) )
    {}

    // Copy assignment
    Signal& operator=(const Signal&) = default;

    // Move assignment
    Signal& operator=(Signal&& other)
    {
        Signal::SignalBase::operator=( std::move(other) );
        return *this;
    }

    const S& Value() const      { return Signal::SignalBase::getValue(); }
    const S& operator()() const { return Signal::SignalBase::getValue(); }

    bool Equals(const Signal& other) const
    {
        return Signal::SignalBase::Equals(other);
    }

    bool IsValid() const
    {
        return Signal::SignalBase::IsValid();
    }

    void SetWeightHint(WeightHint weight)
    {
        Signal::SignalBase::SetWeightHint(weight);
    }
};

///////////////////////////////////////////////////////////////////////////////////////////////////
/// VarSignal
///////////////////////////////////////////////////////////////////////////////////////////////////
template
<
    typename D,
    typename S
>
class VarSignal : public Signal
{
private:
    using NodeT     = REACT_IMPL::VarNode;
    using NodePtrT  = std::shared_ptr;

public:
    // Default ctor
    VarSignal() = default;

    // Copy ctor
    VarSignal(const VarSignal&) = default;

    // Move ctor
    VarSignal(VarSignal&& other) :
        VarSignal::Signal( std::move(other) )
    {}

    // Node ctor
    explicit VarSignal(NodePtrT&& nodePtr) :
        VarSignal::Signal( std::move(nodePtr) )
    {}

    // Copy assignment
    VarSignal& operator=(const VarSignal&) = default;

    // Move assignment
    VarSignal& operator=(VarSignal&& other)
    {
        VarSignal::SignalBase::operator=( std::move(other) );
        return *this;
    }

    void Set(const S& newValue) const
    {
        VarSignal::SignalBase::setValue(newValue);
    }

    void Set(S&& newValue) const
    {
        VarSignal::SignalBase::setValue(std::move(newValue));
    }

    const VarSignal& operator

Web Proxy Viewer  |  New URL  |  Original Page