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