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