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