Logo ROOT  
Reference Guide
TEntryList.cxx
Go to the documentation of this file.
1 // @(#)root/tree:$Id$
2 // Author: Anna Kreshuk 27/10/2006
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2006, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /** \class TEntryList
13 \ingroup tree
14 
15 A List of entry numbers in a TTree or TChain.
16 
17 There are two types of entry lists:
18 
19 #### 1.
20  for a TTree (fBlocks data member is non-zero)
21  Entry numbers are stored in TEntryListBlocks, which, in their turn, are stored
22  in the TObjArray fBlocks. The range of the entry numbers is cut into intervals
23  of kBlockSize entries (currently 64000), so that the first block contains
24  information which entries out of the first 64000 pass the selection, the second
25  block - which entries out of the 64000-127999 interval pass the selection, etc.
26  Some blocks, obviously, might be empty. The internal representation of entry
27  numbers in the blocks is described in the TEntryListBlock class description, and
28  this representation might be changed by calling OptimizeStorage() function
29  (when the list is filled via the Enter() function, this is done automatically,
30  except for the last block).
31  Individual entry lists can be merged (functions Merge() and Add())
32  to make an entry list for a TChain of corresponding TTrees.
33 Begin_Macro
34 entrylist_figure1.C
35 End_Macro
36 
37 #### 2.
38  for a TChain (fLists data member is non-zero)
39  It contains a TList of sub-lists (TEntryList objects, corresponding to each TTree)
40  Trees and lists are matched by the TTree name and its file name (full path).
41  All sub-lists are returned by the GetLists() function and individual lists are
42  returned by GetEntryList() function. Such lists are no different from the lists for
43  TTrees, described above.
44 Begin_Macro
45 entrylist_figure2.C
46 End_Macro
47 
48 ## Operations on entry lists
49 
50 - __Add__() - if the lists are for the same tree, adds all the entries of the second list
51  to the first list. If the lists are for different trees, creates a TEntryList
52  with 2 sublists for each TTree. If the lists are for TChains, merges the ones
53  for the same trees and adds new sublists for the TTrees that were not included
54  in the first TEntryList
55 - __Subtract__() - if the lists are for the same TTree, removes the entries of the second
56  list from the first list. If the lists are for TChains, loops over all
57  sub-lists
58 - __GetEntry(n)__ - returns the n-th entry number
59 - __Next__() - returns next entry number. Note, that this function is
60  much faster than GetEntry, and it's called when GetEntry() is called
61  for 2 or more indices in a row.
62 
63 ## TTree::Draw() and TChain::Draw()
64 
65 Use option __entrylist__ to write the results of TTree::Draw and TChain::Draw into
66 an entry list. Example:
67 ~~~ {.cpp}
68  tree->Draw(">>elist", "x<0 && y>0", "entrylist");
69  TEntryList *elist = (TEntryList*)gDirectory->Get("elist");
70 ~~~
71 ## Example of Loop on TEntryList with a TChain
72 ~~~ {.cpp}
73  void loopChain() {
74  TFile *fe = TFile::Open("myelist.root");
75  TEntryList *myelist = (TEntryList*)fe->Get("myelist");
76  TChain *chain = new TChain("ntuple");
77  chain->Add("hsimple.root");
78  chain->Add("hsimple2.root");
79  Long64_t listEntries = myelist->GetN();
80  Long64_t chainEntries = chain->GetEntries();
81  Int_t treenum = 0;
82  chain->SetEntryList(myelist);
83 
84  for (entry=start;entry < end;entry++) {
85  entryNumber = chain->GetEntryNumber(entry);
86  if (entryNumber < 0) break;
87  localEntry = chain->LoadTree(entryNumber);
88  if (localEntry < 0) break;
89  ....
90  then either call
91  branch->GetEntry(localEntry);
92  or
93  chain->GetEntry(entryNumber);
94  In the later case the LoadTree is then somewhat redudant.
95  ...
96  }
97  }
98 ~~~
99 When using the TEntryList interface directly, you can get the 'tree number' and entry in
100 the current tree (i.e. value similar to the return value of LoadTree) from calling
101 TEntryList::GetEntryAndTree:
102 ~~~ {.cpp}
103  Long64_t treeEntry = myelist->GetEntryAndTree(el,treenum);
104 ~~~
105 to obtain the entry number within the chain you need to add to it the value of
106 `treeEntry+ch->GetTreeOffset()[treenum]`
107 such that the loop in the previous example can also be written as:
108 ~~~ {.cpp}
109  for (Long64_t el = 0; el < listEntries; el++) {
110  Long64_t treeEntry = myelist->GetEntryAndTree(el,treenum);
111  Long64_t chainEntry = treeEntry+ch->GetTreeOffset()[treenum];
112  printf("el=%lld, treeEntry=%lld, chainEntry=%lld, treenum=%d\n", el, treeEntry, chainEntry, treenum);
113 
114  ch->LoadTree(chainEntry); // this also returns treeEntry
115  needed_branch->GetEntry(treeEntry);
116  }
117 ~~~
118 ## TSelectors
119 
120 To fill an TEntryList from a TSelector correctly, one must add the TEntryList object
121 to the output list of the selector (TSelector::fOutput). This is the only way to
122 make the sub-lists of the TEntryList switch when the current tree of the TChain is
123 changed.
124 
125 ## Using a TEntryList as input (TTree::SetEntryList() and TChain::SetEntryList())
126 
127 while the TTree::SetEntryList() function is only setting the TTree::fEntryList
128 data member, the same function in TChain also finds correspondence between
129 the TTrees of this TChain and the sub-lists of this TEntryList.
130 
131 ## TEntryList and the current directory
132 
133 TEntryList objects are automatically added to the current directory (like TTrees).
134 However, in case of a TEntryList for a chain, only the top-level entry list is added,
135 not the sub-lists for specific trees. Placing entry lists in the current directory
136 allows calling them as a part of a TTreeFormula expression, so if the user wants
137 to extract a sublist from a TChain entry list via the GetEntryList() or some other
138 function, they have to add it to the current directory to be able to use it in
139 TTreeFormula expressions.
140 
141 ## TEntryList and TEventList
142 
143 TTree::SetEventList() and TChain::SetEventList() transform a TEventList into a TEntryList
144 See comments to those functions for more details
145 */
146 
147 #include "TEntryList.h"
148 #include "TEntryListBlock.h"
149 #include "TError.h"
150 #include "TKey.h"
151 #include "TBuffer.h"
152 #include "TTree.h"
153 #include "TFile.h"
154 #include "TRegexp.h"
155 #include "TSystem.h"
156 #include "TObjString.h"
157 
159 
160 ////////////////////////////////////////////////////////////////////////////////
161 /// default c-tor
162 
163 TEntryList::TEntryList() : fEntriesToProcess(0)
164 {
165  fLists = 0;
166  fCurrent = 0;
167  fBlocks = 0;
168  fN = 0;
169  fNBlocks = 0;
170  fTreeName = "";
171  fFileName = "";
172  fStringHash = 0;
173  fTreeNumber = -1;
174  fDirectory = 0;
175  fReapply = kFALSE;
176  fLastIndexQueried = -1;
177  fLastIndexReturned = 0;
178  fShift = kFALSE;
179 }
180 
181 ////////////////////////////////////////////////////////////////////////////////
182 /// c-tor with name and title
183 
184 TEntryList::TEntryList(const char *name, const char *title) :
185  TNamed(name, title),
186  fEntriesToProcess(0)
187 {
188  fLists = 0;
189  fCurrent = 0;
190  fBlocks = 0;
191  fN = 0;
192  fNBlocks = 0;
193  fTreeName = "";
194  fFileName = "";
195  fStringHash = 0;
196  fTreeNumber = -1;
197  fReapply = kFALSE;
198 
200  if (fDirectory) fDirectory->Append(this);
201 
202  fLastIndexQueried = -1;
203  fLastIndexReturned = 0;
204  fShift = kFALSE;
205 }
206 
207 ////////////////////////////////////////////////////////////////////////////////
208 /// constructor with name and title, which also sets the tree
209 
210 TEntryList::TEntryList(const char *name, const char *title, const TTree *tree):TNamed(name, title)
211 {
212  fLists = 0;
213  fCurrent = 0;
214  fBlocks = 0;
215  fN = 0;
216  fNBlocks = 0;
217  fTreeNumber = -1;
219  fReapply = kFALSE;
220 
222  if (fDirectory) fDirectory->Append(this);
223 
224  fLastIndexQueried = -1;
225  fLastIndexReturned = 0;
226  fShift = kFALSE;
227 }
228 
229 ////////////////////////////////////////////////////////////////////////////////
230 /// c-tor with name and title, which also sets the treename and the filename
231 
232 TEntryList::TEntryList(const char *name, const char *title, const char *treename, const char *filename) : TNamed(name, title),fEntriesToProcess(0)
233 {
234  fLists = 0;
235  fCurrent = 0;
236  fBlocks = 0;
237  fNBlocks = 0;
238  fN = 0;
239  SetTree(treename, filename);
240  fTreeNumber = -1;
241  fReapply = kFALSE;
242 
244  if (fDirectory) fDirectory->Append(this);
245 
246  fLastIndexQueried = -1;
247  fLastIndexReturned = 0;
248  fShift = kFALSE;
249 }
250 
251 ////////////////////////////////////////////////////////////////////////////////
252 /// c-tor, which sets the tree
253 
254 TEntryList::TEntryList(const TTree *tree) : fEntriesToProcess(0)
255 {
256  fLists = 0;
257  fCurrent = 0;
258  fBlocks = 0;
259  fNBlocks = 0;
260  fN = 0;
261 
262  SetTree(tree);
263  fTreeNumber = -1;
264 
265  fReapply = kFALSE;
267  if (fDirectory) fDirectory->Append(this);
268 
269  fLastIndexQueried = -1;
270  fLastIndexReturned = 0;
271  fShift = kFALSE;
272 }
273 
274 ////////////////////////////////////////////////////////////////////////////////
275 /// copy c-tor
276 
277 TEntryList::TEntryList(const TEntryList &elist) : TNamed(elist)
278 {
279  fNBlocks = elist.fNBlocks;
280  fTreeName = elist.fTreeName;
281  fFileName = elist.fFileName;
282  fStringHash = elist.fStringHash;
283  fTreeNumber = elist.fTreeNumber;
284  fLastIndexQueried = -1;
285  fLastIndexReturned = 0;
286  fN = elist.fN;
287  fShift = elist.fShift;
288  fLists = 0;
289  fBlocks = 0;
290  fReapply = elist.fReapply;
291  fCurrent = 0;
293  if (elist.fLists){
294  fLists = new TList();
295  TEntryList *el1 = 0;
296  TEntryList *el2 = 0;
297  TIter next(elist.fLists);
298  while((el1 = (TEntryList*)next())){
299  el2 = new TEntryList(*el1);
300  if (el1==elist.fCurrent)
301  fCurrent = el2;
302  fLists->Add(el2);
303  }
304  } else {
305  if (elist.fBlocks){
306  TEntryListBlock *block1 = 0;
307  TEntryListBlock *block2 = 0;
308  //or just copy it as a TObjArray??
309  fBlocks = new TObjArray();
310  for (Int_t i=0; i<fNBlocks; i++){
311  block1 = (TEntryListBlock*)elist.fBlocks->UncheckedAt(i);
312  block2 = new TEntryListBlock(*block1);
313  fBlocks->Add(block2);
314  }
315  }
316  fCurrent = this;
317  }
318  fDirectory = 0;
319 
320 }
321 
322 ////////////////////////////////////////////////////////////////////////////////
323 /// Destructor.
324 
326 {
327  if (fBlocks){
328  fBlocks->Delete();
329  delete fBlocks;
330  }
331  fBlocks = 0;
332  if (fLists){
333  fLists->Delete();
334  delete fLists;
335  }
336 
337  fLists = 0;
338 
339  if (fDirectory) fDirectory->Remove(this);
340  fDirectory = 0;
341 
342 }
343 
344 ////////////////////////////////////////////////////////////////////////////////
345 /// Add 2 entry lists
346 
347 void TEntryList::Add(const TEntryList *elist)
348 {
349  if (fN==0){
350  if (!fLists && fTreeName=="" && fFileName==""){
351  //this list is empty. copy the other list completely
352  fNBlocks = elist->fNBlocks;
353  fTreeName = elist->fTreeName;
354  fFileName = elist->fFileName;
355  fStringHash = elist->fStringHash;
356  fTreeNumber = elist->fTreeNumber;
357  fLastIndexQueried = -1;
358  fLastIndexReturned = 0;
359  fN = elist->fN;
360  if (elist->fLists){
361  fLists = new TList();
362  TEntryList *el1 = 0;
363  TEntryList *el2 = 0;
364  TIter next(elist->fLists);
365  while((el1 = (TEntryList*)next())){
366  el2 = new TEntryList(*el1);
367  if (el1==elist->fCurrent)
368  fCurrent = el2;
369  fLists->Add(el2);
370  }
371  } else {
372  if (elist->fBlocks){
373  TEntryListBlock *block1 = 0;
374  TEntryListBlock *block2 = 0;
375  fBlocks = new TObjArray();
376  for (Int_t i=0; i<fNBlocks; i++){
377  block1 = (TEntryListBlock*)elist->fBlocks->UncheckedAt(i);
378  block2 = new TEntryListBlock(*block1);
379  fBlocks->Add(block2);
380  }
381  }
382  fCurrent = 0;
383  }
384  return;
385  }
386  }
387 
388  if (!fLists){
389  if (!elist->fLists){
390  if (!strcmp(elist->fTreeName.Data(),fTreeName.Data()) && !strcmp(elist->fFileName.Data(),fFileName.Data())){
391  //entry lists are for the same tree
392  if (!elist->fBlocks)
393  //the other list is empty list
394  return;
395  if (!fBlocks){
396  //this entry list is empty
397  TEntryListBlock *block1 = 0;
398  TEntryListBlock *block2 = 0;
399  fNBlocks = elist->fNBlocks;
400  fN = elist->fN;
401  fBlocks = new TObjArray();
402  for (Int_t i=0; i<fNBlocks; i++){
403  block1 = (TEntryListBlock*)elist->fBlocks->UncheckedAt(i);
404  block2 = new TEntryListBlock(*block1);
405  fBlocks->Add(block2);
406  }
407  return;
408  }
409  //both not empty, merge block by block
410  TEntryListBlock *block1=0;
411  TEntryListBlock *block2=0;
412  Int_t i;
413  Int_t nmin = TMath::Min(fNBlocks, elist->fNBlocks);
414  Long64_t nnew, nold;
415  for (i=0; i<nmin; i++){
416  block1 = (TEntryListBlock*)fBlocks->UncheckedAt(i);
417  block2 = (TEntryListBlock*)elist->fBlocks->UncheckedAt(i);
418  nold = block1->GetNPassed();
419  nnew = block1->Merge(block2);
420  fN = fN - nold + nnew;
421  }
422  if (fNBlocks<elist->fNBlocks){
423  Int_t nmax = elist->fNBlocks;
424  for (i=nmin; i<nmax; i++){
425  block2 = (TEntryListBlock*)elist->fBlocks->UncheckedAt(i);
426  block1 = new TEntryListBlock(*block2);
427  fBlocks->Add(block1);
428  fN+=block1->GetNPassed();
429  fNBlocks++;
430  }
431  }
432  fLastIndexQueried = -1;
433  fLastIndexReturned = 0;
434  } else {
435  //entry lists are for different trees. create a chain entry list with
436  //2 sub lists for the first and second entry lists
437  fLastIndexQueried = -1;
438  fLastIndexReturned = 0;
439  fLists = new TList();
440  TEntryList *el = new TEntryList();
441  el->fTreeName = fTreeName;
442  el->fFileName = fFileName;
443  el->fBlocks = fBlocks;
444  fBlocks = 0;
445  el->fNBlocks = fNBlocks;
446  el->fN = fN;
447  el->fLastIndexQueried = -1;
448  el->fLastIndexReturned = 0;
449  fLists->Add(el);
450  el = new TEntryList(*elist);
451  el->fLastIndexQueried = -1;
452  el->fLastIndexReturned = 0;
453  fLists->Add(el);
454  fN+=el->GetN();
455  fCurrent = 0;
456  }
457  } else {
458  //second list already has sublists. add one by one
459  TEntryList *el = 0;
460  TIter next(elist->fLists);
461  while ((el = (TEntryList*)next())){
462  Add(el);
463  }
464  fCurrent = 0;
465  }
466  } else {
467  //there are already some sublists in this list, just add another one
468  if (!elist->fLists){
469  //the other list doesn't have sublists
470  TIter next(fLists);
471  TEntryList *el = 0;
472  Bool_t found = kFALSE;
473  while ((el = (TEntryList*)next())){
474  if (!strcmp(el->fTreeName.Data(), elist->fTreeName.Data()) &&
475  !strcmp(el->fFileName.Data(), elist->fFileName.Data())){
476  // if (el->fStringHash == elist->fStringHash){
477  //found a list for the same tree
478  Long64_t oldn = el->GetN();
479  el->Add(elist);
480  found = kTRUE;
481  fN = fN - oldn + el->GetN();
482  break;
483  }
484  }
485  if (!found){
486  el = new TEntryList(*elist);
487  el->fLastIndexQueried = -1;
488  el->fLastIndexReturned = 0;
489  fLists->Add(el);
490  fN+=el->GetN();
491  }
492  } else {
493  //add all sublists from the other list
494  TEntryList *el = 0;
495  TIter next(elist->fLists);
496  while ((el = (TEntryList*)next())){
497  Add(el);
498  }
499  fCurrent = 0;
500  }
501  if (fCurrent){
502  if (fCurrent->fBlocks){
503  Int_t currentblock = (fCurrent->fLastIndexReturned)/kBlockSize;
505  block->ResetIndices();
508  }
509  }
510  fCurrent = 0;
511  }
512 
513 }
514 
515 ////////////////////////////////////////////////////////////////////////////////
516 /// - When tree = 0, returns from the current list
517 /// - When tree != 0, finds the list, corresponding to this tree
518 /// - When tree is a chain, the entry is assumed to be global index and the local
519 /// entry is recomputed from the treeoffset information of the chain
520 
522 {
523  if (!tree){
524  if (fBlocks) {
525  //this entry list doesn't contain any sub-lists
526  TEntryListBlock *block = 0;
527  Int_t nblock = entry/kBlockSize;
528  if (nblock >= fNBlocks) return 0;
530  return block->Contains(entry-nblock*kBlockSize);
531  }
532  if (fLists) {
533  if (!fCurrent) fCurrent = (TEntryList*)fLists->First();
534  return fCurrent->Contains(entry);
535  }
536  return 0;
537  } else {
538  Long64_t localEntry = tree->LoadTree(entry);
539  SetTree(tree->GetTree());
540  if (fCurrent)
541  return fCurrent->Contains(localEntry);
542  }
543  return 0;
544 
545 }
546 
547 ////////////////////////////////////////////////////////////////////////////////
548 /// Called by TKey and others to automatically add us to a directory when we are read from a file.
549 
551 {
552  SetDirectory(dir);
553 }
554 
555 ////////////////////////////////////////////////////////////////////////////////
556 /// Add entry \#entry to the list
557 /// - When tree = 0, adds to the current list
558 /// - When tree != 0, finds the list, corresponding to this tree
559 /// - When tree is a chain, the entry is assumed to be global index and the local
560 /// entry is recomputed from the treeoffset information of the chain
561 
563 {
564  if (!tree){
565  if (!fLists) {
566  if (!fBlocks) fBlocks = new TObjArray();
567  TEntryListBlock *block = 0;
568  Long64_t nblock = entry/kBlockSize;
569  if (nblock >= fNBlocks) {
570  if (fNBlocks>0){
572  if (!block) return 0;
573  block->OptimizeStorage();
574  }
575  for (Int_t i=fNBlocks; i<=nblock; i++){
576  block = new TEntryListBlock();
577  fBlocks->Add(block);
578  }
579  fNBlocks = nblock+1;
580  }
582  if (block->Enter(entry-nblock*kBlockSize)) {
583  fN++;
584  return 1;
585  }
586  } else {
587  //the entry in the current entry list
588  if (!fCurrent) fCurrent = (TEntryList*)fLists->First();
589  if (fCurrent->Enter(entry)) {
590  if (fLists)
591  fN++;
592  return 1;
593  }
594  }
595  } else {
596  Long64_t localentry = tree->LoadTree(entry);
597  SetTree(tree->GetTree());
598  if (fCurrent){
599  if (fCurrent->Enter(localentry)) {
600  if (fLists)
601  fN++;
602  return 1;
603  }
604  }
605  }
606  return 0;
607 
608 }
609 
610 ////////////////////////////////////////////////////////////////////////////////
611 /// Remove entry \#entry from the list
612 /// - When tree = 0, removes from the current list
613 /// - When tree != 0, finds the list, corresponding to this tree
614 /// - When tree is a chain, the entry is assumed to be global index and the local
615 /// entry is recomputed from the treeoffset information of the chain
616 
618 {
619  if (entry < 0)
620  return kFALSE;
621  if (!tree) {
622  if (!fLists) {
623  if (!fBlocks) return 0;
624  TEntryListBlock *block = 0;
625  Long64_t nblock = entry/kBlockSize;
627  if (!block) return 0;
628  Long64_t blockindex = entry - nblock*kBlockSize;
629  if (block->Remove(blockindex)){
630  fN--;
631  return 1;
632  }
633  } else {
634  if (!fCurrent) fCurrent = (TEntryList*)fLists->First();
635  if (fCurrent->Remove(entry)){
636  if (fLists)
637  fN--;
638  return 1;
639  }
640  }
641  } else {
642  Int_t localentry = tree->LoadTree(entry);
643  SetTree(tree->GetTree());
644  if (fCurrent){
645  if (fCurrent->Remove(localentry)) {
646  if (fLists)
647  fN--;
648  return 1;
649  }
650  }
651  }
652  return 0;
653 }
654 
655 ////////////////////////////////////////////////////////////////////////////////
656 /// Return the number of the entry \#index of this TEntryList in the TTree or TChain
657 /// See also Next().
658 
660 {
661 
662  if (index>=fN){
663  return -1;
664  }
665  if (index==fLastIndexQueried+1){
666  //in a loop
667  return Next();
668  } else {
669  if (fBlocks) {
670  TEntryListBlock *block = 0;
671  Long64_t total_passed = 0;
672  Int_t i=0;
673  while (total_passed<=index && i<fNBlocks){
675  total_passed+=block->GetNPassed();
676  i++;
677  }
678  i--;
679  total_passed-=block->GetNPassed();
682  block->ResetIndices();
684  }
685 
686  Long64_t localindex = index - total_passed;
687  Long64_t blockindex = block->GetEntry(localindex);
688  if (blockindex < 0) return -1;
689  Long64_t res = i*kBlockSize + blockindex;
690  fLastIndexQueried = index;
691  fLastIndexReturned = res;
692  return res;
693  } else {
694  //find the corresponding list
695  if (!fCurrent) fCurrent = (TEntryList*)fLists->First();
696  TIter next(fLists);
697  TEntryList *templist;
698  Long64_t ntotal = 0;
699  if (fCurrent){
700  //reset all indices of the current list
701  if (fCurrent->fBlocks){
702  Int_t currentblock = (fCurrent->fLastIndexReturned)/kBlockSize;
704  block->ResetIndices();
707  }
708  }
709  while ((templist = (TEntryList*)next())){
710  if (!fShift){
711  ntotal += templist->GetN();
712  } else {
713  if (templist->GetTreeNumber() >= 0)
714  ntotal += templist->GetN();
715  }
716  if (ntotal > index)
717  break;
718  }
719  fCurrent = templist;
720  if (!fCurrent) return -1;
721  Long64_t localentry = index - (ntotal - fCurrent->GetN());
722  fLastIndexQueried = index;
723  fLastIndexReturned = fCurrent->GetEntry(localentry);
724  return fLastIndexReturned;
725  }
726 
727  }
728  return -1;
729 }
730 
731 ////////////////////////////////////////////////////////////////////////////////
732 /// Return the index of "index"-th non-zero entry in the TTree or TChain
733 /// and the # of the corresponding tree in the chain
734 
736 {
737 //If shift is true, then when the requested entry is found in an entry list,
738 //for which there is no corresponding tree in the chain, this list is not
739 //taken into account, and entry from the next list with a tree is returned.
740 //Example:
741 //First sublist - 20 entries, second sublist - 5 entries, third sublist - 10 entries
742 //Second sublist doesn't correspond to any trees of the chain
743 //Then, when GetEntryAndTree(21, treenum, kTRUE) is called, first entry of the
744 //third sublist will be returned
745 
746  Long64_t result = GetEntry(index);
747  if (result < 0) {
748  treenum = -1;
749  return result;
750  }
751  R__ASSERT(fLists == nullptr || (fLists != nullptr && fCurrent != nullptr));
752  if (fCurrent)
753  treenum = fCurrent->fTreeNumber;
754  else
755  treenum = fTreeNumber;
756  if (treenum < 0)
757  return -1;
758 
759  return result;
760 }
761 
762 ////////////////////////////////////////////////////////////////////////////////
763 /// To be able to re-localize the entry-list we identify the file by just the
764 /// name and the anchor, i.e. we drop protocol, host, options, ...
765 /// The result in the form 'file#anchor' (or 'file', if no anchor is present)
766 /// is saved in 'fn'.
767 /// The function optionally (is 'local' is defined) checks file locality (i.e.
768 /// protocol 'file://') returning the result in '*local' .
769 
770 void TEntryList::GetFileName(const char *filename, TString &fn, Bool_t *local)
771 {
772  TUrl u(filename, kTRUE);
773  if (local) *local = (!strcmp(u.GetProtocol(), "file")) ? kTRUE : kFALSE;
774  if (strlen(u.GetAnchor()) > 0) {
775  fn.Form("%s#%s", u.GetFile(), u.GetAnchor());
776  } else {
777  fn = u.GetFile();
778  }
779  // Done
780  return;
781 }
782 
783 ////////////////////////////////////////////////////////////////////////////////
784 /// Return the entry list, corresponding to treename and filename
785 /// By default, the filename is first tried as is, and then, if the corresponding list
786 /// is not found, the filename is expanded to the absolute path, and compared again.
787 /// To avoid it, use option "ne"
788 
789 TEntryList *TEntryList::GetEntryList(const char *treename, const char *filename, Option_t *opt)
790 {
791  if (gDebug > 1)
792  Info("GetEntryList","tree: %s, file: %s",
793  (treename ? treename : "-"), (filename ? filename : "-"));
794 
795  if (!treename || !filename) return 0;
796  TString option = opt;
797  option.ToUpper();
798  Bool_t nexp = option.Contains("NE");
799 
800  TString fn;
801  Bool_t local;
802  GetFileName(filename, fn, &local);
803  if (nexp) local = kFALSE;
804 
805  if (gDebug > 1)
806  Info("GetEntryList", "file: %s, local? %d", filename, local);
807 
808  if (!fLists){
809  //there are no sublists
810  if (!strcmp(treename, fTreeName.Data()) && !(strcmp(fn.Data(), fFileName.Data()))){
811  return this;
812  } else {
813  //if the file is local, try the full name, unless "ne" option was specified
814  if (!nexp && local){
815  gSystem->ExpandPathName(fn);
816  if (!gSystem->IsAbsoluteFileName(fn))
818  fn = gSystem->UnixPathName(fn);
819  if (!strcmp(treename, fTreeName.Data()) && !(strcmp(fn.Data(), fFileName.Data())))
820  return this;
821  }
822  return 0;
823  }
824  }
825 
826  TString stotal = treename;
827  stotal.Append(fn);
828  ULong_t newhash = stotal.Hash();
829 
830  TIter next(fLists);
831  TEntryList *templist;
832  while ((templist = (TEntryList*)next())){
833  if (templist->fStringHash==0){
834  stotal = templist->fTreeName + templist->fFileName;
835  templist->fStringHash = stotal.Hash();
836  }
837  if (gDebug > 1)
838  Info("GetEntryList", "file: %s (fn: %s), hash: %lu, element hash: %lu",
839  filename, fn.Data(), newhash, templist->fStringHash);
840  if (newhash == templist->fStringHash){
841  if (!strcmp(templist->GetTreeName(), treename) && !strcmp(templist->GetFileName(), fn.Data())){
842  return templist;
843  }
844  }
845  }
846 
847  //didn't find anything for this filename, try the full name too
848  if (!nexp && local){
849  TString longname = fn;
850  gSystem->ExpandPathName(longname);
851  if (!gSystem->IsAbsoluteFileName(longname))
852  gSystem->PrependPathName(gSystem->pwd(), longname);
853  longname = gSystem->UnixPathName(longname);
854  stotal = treename;
855  stotal.Append(longname);
856  newhash = stotal.Hash();
857  next.Reset();
858  while ((templist = (TEntryList*)next())){
859  if (templist->fStringHash==0){
860  stotal = templist->fTreeName + templist->fFileName;
861  templist->fStringHash = stotal.Hash();
862  }
863  if (gDebug > 1)
864  Info("GetEntryList", "file: %s (longname: %s), hash: %lu, element hash: %lu",
865  filename, longname.Data(), newhash, templist->fStringHash);
866  if (newhash == templist->fStringHash){
867  if (templist->fTreeName == treename && templist->fFileName == longname){
868  return templist;
869  }
870  }
871  }
872  }
873  return 0;
874 }
875 
876 ////////////////////////////////////////////////////////////////////////////////
877 /// Merge this list with the lists from the collection
878 
880 {
881  if (!list) return -1;
882  TIter next(list);
883  TEntryList *elist = 0;
884  while ((elist = (TEntryList*)next())) {
885  if (!elist->InheritsFrom(TEntryList::Class())) {
886  Error("Add","Attempt to add object of class: %s to a %s",elist->ClassName(),this->ClassName());
887  return -1;
888  }
889  Add(elist);
890  }
891  return 0;
892 }
893 
894 ////////////////////////////////////////////////////////////////////////////////
895 /// Return the next non-zero entry index (next after fLastIndexQueried)
896 /// this function is faster than GetEntry()
897 
899 {
900  Long64_t result;
901  if (fN == fLastIndexQueried+1 || fN==0){
902  return -1;
903  }
904  if (fBlocks){
906  TEntryListBlock *current_block = (TEntryListBlock*)fBlocks->UncheckedAt(iblock);
907  result = current_block->Next();
908  if (result>=0) {
910  fLastIndexReturned = result+kBlockSize*iblock;
911  return fLastIndexReturned;
912  }
913  else {
914  while (result<0 && iblock<fNBlocks-1) {
915  current_block->ResetIndices();
916  iblock++;
917  current_block = (TEntryListBlock*)fBlocks->UncheckedAt(iblock);
918  current_block->ResetIndices();
919  result = current_block->Next();
920  }
921  if (result<0) {
922  fLastIndexQueried = -1;
923  fLastIndexReturned = 0;
924  return -1;
925  }
927  fLastIndexReturned = result+kBlockSize*iblock;
928 
929  return fLastIndexReturned;
930  }
931  } else {
932  if (!fCurrent) {
934  if (!fCurrent) return 0;
935  if (fShift) {
936  while (fCurrent->GetTreeNumber()<0) {
938  if (!fCurrent) return 0;
939  }
940  }
941  }
942  result = fCurrent->Next();
943  if (result>=0) {
945  fLastIndexReturned = result;
946  return result;
947  } else {
948  if (fCurrent){
949  //reset all indices of the current list
950  if (fCurrent->fBlocks){
951  Int_t currentblock = (fCurrent->fLastIndexReturned)/kBlockSize;
953  block->ResetIndices();
956  }
957  }
958 
959  //find the list with the next non-zero entry
960  while (result<0 && fCurrent!=((TEntryList*)fLists->Last())){
961  if (!fCurrent) return 0;
965  // fCurrent is guarantee to be non-zero because it is not the 'last'
966  // element of the list.
967  if (!fCurrent) return 0;
968  if (!fShift)
969  result = fCurrent->Next();
970  else {
971  if (fCurrent->GetTreeNumber() >= 0)
972  result = fCurrent->Next();
973  }
974  }
976  fLastIndexReturned = result;
977  return result;
978  }
979  }
980 }
981 
982 ////////////////////////////////////////////////////////////////////////////////
983 /// Checks if the array representation is more economical and if so, switches to it
984 
986 {
987  if (fBlocks){
988  TEntryListBlock *block = 0;
989  for (Int_t i=0; i<fNBlocks; i++){
991  block->OptimizeStorage();
992  }
993  }
994 }
995 
996 ////////////////////////////////////////////////////////////////////////////////
997 /// Print this list
998 /// - option = "" - default - print the name of the tree and file
999 /// - option = "all" - print all the entry numbers
1000 
1001 void TEntryList::Print(const Option_t* option) const
1002 {
1003  TString opt = option;
1004  opt.ToUpper();
1005  if (fBlocks) {
1006  Printf("%s %s %lld", fTreeName.Data(), fFileName.Data(), fN);
1007  if (opt.Contains("A")){
1008  TEntryListBlock* block = 0;
1009  for (Int_t i=0; i<fNBlocks; i++){
1011  Int_t shift = i*kBlockSize;
1012  block->PrintWithShift(shift);
1013  }
1014  }
1015  }
1016  else {
1017  TEntryList *elist = 0;
1018  if (fN>0){
1019  TIter next(fLists);
1020  while((elist = (TEntryList*)next())){
1021  elist->Print(option);
1022  }
1023  } else {
1024  if (!fLists) Printf("%s %s %lld", fTreeName.Data(), fFileName.Data(), fN);
1025  else {
1026  TIter next(fLists);
1027  while ((elist = (TEntryList*)next())){
1028  Printf("%s %s %lld", elist->GetTreeName(), elist->GetFileName(), elist->GetN());
1029  }
1030  }
1031  }
1032  }
1033 }
1034 
1035 ////////////////////////////////////////////////////////////////////////////////
1036 /// Reset this list
1037 
1038 void TEntryList::Reset()
1039 {
1040  //Maybe not delete, but just reset the number of blocks to 0????
1041 
1042  if (fBlocks){
1043  fBlocks->Delete();
1044  delete fBlocks;
1045  fBlocks = 0;
1046  }
1047  if (fLists){
1048  if (!((TEntryList*)fLists->First())->GetDirectory()){
1049  fLists->Delete();
1050  }
1051  delete fLists;
1052  fLists = 0;
1053  }
1054  fCurrent = 0;
1055  fBlocks = 0;
1056  fNBlocks = 0;
1057  fN = 0;
1058  fTreeName = "";
1059  fFileName = "";
1060  fStringHash = 0;
1061  fTreeNumber = -1;
1062  fLastIndexQueried = -1;
1063  fLastIndexReturned = 0;
1064  fReapply = kFALSE;
1065 }
1066 
1067 ////////////////////////////////////////////////////////////////////////////////
1068 /// Add reference to directory dir. dir can be 0.
1069 
1071 {
1072  if (fDirectory == dir) return;
1073  if (fDirectory) fDirectory->Remove(this);
1074  fDirectory = dir;
1075  if (fDirectory) fDirectory->Append(this);
1076 }
1077 
1078 ////////////////////////////////////////////////////////////////////////////////
1079 /// If a list for a tree with such name and filename exists, sets it as the current sublist
1080 /// If not, creates this list and sets it as the current sublist
1081 ///
1082 /// ! the filename is taken as provided, no extensions to full path or url !
1083 
1084 void TEntryList::SetTree(const char *treename, const char *filename)
1085 {
1086  TEntryList *elist = 0;
1087 
1088  TString fn;
1089  GetFileName(filename, fn);
1090 
1091  TString stotal = treename;
1092  stotal.Append(fn.Data());
1093  //printf("setting tree %s\n", stotal.Data());
1094  ULong_t newhash = stotal.Hash();
1095  if (fLists) {
1096  //find the corresponding entry list and make it current
1097  if (!fCurrent) fCurrent = (TEntryList*)fLists->First();
1098  if (fCurrent->fStringHash == 0){
1099  stotal = fCurrent->fTreeName + fCurrent->fFileName;
1100  fCurrent->fStringHash = stotal.Hash();
1101  }
1102  if (newhash == fCurrent->fStringHash){
1103  //this list is current
1104  if (!strcmp(fCurrent->fTreeName, treename) && !strcmp(fCurrent->fFileName, fn.Data())){
1105  return;
1106  }
1107  }
1108  TIter next(fLists);
1109  while ((elist = (TEntryList*)next())){
1110  if (newhash == elist->fStringHash){
1111  if (elist->fTreeName == treename && elist->fFileName == fn.Data()) {
1112  //the current entry list was changed. reset the fLastIndexQueried,
1113  //so that Next() doesn't start with the wrong current list
1114  //Also, reset those indices in the previously current list
1115  if (fCurrent->fBlocks){
1116  Int_t currentblock = (fCurrent->fLastIndexReturned)/kBlockSize;
1118  block->ResetIndices();
1121  }
1122  fCurrent = elist;
1123  fLastIndexQueried = -3;
1124  return;
1125  }
1126  }
1127  }
1128  //didn't find an entry list for this tree, create a new one
1129  elist = new TEntryList("", "", treename, fn.Data());
1130  if (elist->GetDirectory()) {
1131  //sub lists are not added to the current directory
1132  elist->GetDirectory()->Remove(elist);
1133  elist->SetDirectory(0);
1134  }
1135  fLists->Add(elist);
1136  fCurrent = elist;
1137  return;
1138  } else {
1139  if (fN==0 && fTreeName=="" && fFileName==""){
1140  //this is the first tree set to this list
1141  fTreeName = treename;
1142  fFileName = fn;
1143  stotal = fTreeName + fFileName;
1144  //fStringHash = stotal.Hash();
1145  fStringHash = newhash;
1146  fCurrent = this;
1147  } else {
1148  if (fStringHash == 0){
1149  stotal = fTreeName + fFileName;
1150  fStringHash = stotal.Hash();
1151  }
1152  if (newhash != fStringHash){
1153  //we have a chain and already have an entry list for the first tree
1154  //move the first entry list to the fLists
1155  fLists = new TList();
1156  elist = new TEntryList();
1157  elist->fTreeName = fTreeName;
1158  elist->fFileName = fFileName;
1159  elist->fStringHash = fStringHash;
1160  elist->fN = fN;
1161  elist->fTreeNumber = fTreeNumber;
1162  elist->fBlocks = fBlocks;
1163  fBlocks = 0;
1164  elist->fNBlocks = fNBlocks;
1165  fLists->Add(elist);
1166  elist = new TEntryList("", "", treename, fn.Data());
1167  if (elist->GetDirectory()) {
1168  //sub lists are not added to the current directory
1169  elist->GetDirectory()->Remove(elist);
1170  elist->SetDirectory(0);
1171  }
1172  fLists->Add(elist);
1173  fCurrent = elist;
1174  //the current entry list was changed. reset the fLastIndexQueried,
1175  //so that Next() doesn't start with the wrong current list
1176  fLastIndexQueried = -3;
1177 
1178  }
1179  else {
1180  //same tree as in the current entry list, don't do anything
1181  return;
1182  }
1183  }
1184  }
1185 }
1186 
1187 ////////////////////////////////////////////////////////////////////////////////
1188 /// If a list for a tree with such name and filename exists, sets it as the current sublist
1189 /// If not, creates this list and sets it as the current sublist
1190 /// The name of the file, where the tree is, is taken as
1191 /// `tree->GetTree()->GetCurrentFile()->GetName()`, and then expanded either to the absolute path,
1192 /// or to full url. If, for some reason, you want to provide
1193 /// the filename in a different format, use SetTree(const char *treename, const char *filename),
1194 /// where the filename is taken "as is".
1195 
1196 void TEntryList::SetTree(const TTree *tree)
1197 {
1198  if (!tree) return;
1199  auto thisTree = tree->GetTree();
1200  if (!thisTree) return;
1201 
1202  TString treename;
1203  if (tree->GetDirectory()->InheritsFrom("TFile")) {
1204  treename = thisTree->GetName();
1205  } else {
1206  treename = TString::Format("%s/%s",tree->GetDirectory()->GetName(),thisTree->GetName());
1207  }
1208 
1209  TString filename;
1210  if (tree->GetTree()->GetCurrentFile()){
1211  filename = tree->GetTree()->GetCurrentFile()->GetName();
1212  TUrl url(filename.Data(), kTRUE);
1213  if (!strcmp(url.GetProtocol(), "file")){
1214  gSystem->ExpandPathName(filename);
1215  if (!gSystem->IsAbsoluteFileName(filename))
1216  gSystem->PrependPathName(gSystem->pwd(), filename);
1217  filename = gSystem->UnixPathName(filename);
1218  url.SetFile(filename);
1219  }
1220  filename = url.GetUrl();
1221  } else {
1222  //memory-resident
1223  filename = "";
1224  }
1225  SetTree(treename, filename);
1226 
1227 }
1228 
1229 ////////////////////////////////////////////////////////////////////////////////
1230 /// Remove all the entries of this entry list, that are contained in elist
1231 
1232 void TEntryList::Subtract(const TEntryList *elist)
1233 {
1234  TEntryList *templist = 0;
1235  if (!fLists){
1236  if (!fBlocks) return;
1237  //check if lists are for the same tree
1238  if (!elist->fLists){
1239  //second list is also only for 1 tree
1240  if (!strcmp(elist->fTreeName.Data(),fTreeName.Data()) &&
1241  !strcmp(elist->fFileName.Data(),fFileName.Data())){
1242  //same tree
1243  Long64_t n2 = elist->GetN();
1244  Long64_t entry;
1245  for (Int_t i=0; i<n2; i++){
1246  entry = (const_cast<TEntryList*>(elist))->GetEntry(i);
1247  Remove(entry);
1248  }
1249  } else {
1250  //different trees
1251  return;
1252  }
1253  } else {
1254  //second list has sublists, try to find one for the same tree as this list
1255  TIter next1(elist->GetLists());
1256  templist = 0;
1257  Bool_t found = kFALSE;
1258  while ((templist = (TEntryList*)next1())){
1259  if (!strcmp(templist->fTreeName.Data(),fTreeName.Data()) &&
1260  !strcmp(templist->fFileName.Data(),fFileName.Data())){
1261  found = kTRUE;
1262  break;
1263  }
1264  }
1265  if (found) {
1266  Subtract(templist);
1267  }
1268  }
1269  } else {
1270  //this list has sublists
1271  TIter next2(fLists);
1272  templist = 0;
1273  Long64_t oldn=0;
1274  while ((templist = (TEntryList*)next2())){
1275  oldn = templist->GetN();
1276  templist->Subtract(elist);
1277  fN = fN - oldn + templist->GetN();
1278  }
1279  }
1280  return;
1281 }
1282 
1283 ////////////////////////////////////////////////////////////////////////////////
1284 
1285 TEntryList operator||(TEntryList &elist1, TEntryList &elist2)
1286 {
1287  TEntryList eresult = elist1;
1288  //eresult = elist1;
1289  // printf("internal in operator1\n");
1290  eresult.Print("all");
1291  eresult.Add(&elist2);
1292  // printf("internal in operator2\n");
1293  eresult.Print("all");
1294 
1295  return eresult;
1296 }
1297 
1298 ////////////////////////////////////////////////////////////////////////////////
1299 /// Relocate the file paths.
1300 /// If `oldroot` is defined, replace `oldroot` with `newroot` in all file names,
1301 /// i.e. `oldroot/re/st/of/the/path` will become `newroot`/re/st/of/the/path`.
1302 /// If `oldroot` is null, the new path will be just `newroot/path`.
1303 /// Relocation is mandatory to use the entry-list with the same dataset at a different
1304 /// location (i.e. on a different cluster, machine or disks).
1305 
1306 Int_t TEntryList::RelocatePaths(const char *newroot, const char *oldroot)
1307 {
1308  // At least newroot must be given
1309  if (!newroot || (newroot && strlen(newroot) <= 0)) {
1310  Warning("RelocatePaths", "the new location must be given!");
1311  return -1;
1312  }
1313 
1314  if (strlen(GetName()) > 0)
1315  Info("RelocatePaths", "'%s': relocating paths '%s' to '%s'",
1316  GetName(), oldroot ? oldroot : "*", newroot);
1317 
1318  Int_t nrl = 0, xnrl = 0;
1319  // Apply to all underlying lists, if any
1320  if (fLists) {
1321  TIter nxl(fLists);
1322  TEntryList *enl = 0;
1323  while ((enl = (TEntryList *) nxl())) {
1324  if ((xnrl = enl->RelocatePaths(newroot, oldroot)) < 0) {
1325  Warning("RelocatePaths", "problems relocating '%s'", enl->GetName());
1326  } else {
1327  nrl += xnrl;
1328  }
1329  }
1330  }
1331  // Apply to ourselves
1332  TString temp;
1333  Ssiz_t lo = 0;
1334  if (oldroot && (lo = strlen(oldroot)) > 0) {
1335  if (fFileName.BeginsWith(oldroot)) {
1336  fFileName.Replace(0, lo, newroot);
1337  nrl++;
1338  }
1339  } else {
1340  Ssiz_t ilst = fFileName.Last('/');
1341  if (ilst != kNPOS) {
1342  fFileName.Replace(0, ilst, newroot);
1343  } else {
1344  fFileName.Insert(0, TString::Format("%s/", newroot));
1345  }
1346  nrl++;
1347  }
1348  if (fStringHash != 0) {
1349  temp.Form("%s%s", fTreeName.Data(), fFileName.Data());
1350  fStringHash = temp.Hash();
1351  }
1352 
1353  // Done
1354  return nrl;
1355 }
1356 
1357 ////////////////////////////////////////////////////////////////////////////////
1358 /// Relocate entry list 'enlnm' in file 'fn' replacing 'oldroot' with 'newroot' in
1359 /// filenames. If 'enlnm' is null or '*' all entry lists in the file are relocated.
1360 /// Relocation is mandatory to use the entry-list with the same dataset at a different
1361 /// location (i.e. on a different cluster, machine or disks).
1362 /// This function can be called as many times as need to reach the desired result.
1363 /// The existing 'locations' can be checked qith TEntryList::Scan .
1364 
1365 Int_t TEntryList::Relocate(const char *fn,
1366  const char *newroot, const char *oldroot, const char *enlnm)
1367 {
1368  // Open the file for updating
1369  TFile *fl = TFile::Open(fn, "UPDATE");
1370  if (!fl || (fl&& fl->IsZombie())) {
1371  ::Error("TEntryList::Relocate", "file '%s' cannot be open for updating", fn);
1372  return -1;
1373  }
1374 
1375  Int_t nrl = 0;
1376  // Read the lists
1377  TString nm(enlnm);
1378  if (nm.IsNull()) nm = "*";
1379  TRegexp nmrg(nm, kTRUE);
1380  TIter nxk(fl->GetListOfKeys());
1381  TKey *key = 0;
1382  while ((key = (TKey *) nxk())) {
1383  if (!strcmp(key->GetClassName(), "TEntryList")) {
1384  TString knm(key->GetName());
1385  if (knm.Index(nmrg) != kNPOS) {
1386  TEntryList *enl = dynamic_cast<TEntryList *>(fl->Get(knm));
1387  if (enl) {
1388  Int_t xnrl = enl->RelocatePaths(newroot, oldroot);
1389  if (xnrl >= 0) {
1390  enl->Write(knm, TObject::kOverwrite);
1391  nrl += xnrl;
1392  } else {
1393  ::Error("TEntryList::Relocate", "problems relocating '%s' ...", enl->GetName());
1394  }
1395  }
1396  }
1397  }
1398  }
1399  // Close the file
1400  fl->Close();
1401  delete fl;
1402  // Done
1403  return nrl;
1404 }
1405 
1406 ////////////////////////////////////////////////////////////////////////////////
1407 /// Get in 'c' the string in common at the beginning of 'a' and 'b'
1408 ///
1409 /// Return:
1410 /// - 0 a and b are not contained in each other, i.e. c != a && c != b
1411 /// - 1 a is contained in b, i.e. c == a (includes a == empty)
1412 /// - 2 b is contained in a, i.e. c == b (includes b == empty)
1413 /// - 3 b is a, i.e. c == b == a (includes a == b == empty)
1414 /// Auxiliary function for path scans.
1415 
1417 {
1418  if (a == b) {
1419  c = a;
1420  return 3;
1421  }
1422  if (a.IsNull()) {
1423  c = "";
1424  return 1;
1425  }
1426  if (b.IsNull()) {
1427  c = "";
1428  return 2;
1429  }
1430  Bool_t ashort = (a.Length() > b.Length()) ? kFALSE : kTRUE;
1431  Ssiz_t len = (ashort) ? a.Length() : b.Length();
1432  Int_t lcom = 0;
1433  for (Int_t i = 0; i < len; i++) {
1434  if (a[i] != b[i]) break;
1435  lcom++;
1436  }
1437  if (lcom == len) {
1438  c = ashort ? a : b;
1439  return ashort ? 1 : 2;
1440  }
1441  c = a(0,lcom);
1442  // Done
1443  return 0;
1444 }
1445 
1446 ////////////////////////////////////////////////////////////////////////////////
1447 /// Scan the paths to find the common roots. If 'roots' is defined, add
1448 /// the found roots to the list as TObjStrings.
1449 /// Return the number of roots found.
1450 
1452 {
1453  TList *xrl = roots ? roots : new TList;
1454 
1455  Int_t nrl = 0;
1456  // Apply to all underlying lists, if any
1457  if (fLists) {
1458  TIter nxl(fLists);
1459  TEntryList *enl = 0;
1460  while ((enl = (TEntryList *) nxl()))
1461  nrl += enl->ScanPaths(xrl, kFALSE);
1462  }
1463  // Apply to ourselves
1464  Bool_t newobjs = kTRUE;
1465  TString path = gSystem->GetDirName(fFileName), com;
1466  TObjString *objs = nullptr;
1467  TIter nxr(xrl);
1468  while ((objs = (TObjString *) nxr())) {
1469  Int_t rc = 0;
1470  if ((rc = GetCommonString(path, objs->GetString(), com)) != 2) {
1471  TUrl ucom(com);
1472  if (strlen(ucom.GetFile()) > 0 && strcmp(ucom.GetFile(), "/")) {
1473  objs->SetString(com.Data());
1474  newobjs = kFALSE;
1475  break;
1476  }
1477  }
1478  }
1479  if (newobjs) xrl->Add(new TObjString(path));
1480 
1481  // Done
1482  nrl = xrl->GetSize();
1483  if (notify) {
1484  Printf(" * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ *");
1485  Printf(" * Entry-list: %s", GetName());
1486  Printf(" * %d common root paths found", nrl);
1487  nxr.Reset();
1488  while ((objs = (TObjString *) nxr())) {
1489  Printf(" * %s", objs->GetName());
1490  }
1491  Printf(" * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ *");
1492  }
1493 
1494  if (xrl != roots) {
1495  xrl->SetOwner(kTRUE);
1496  SafeDelete(xrl);
1497  }
1498 
1499  // Done
1500  return nrl;
1501 }
1502 
1503 ////////////////////////////////////////////////////////////////////////////////
1504 /// Scan TEntryList in 'fn' to find the common parts of paths.
1505 /// If 'roots' is defined, add the found roots to the list as TObjStrings.
1506 /// Return the number of common root paths found.
1507 
1508 Int_t TEntryList::Scan(const char *fn, TList *roots)
1509 {
1510  // Open the file for updating
1511  TFile *fl = TFile::Open(fn);
1512  if (!fl || (fl&& fl->IsZombie())) {
1513  ::Error("TEntryList::Relocate", "file '%s' cannot be open for reading", fn);
1514  return -1;
1515  }
1516 
1517  Int_t nrs = 0;
1518  // Read the lists
1519  TIter nxk(fl->GetListOfKeys());
1520  TKey *key = 0;
1521  while ((key = (TKey *) nxk())) {
1522  if (!strcmp(key->GetClassName(), "TEntryList")) {
1523  TEntryList *enl = dynamic_cast<TEntryList *>(fl->Get(key->GetName()));
1524  if (enl) {
1525  nrs += enl->ScanPaths(roots);
1526  } else {
1527  ::Error("TEntryList::Scan", "object entry-list '%s' not found or not loadable!", key->GetName());
1528  }
1529  }
1530  }
1531  // Close the file
1532  fl->Close();
1533  delete fl;
1534 
1535  // Done
1536  return nrs;
1537 }
1538 
1539 ////////////////////////////////////////////////////////////////////////////////
1540 /// Custom streamer for class TEntryList to handle the different interpretation
1541 /// of fFileName between version 1 and >1 .
1542 
1543 void TEntryList::Streamer(TBuffer &b)
1544 {
1545  if (b.IsReading()) {
1546  UInt_t R__s, R__c;
1547  Version_t R__v = b.ReadVersion(&R__s, &R__c);
1548  b.ReadClassBuffer(TEntryList::Class(), this, R__v, R__s, R__c);
1549  if (R__v <= 1) {
1550  // The filename contained also the protocol and host: this was dropped
1551  // in version > 1 to allow re-localization
1553  }
1554  } else {
1555  b.WriteClassBuffer(TEntryList::Class(), this);
1556  }
1557 }
c
#define c(i)
Definition: RSha256.hxx:101
TEntryList::DirectoryAutoAdd
virtual void DirectoryAutoAdd(TDirectory *)
Called by TKey and others to automatically add us to a directory when we are read from a file.
Definition: TEntryList.cxx:548
TEntryList::TEntryList
TEntryList()
default c-tor
Definition: TEntryList.cxx:161
TDirectory::Remove
virtual TObject * Remove(TObject *)
Remove an object from the in-memory list.
Definition: TDirectory.cxx:1155
kTRUE
const Bool_t kTRUE
Definition: RtypesCore.h:91
TObjArray::Delete
virtual void Delete(Option_t *option="")
Remove all objects from the array AND delete all heap based objects.
Definition: TObjArray.cxx:356
TEntryList::GetDirectory
virtual TDirectory * GetDirectory() const
Definition: TEntryList.h:74
Version_t
short Version_t
Definition: RtypesCore.h:65
TObjArray
An array of TObjects.
Definition: TObjArray.h:37
Option_t
const char Option_t
Definition: RtypesCore.h:66
TEntryList::GetTreeName
virtual const char * GetTreeName() const
Definition: TEntryList.h:76
TEntryList::Remove
virtual Bool_t Remove(Long64_t entry, TTree *tree=0)
Remove entry #entry from the list.
Definition: TEntryList.cxx:615
kNPOS
const Ssiz_t kNPOS
Definition: RtypesCore.h:115
TList::Delete
virtual void Delete(Option_t *option="")
Remove all objects from the list AND delete all heap based objects.
Definition: TList.cxx:469
TString::Data
const char * Data() const
Definition: TString.h:369
TSystem::IsAbsoluteFileName
virtual Bool_t IsAbsoluteFileName(const char *dir)
Return true if dir is an absolute pathname.
Definition: TSystem.cxx:950
TEntryList::fTreeName
TString fTreeName
name of the tree
Definition: TEntryList.h:38
tree
Definition: tree.py:1
ClassImp
#define ClassImp(name)
Definition: Rtypes.h:364
TObjString.h
TString::Replace
TString & Replace(Ssiz_t pos, Ssiz_t n, const char *s)
Definition: TString.h:682
TObject::Info
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:864
Long64_t
long long Long64_t
Definition: RtypesCore.h:73
TObject::Error
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:890
TTree
A TTree represents a columnar dataset.
Definition: TTree.h:79
TCollection::SetOwner
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
Definition: TCollection.cxx:746
TEntryList::fCurrent
TEntryList * fCurrent
! currently filled entry list
Definition: TEntryList.h:32
TFile::Open
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault, Int_t netopt=0)
Create / open a file.
Definition: TFile.cxx:3995
Int_t
int Int_t
Definition: RtypesCore.h:45
TObjString::GetString
const TString & GetString() const
Definition: TObjString.h:46
TEntryListBlock.h
TEntryListBlock::ResetIndices
void ResetIndices()
Definition: TEntryListBlock.h:74
TEntryList::OptimizeStorage
virtual void OptimizeStorage()
Checks if the array representation is more economical and if so, switches to it.
Definition: TEntryList.cxx:983
TEntryList::Scan
static Int_t Scan(const char *fn, TList *roots)
Scan TEntryList in 'fn' to find the common parts of paths.
Definition: TEntryList.cxx:1506
TEntryList::fLastIndexQueried
Long64_t fLastIndexQueried
! used to optimize GetEntry() function from a loop
Definition: TEntryList.h:44
TString::Hash
UInt_t Hash(ECaseCompare cmp=kExact) const
Return hash value.
Definition: TString.cxx:638
TString::Contains
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:624
SafeDelete
#define SafeDelete(p)
Definition: RConfig.hxx:543
TEntryList::fShift
Bool_t fShift
! true when some sub-lists don't correspond to trees (when the entry list is used as input in TChain)
Definition: TEntryList.h:46
roots
TCanvas * roots()
Definition: roots.C:1
operator||
TEntryList operator||(TEntryList &elist1, TEntryList &elist2)
Definition: TEntryList.cxx:1283
TList::Last
virtual TObject * Last() const
Return the last object in the list. Returns 0 when list is empty.
Definition: TList.cxx:692
TIter::Reset
void Reset()
Definition: TCollection.h:252
TObjString::SetString
void SetString(const char *s)
Definition: TObjString.h:45
TBuffer
Buffer base class used for serializing objects.
Definition: TBuffer.h:43
TEntryList::fLists
TList * fLists
a list of underlying entry lists for each tree of a chain
Definition: TEntryList.h:31
TSystem::PrependPathName
virtual const char * PrependPathName(const char *dir, TString &name)
Concatenate a directory and a file name.
Definition: TSystem.cxx:1079
TObjArray::UncheckedAt
TObject * UncheckedAt(Int_t i) const
Definition: TObjArray.h:90
TString::Format
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition: TString.cxx:2311
TEntryList::SetTree
virtual void SetTree(const TTree *tree)
If a list for a tree with such name and filename exists, sets it as the current sublist If not,...
Definition: TEntryList.cxx:1194
TTree.h
BatchHelpers::block
constexpr size_t block
Definition: BatchHelpers.h:29
TEntryList::~TEntryList
virtual ~TEntryList()
Destructor.
Definition: TEntryList.cxx:323
TString
Basic string class.
Definition: TString.h:136
Bool_t
bool Bool_t
Definition: RtypesCore.h:63
TObject::InheritsFrom
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition: TObject.cxx:445
b
#define b(i)
Definition: RSha256.hxx:100
TFile.h
TObjString::GetName
const char * GetName() const
Returns name of object.
Definition: TObjString.h:38
TSystem::GetDirName
virtual TString GetDirName(const char *pathname)
Return the directory name in pathname.
Definition: TSystem.cxx:1030
bool
TObjArray::Add
void Add(TObject *obj)
Definition: TObjArray.h:74
TString::Last
Ssiz_t Last(char c) const
Find last occurrence of a character c.
Definition: TString.cxx:892
TEntryList::fStringHash
ULong_t fStringHash
! Hash value of a string of treename and filename
Definition: TEntryList.h:40
TString::ToUpper
void ToUpper()
Change string to upper case.
Definition: TString.cxx:1138
TObject::kOverwrite
@ kOverwrite
overwrite existing object with same name
Definition: TObject.h:88
TObjString
Collectable string class.
Definition: TObjString.h:28
TList::First
virtual TObject * First() const
Return the first object in the list. Returns 0 when list is empty.
Definition: TList.cxx:658
TRegexp.h
TString::Form
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2289
TList::After
virtual TObject * After(const TObject *obj) const
Returns the object after object obj.
Definition: TList.cxx:329
TDirectoryFile::GetListOfKeys
TList * GetListOfKeys() const override
Definition: TDirectoryFile.h:93
TDirectoryFile::Get
TObject * Get(const char *namecycle) override
Return pointer to object identified by namecycle.
Definition: TDirectoryFile.cxx:909
TDirectory::Append
virtual void Append(TObject *obj, Bool_t replace=kFALSE)
Append object to this directory.
Definition: TDirectory.cxx:191
TEntryList::GetEntry
virtual Long64_t GetEntry(Int_t index)
Return the number of the entry #index of this TEntryList in the TTree or TChain See also Next().
Definition: TEntryList.cxx:657
TBuffer.h
TSystem.h
TEntryList::fDirectory
TDirectory * fDirectory
! Pointer to directory holding this tree
Definition: TEntryList.h:48
TEntryListBlock::Next
Int_t Next()
Return the next non-zero entry Faster than GetEntry() function.
Definition: TEntryListBlock.cxx:446
TKey::GetClassName
virtual const char * GetClassName() const
Definition: TKey.h:76
TEntryList::GetLists
virtual TList * GetLists() const
Definition: TEntryList.h:73
TEntryList::Enter
virtual Bool_t Enter(Long64_t entry, TTree *tree=0)
Add entry #entry to the list.
Definition: TEntryList.cxx:560
a
auto * a
Definition: textangle.C:12
TEntryList::fBlocks
TObjArray * fBlocks
blocks with indices of passing events (TEntryListBlocks)
Definition: TEntryList.h:35
TNamed
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:29
kFALSE
const Bool_t kFALSE
Definition: RtypesCore.h:92
TString::Append
TString & Append(const char *cs)
Definition: TString.h:564
TUrl::SetFile
void SetFile(const char *file)
Definition: TUrl.h:85
TEntryList::fFileName
TString fFileName
name of the file, where the tree is
Definition: TEntryList.h:39
gDirectory
#define gDirectory
Definition: TDirectory.h:236
TEntryListBlock::Merge
Int_t Merge(TEntryListBlock *block)
Merge with the other block Returns the resulting number of entries in the block.
Definition: TEntryListBlock.cxx:242
gDebug
Int_t gDebug
Definition: TROOT.cxx:590
TString::Insert
TString & Insert(Ssiz_t pos, const char *s)
Definition: TString.h:649
UInt_t
unsigned int UInt_t
Definition: RtypesCore.h:46
TString::BeginsWith
Bool_t BeginsWith(const char *s, ECaseCompare cmp=kExact) const
Definition: TString.h:615
TEntryList::fReapply
Bool_t fReapply
If true, TTree::Draw will 'reapply' the original cut.
Definition: TEntryList.h:49
ULong_t
unsigned long ULong_t
Definition: RtypesCore.h:55
TSystem::ExpandPathName
virtual Bool_t ExpandPathName(TString &path)
Expand a pathname getting rid of special shell characters like ~.
Definition: TSystem.cxx:1272
TObject::Warning
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:876
TUrl::GetUrl
const char * GetUrl(Bool_t withDeflt=kFALSE) const
Return full URL.
Definition: TUrl.cxx:387
TUrl
This class represents a WWW compatible URL.
Definition: TUrl.h:33
TFile
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format.
Definition: TFile.h:54
TMath::Min
Short_t Min(Short_t a, Short_t b)
Definition: TMathBase.h:180
TRegexp
Regular expression class.
Definition: TRegexp.h:31
TEntryList
A List of entry numbers in a TTree or TChain.
Definition: TEntryList.h:26
TEntryList::GetFileName
void GetFileName(const char *filename, TString &fn, Bool_t *=0)
To be able to re-localize the entry-list we identify the file by just the name and the anchor,...
Definition: TEntryList.cxx:768
TUrl::GetFile
const char * GetFile() const
Definition: TUrl.h:69
TString::Index
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:639
TEntryList::Next
virtual Long64_t Next()
Return the next non-zero entry index (next after fLastIndexQueried) this function is faster than GetE...
Definition: TEntryList.cxx:896
TEntryList::Merge
virtual Int_t Merge(TCollection *list)
Merge this list with the lists from the collection.
Definition: TEntryList.cxx:877
Printf
void Printf(const char *fmt,...)
TUrl::GetProtocol
const char * GetProtocol() const
Definition: TUrl.h:64
TObject::IsZombie
R__ALWAYS_INLINE Bool_t IsZombie() const
Definition: TObject.h:134
gSystem
R__EXTERN TSystem * gSystem
Definition: TSystem.h:559
TKey
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition: TKey.h:28
Ssiz_t
int Ssiz_t
Definition: RtypesCore.h:67
TEntryListBlock::GetNPassed
Int_t GetNPassed()
Returns the number of entries, passing the selection.
Definition: TEntryListBlock.cxx:369
TEntryList::GetEntryAndTree
virtual Long64_t GetEntryAndTree(Int_t index, Int_t &treenum)
Return the index of "index"-th non-zero entry in the TTree or TChain and the # of the corresponding t...
Definition: TEntryList.cxx:733
R__ASSERT
#define R__ASSERT(e)
Definition: TError.h:120
TEntryList::Add
virtual void Add(const TEntryList *elist)
Add 2 entry lists.
Definition: TEntryList.cxx:345
TSystem::UnixPathName
virtual const char * UnixPathName(const char *unixpathname)
Convert from a local pathname to a Unix pathname.
Definition: TSystem.cxx:1061
TCollection::GetSize
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
Definition: TCollection.h:182
TEntryList::GetTreeNumber
virtual Int_t GetTreeNumber() const
Definition: TEntryList.h:78
TUrl::GetAnchor
const char * GetAnchor() const
Definition: TUrl.h:70
TEntryList::ScanPaths
virtual Int_t ScanPaths(TList *roots, Bool_t notify=kTRUE)
Scan the paths to find the common roots.
Definition: TEntryList.cxx:1449
TEntryList::Relocate
static Int_t Relocate(const char *fn, const char *newroot, const char *oldroot=0, const char *enlnm=0)
Relocate entry list 'enlnm' in file 'fn' replacing 'oldroot' with 'newroot' in filenames.
Definition: TEntryList.cxx:1363
TObject::Write
virtual Int_t Write(const char *name=0, Int_t option=0, Int_t bufsize=0)
Write this object to the current directory.
Definition: TObject.cxx:795
TList::Add
virtual void Add(TObject *obj)
Definition: TList.h:87
TEntryList::Print
virtual void Print(const Option_t *option="") const
Print this list.
Definition: TEntryList.cxx:999
TFile::Close
void Close(Option_t *option="") override
Close a file.
Definition: TFile.cxx:876
TEntryList::kBlockSize
@ kBlockSize
Definition: TEntryList.h:54
TEntryList.h
TEntryList::Subtract
virtual void Subtract(const TEntryList *elist)
Remove all the entries of this entry list, that are contained in elist.
Definition: TEntryList.cxx:1230
name
char name[80]
Definition: TGX11.cxx:110
TDirectory
Describe directory structure in memory.
Definition: TDirectory.h:40
TEntryListBlock
Used by TEntryList to store the entry numbers.
Definition: TEntryListBlock.h:44
TIter
Definition: TCollection.h:233
TEntryList::fLastIndexReturned
Long64_t fLastIndexReturned
! used to optimize GetEntry() function from a loop
Definition: TEntryList.h:45
TEntryList::GetFileName
virtual const char * GetFileName() const
Definition: TEntryList.h:77
TEntryList::RelocatePaths
virtual Int_t RelocatePaths(const char *newloc, const char *oldloc=0)
Relocate the file paths.
Definition: TEntryList.cxx:1304
TEntryList::Reset
virtual void Reset()
Reset this list.
Definition: TEntryList.cxx:1036
TCollection
Collection abstract base class.
Definition: TCollection.h:63
TNamed::GetName
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
TKey.h
TGeant4Unit::nm
static constexpr double nm
Definition: TGeant4SystemOfUnits.h:105
Class
void Class()
Definition: Class.C:29
GetCommonString
static Int_t GetCommonString(TString a, TString b, TString &c)
Get in 'c' the string in common at the beginning of 'a' and 'b'.
Definition: TEntryList.cxx:1414
TEntryList::fN
Long64_t fN
number of entries in the list
Definition: TEntryList.h:36
TEntryList::fTreeNumber
Int_t fTreeNumber
! the index of the tree in the chain (used when the entry list is used as input (TTree::SetEntryList(...
Definition: TEntryList.h:41
TObject::ClassName
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition: TObject.cxx:130
TEntryList::GetN
virtual Long64_t GetN() const
Definition: TEntryList.h:75
TEntryList::SetDirectory
virtual void SetDirectory(TDirectory *dir)
Add reference to directory dir. dir can be 0.
Definition: TEntryList.cxx:1068
TSystem::pwd
const char * pwd()
Definition: TSystem.h:422
TList
A doubly linked list.
Definition: TList.h:44
TEntryList::fNBlocks
Int_t fNBlocks
number of TEntryListBlocks
Definition: TEntryList.h:34
TEntryList::GetEntryList
virtual TEntryList * GetEntryList(const char *treename, const char *filename, Option_t *opt="")
Return the entry list, corresponding to treename and filename By default, the filename is first tried...
Definition: TEntryList.cxx:787
int
TError.h
TEntryList::Contains
virtual Int_t Contains(Long64_t entry, TTree *tree=0)
Definition: TEntryList.cxx:519
TEntryList::fEntriesToProcess
Long64_t fEntriesToProcess
used on proof to set the number of entries to process in a packet
Definition: TEntryList.h:37