[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/lineCode/cpp.react/master/include/react/Observer.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_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::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 = 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

Web Proxy Viewer  |  New URL  |  Original Page