From eac6cac6dd18fe9e65e714ca12ab72f947c23089 Mon Sep 17 00:00:00 2001
From: Enric Tejedor Saavedra <enric.tejedor.saavedra@cern.ch>
Date: Tue, 28 Feb 2017 15:18:38 +0100
Subject: [PATCH] Add new constructor in TTreeProcessorMT that receives a
 TEntryList.

This is intended to support the corresponding constructor in TDataFrame.
---
 tree/treeplayer/inc/ROOT/TTreeProcessorMT.hxx | 72 +++++++++++++++++--
 tree/treeplayer/src/TTreeProcessorMT.cxx      |  9 ++-
 2 files changed, 75 insertions(+), 6 deletions(-)

diff --git a/tree/treeplayer/inc/ROOT/TTreeProcessorMT.hxx b/tree/treeplayer/inc/ROOT/TTreeProcessorMT.hxx
index 70780436cab..4c053cf984b 100644
--- a/tree/treeplayer/inc/ROOT/TTreeProcessorMT.hxx
+++ b/tree/treeplayer/inc/ROOT/TTreeProcessorMT.hxx
@@ -18,6 +18,7 @@
 #include "TChain.h"
 #include "TTreeReader.h"
 #include "TError.h"
+#include "TEntryList.h"
 #include "ROOT/TThreadedObject.hxx"
 
 #include <string.h>
@@ -50,7 +51,9 @@ namespace ROOT {
          std::string fTreeName;               ///< Name of the tree
          std::unique_ptr<TFile> fCurrentFile; ///<! Current file object of this view.
          std::unique_ptr<TTree> fCurrentTree; ///<! Current tree object of this view.
-         int fCurrentIdx;                     ///<! Index of the current file.
+         unsigned int fCurrentIdx;            ///<! Index of the current file.
+         std::vector<TEntryList> fEntryLists; ///< Entry numbers to be processed per tree/file
+         TEntryList fCurrentEntryList;        ///< Entry numbers for the current range being processed
 
          ////////////////////////////////////////////////////////////////////////////////
          /// Initialize the file and the tree for this view, first looking for a tree in
@@ -134,6 +137,42 @@ namespace ROOT {
             }
          }
 
+         //////////////////////////////////////////////////////////////////////////
+         /// Constructor based on a TTree and a TEntryList.
+         /// \param[in] tree Tree or chain of files containing the tree to process.
+         /// \param[in] entries List of entry numbers to process.
+         TTreeView(TTree& tree, TEntryList& entries) : TTreeView(tree)
+         {
+            static const TClassRef clRefTChain("TChain");
+            if (clRefTChain == tree.IsA()) {
+               // We need to convert the global entry numbers to per-tree entry numbers.
+               // This will allow us to build a TEntryList for a given entry range of a tree of the chain.
+               size_t nTrees = fFileNames.size();
+               fEntryLists.resize(nTrees);
+
+               TChain *chain = dynamic_cast<TChain*>(&tree);
+               Long64_t currListEntry  = entries.GetEntry(0);
+               Long64_t currTreeOffset = 0;
+
+               for (unsigned int treeNum = 0; treeNum < nTrees && currListEntry >= 0; ++treeNum) {
+                  chain->LoadTree(currTreeOffset);
+                  TTree *currTree = chain->GetTree();
+                  Long64_t currTreeEntries = currTree->GetEntries();
+                  Long64_t nextTreeOffset = currTreeOffset + currTreeEntries;
+
+                  while (currListEntry >= 0 && currListEntry < nextTreeOffset) {
+                     fEntryLists[treeNum].Enter(currListEntry - currTreeOffset);
+                     currListEntry = entries.Next();
+                  }
+
+                  currTreeOffset = nextTreeOffset;
+               }
+            }
+            else {
+               fEntryLists.emplace_back(entries);
+            }
+         }
+
          //////////////////////////////////////////////////////////////////////////
          /// Copy constructor.
          /// \param[in] view Object to copy.
