Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/root/TNotifyLink.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 // @(#)root/base:$Id$
0002 // Author: Philippe Canal 2019
0003 
0004 /*************************************************************************
0005  * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers.               *
0006  * All rights reserved.                                                  *
0007  *                                                                       *
0008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
0009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
0010  *************************************************************************/
0011 
0012 #ifndef ROOT_TNotifyLink
0013 #define ROOT_TNotifyLink
0014 
0015 #include <TObject.h>
0016 #include <TError.h> // for R__ASSERT
0017 
0018 /** \class TNotifyLink
0019 \ingroup Base
0020 
0021 A node in a doubly linked list of subscribers to TChain notifications.
0022 
0023 TObject has a virtual TObject::Notify() method that takes no parameters and returns a boolean.
0024 By default the method does nothing, and different objects in ROOT use this method for different purposes.
0025 
0026 `TChain` uses `Notify` to implement a callback mechanism that notifies interested parties (subscribers) when
0027 the chain switches to a new sub-tree.
0028 In practice it calls the Notify() method of its fNotify data member from TChain::LoadTree().
0029 However there could be several different objects interested in knowing that a given TChain switched to a new tree.
0030 TNotifyLink can be used to build a linked list of subscribers: calling TNotifyLink::Notify() on the head
0031 node of the list propagates the call to all subscribers in the list.
0032 
0033 Example usage:
0034 ~~~{.cpp}
0035 TNotifyLink l(subscriber); // subscriber must implement `Notify()`
0036 l.PrependLink(chain); // prepends `l` to the list of notify links of the chain
0037 ~~~
0038 
0039 \note TChain does not explicitly enforce that its fNotify data member be the head node of a list of
0040 TNotifyLinks, but that is the case in practice at least when using TTreeReader or RDataFrame to process the chain.
0041 
0042 \note TChain does not take ownership of the TNotifyLink and the TNotifyLink does not take ownership of the
0043       subscriber object.
0044 **/
0045 
0046 /// See TNotifyLink.
0047 class TNotifyLinkBase : public TObject {
0048 protected:
0049    /// Previous node in a TChain's list of subscribers to its notification.
0050    /// If null, this TNotifyLink is the head node of the list and the TChain::GetNotify() for the corresponding
0051    /// chain is expected to return `this`.
0052    TNotifyLinkBase *fPrevious = nullptr;
0053    /// Next node in a TChain's list of subscribers.
0054    /// For generality, it might be a generic TObject rather than another TNotifyLink: this makes it possible
0055    /// to call TChain::SetNotify() with a generic notifier exactly once before more TNotifyLinks are added.
0056    /// Null if this is the tail of the list.
0057    TObject         *fNext = nullptr;
0058 
0059 public:
0060    // TTree status bits
0061    enum EStatusBits {
0062       kLinked = BIT(11) // Used when the TNotifyLink is connected to a TTree.
0063    };
0064 
0065    void Clear(Option_t * /*option*/ ="") override
0066    {
0067       auto current = this;
0068       do {
0069          auto next = dynamic_cast<TNotifyLinkBase*>(fNext);
0070          current->ResetBit(kLinked);
0071          current->fPrevious = nullptr;
0072          current->fNext = nullptr;
0073          current = next;
0074       } while(current);
0075    }
0076 
0077    /// Set this link as the head of the chain's list of notify subscribers.
0078    /// Templated only to remove an include dependency from TChain: it expects
0079    /// a TChain as input (in practice anything that implements SetNotify and
0080    /// GetNotify will work, but in ROOT that is only TTree and its sub-classes).
0081    template <class Chain>
0082    void PrependLink(Chain &chain)
0083    {
0084       SetBit(kLinked);
0085 
0086       fNext = chain.GetNotify();
0087       chain.SetNotify(this);
0088       if (auto next = dynamic_cast<TNotifyLinkBase *>(fNext))
0089          next->fPrevious = this;
0090    }
0091 
0092    /// Remove this link from a chain's list of notify subscribers.
0093    /// Templated only to remove an include dependency from TChain: it expects
0094    /// a TChain as input (in practice anything that implements SetNotify and
0095    /// GetNotify will work, but in ROOT that is only TTree and its sub-classes).
0096    /// \note No error is emitted if the TNotifyLink is not part of the linked list
0097    /// for the chain passed as argument. The TNotifyLink will still remove itself
0098    /// from the doubly linked list.
0099    template <class Chain>
0100    void RemoveLink(Chain &chain)
0101    {
0102       ResetBit(kLinked);
0103 
0104       if (chain.GetNotify() == this) { // this notify link is the first in the list
0105          R__ASSERT(fPrevious == nullptr && "The TNotifyLink head node should not have a previous element.");
0106          chain.SetNotify(fNext);
0107       } else if (fPrevious) {
0108          fPrevious->fNext = fNext;
0109       }
0110       if (auto next = dynamic_cast<TNotifyLinkBase *>(fNext))
0111          next->fPrevious = fPrevious;
0112       fPrevious = nullptr;
0113       fNext = nullptr;
0114    }
0115 
0116    Bool_t IsLinked()
0117    {
0118       return TestBit(kLinked);
0119    }
0120 
0121    TObject *GetNext() const { return fNext; }
0122 
0123    ClassDefOverride(TNotifyLinkBase, 0);
0124 };
0125 
0126 template <class Type>
0127 class TNotifyLink : public TNotifyLinkBase {
0128 private:
0129    Type *fSubscriber;
0130 
0131 public:
0132    TNotifyLink(Type *subscriber) : fSubscriber(subscriber) {}
0133 
0134    /// Call Notify on our subscriber and propagate the call to the next link.
0135    Bool_t Notify() override
0136    {
0137       bool result = true;
0138       if (fSubscriber)
0139          result &= fSubscriber->Notify();
0140       if (fNext)
0141          result &= fNext->Notify();
0142       return result;
0143    }
0144 
0145    ClassDefOverride(TNotifyLink, 0);
0146 };
0147 
0148 #endif // ROOT_TNotifyLink