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