@@ -141,6 +180,10 @@ namespace ROOT {
          {
             for (auto& fn : view.fFileNames)
                fFileNames.emplace_back(fn);
+
+            for (auto& el : view.fEntryLists)
+               fEntryLists.emplace_back(el);
+
             Init();
          }
 
@@ -154,9 +197,29 @@ namespace ROOT {
 
          //////////////////////////////////////////////////////////////////////////
          /// Get a TTreeReader for the current tree of this view.
-         std::unique_ptr<TTreeReader> GetTreeReader() const
+         std::unique_ptr<TTreeReader> GetTreeReader(Long64_t start, Long64_t end)
          {
-            return std::unique_ptr<TTreeReader>(new TTreeReader(fCurrentTree.get()));
+            TTreeReader *reader;
+            if (fEntryLists.size() > 0 && fEntryLists[fCurrentIdx].GetN() > 0) {
+               // TEntryList and SetEntriesRange do not work together (the former has precedence).
+               // We need to construct a TEntryList that contains only those entry numbers
+               // in our desired range.
+               fCurrentEntryList.Reset();
+               Long64_t entry = fEntryLists[fCurrentIdx].GetEntry(0);
+               do {
+                  if (entry >= start && entry < end) fCurrentEntryList.Enter(entry);
+               } while ((entry = fEntryLists[fCurrentIdx].Next()) >= 0);
+
+               reader = new TTreeReader(fCurrentTree.get(), &fCurrentEntryList);
+
+            }
+            else {
+               // If no TEntryList is involved we can safely set the range in the reader
+               reader = new TTreeReader(fCurrentTree.get());
+               reader->SetEntriesRange(start, end);
+            }
+
+            return std::unique_ptr<TTreeReader>(reader);
          }
 
          //////////////////////////////////////////////////////////////////////////
@@ -175,7 +238,7 @@ namespace ROOT {
 
          //////////////////////////////////////////////////////////////////////////
          /// Set the current file and tree of this view.
-         void SetCurrent(int i)
+         void SetCurrent(unsigned int i)
          {
             if (i != fCurrentIdx) {
                fCurrentIdx = i;
@@ -197,6 +260,7 @@ namespace ROOT {
       TTreeProcessorMT(std::string_view filename, std::string_view treename = "");
       TTreeProcessorMT(const std::vector<std::string_view>& filenames, std::string_view treename = "");
       TTreeProcessorMT(TTree& tree);
+      TTreeProcessorMT(TTree& tree, TEntryList& entries);
  
       void Process(std::function<void(TTreeReader&)> func);
 
diff --git a/tree/treeplayer/src/TTreeProcessorMT.cxx b/tree/treeplayer/src/TTreeProcessorMT.cxx
index ef7dbf494bf..a848b73ac3b 100644
--- a/tree/treeplayer/src/TTreeProcessorMT.cxx
+++ b/tree/treeplayer/src/TTreeProcessorMT.cxx
@@ -52,6 +52,12 @@ TTreeProcessorMT::TTreeProcessorMT(const std::vector<std::string_view>& filename
 /// \param[in] tree Tree or chain of files containing the tree to process.
 TTreeProcessorMT::TTreeProcessorMT(TTree& tree) : treeView(tree) {}
 
+////////////////////////////////////////////////////////////////////////
+/// Constructor based on a TTree and a TEntryList.
+/// \param[in] tree Tree or chain of files containing the tree to process.
+/// \param[in] entries List of entry numbers to process.
+TTreeProcessorMT::TTreeProcessorMT(TTree& tree, TEntryList& entries) : treeView(tree, entries) {}
+
 //////////////////////////////////////////////////////////////////////////////
 /// Process the entries of a TTree in parallel. The user-provided function
 /// receives a TTreeReader which can be used to iterate on a subrange of
@@ -89,8 +95,7 @@ void TTreeProcessorMT::Process(std::function<void(TTreeReader&)> func)
 
          g.run([this, &func, start, end, i]() {
             treeView->SetCurrent(i);
-            auto tr = treeView->GetTreeReader();
-            tr->SetEntriesRange(start, end);
+            auto tr = treeView->GetTreeReader(start, end);
             func(*tr);
          });
       }
-- 
GitLab