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