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 = 0;
166 fCurrent = 0;
167 fBlocks = 0;
168 fN = 0;
169 fNBlocks = 0;
170 fTreeName = "";
171 fFileName = "";
172 fStringHash = 0;
173 fTreeNumber = -1;
174 fDirectory = 0;
178 fShift = kFALSE;
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 = 0;
189 fCurrent = 0;
190 fBlocks = 0;
191 fN = 0;
192 fNBlocks = 0;
193 fTreeName = "";
194 fFileName = "";
195 fStringHash = 0;
196 fTreeNumber = -1;
198
200 if (fDirectory) fDirectory->Append(this);
201
204 fShift = kFALSE;
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 = 0;
213 fCurrent = 0;
214 fBlocks = 0;
215 fN = 0;
216 fNBlocks = 0;
217 fTreeNumber = -1;
220
222 if (fDirectory) fDirectory->Append(this);
223
226 fShift = kFALSE;
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 = 0;
235 fCurrent = 0;
236 fBlocks = 0;
237 fNBlocks = 0;
238 fN = 0;
239 SetTree(treename, filename);
240 fTreeNumber = -1;
242
244 if (fDirectory) fDirectory->Append(this);
245
248 fShift = kFALSE;
249}
250
251////////////////////////////////////////////////////////////////////////////////
252/// c-tor, which sets the tree
253
254TEntryList::TEntryList(const TTree *tree) : fEntriesToProcess(0)
255{
256 fLists = 0;
257 fCurrent = 0;
258 fBlocks = 0;
259 fNBlocks = 0;
260 fN = 0;
261
262 SetTree(tree);
263 fTreeNumber = -1;
264
267 if (fDirectory) fDirectory->Append(this);
268
271 fShift = kFALSE;
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 = 0;
289 fBlocks = 0;
290 fReapply = elist.fReapply;
291 fCurrent = 0;
293 if (elist.fLists){
294 fLists = new TList();
295 TEntryList *el1 = 0;
296 TEntryList *el2 = 0;
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 = 0;
307 TEntryListBlock *block2 = 0;
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 = 0;
319
320}
321
322////////////////////////////////////////////////////////////////////////////////
323/// Destructor.
324
326{
327 if (fBlocks){
328 fBlocks->Delete();
329 delete fBlocks;
330 }
331 fBlocks = 0;
332 if (fLists){
333 fLists->Delete();
334 delete fLists;
335 }
336
337 fLists = 0;
338
339 if (fDirectory) fDirectory->Remove(this);
340 fDirectory = 0;
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 = 0;
377 TEntryList *el2 = 0;
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 = 0;
388 TEntryListBlock *block2 = 0;
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 = 0;
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 = 0;
412 TEntryListBlock *block2 = 0;
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=0;
425 TEntryListBlock *block2=0;
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 = 0;
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 = 0;
470 }
471 } else {
472 //second list already has sublists. add one by one
473 TEntryList *el = 0;
474 TIter next(elist->fLists);
475 while ((el = (TEntryList*)next())){
476 Add(el);
477 }
478 fCurrent = 0;
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 = 0;
486 Bool_t found = kFALSE;
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 = kTRUE;
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 = 0;
509 TIter next(elist->fLists);
510 while ((el = (TEntryList*)next())){
511 Add(el);
512 }
513 fCurrent = 0;
514 }
515 if (fCurrent){
516 if (fCurrent->fBlocks){
519 block->ResetIndices();
522 }
523 }
524 fCurrent = 0;
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 = 0;
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
628{
629 if (!tree){
630 if (!fLists) {
631 if (!fBlocks) fBlocks = new TObjArray();
632 TEntryListBlock *block = 0;
633 Long64_t nblock = entry/kBlockSize;
634 if (nblock >= fNBlocks) {
635 if (fNBlocks>0){
637 if (!block) return 0;
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 1;
650 }
651 } else {
652 //the entry in the current entry list
654 if (fCurrent->Enter(entry)) {
655 if (fLists)
656 fN++;
657 return 1;
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 1;
668 }
669 }
670 }
671 return 0;
672
673}
674
675/////////////////////////////////////////////////////////////////////////////
676/// \brief Enter all entries in a range in the TEntryList.
677/// \param[in] start starting entry to enter.
678/// \param[in] end ending entry to enter.
679/// \param[in] tree passed as is to TEntryList::Enter.
680/// \param[in] step step increase of the loop entering the entries.
681///
682/// This is a helper function that enters all entries between \p start
683/// (inclusive) and \p end (exclusive) to the TEntryList in a loop. It
684/// is useful also in PyROOT to avoid having to do the same in a Python loop.
685
687{
688 for (auto entry = start; entry < end; entry += step) {
689 this->Enter(entry, tree);
690 }
691}
692
693////////////////////////////////////////////////////////////////////////////////
694/// Remove entry \#entry from the list
695/// - When tree = 0, removes from the current list
696/// - When tree != 0, finds the list, corresponding to this tree
697/// - When tree is a chain, the entry is assumed to be global index and the local
698/// entry is recomputed from the treeoffset information of the chain
699
701{
702 if (entry < 0)
703 return kFALSE;
704 if (!tree) {
705 if (!fLists) {
706 if (!fBlocks) return 0;
707 TEntryListBlock *block = 0;
708 Long64_t nblock = entry/kBlockSize;
709 block = (TEntryListBlock*)fBlocks->UncheckedAt(nblock);
710 if (!block) return 0;
711 Long64_t blockindex = entry - nblock*kBlockSize;
712 if (block->Remove(blockindex)){
713 fN--;
714 return 1;
715 }
716 } else {
718 if (fCurrent->Remove(entry)){
719 if (fLists)
720 fN--;
721 return 1;
722 }
723 }
724 } else {
725 Int_t localentry = tree->LoadTree(entry);
726 SetTree(tree->GetTree());
727 if (fCurrent){
728 if (fCurrent->Remove(localentry)) {
729 if (fLists)
730 fN--;
731 return 1;
732 }
733 }
734 }
735 return 0;
736}
737
738////////////////////////////////////////////////////////////////////////////////
739/// Return the number of the entry \#index of this TEntryList in the TTree or TChain
740/// See also Next().
741
743{
744
745 if ((index>=fN) || (index<0)) {
746 return -1;
747 }
748 if (index==fLastIndexQueried+1){
749 //in a loop
750 return Next();
751 } else {
752 if (fBlocks) {
753 TEntryListBlock *block = 0;
754 Long64_t total_passed = 0;
755 Int_t i=0;
756 while (total_passed<=index && i<fNBlocks){
758 total_passed+=block->GetNPassed();
759 i++;
760 }
761 i--;
762 total_passed-=block->GetNPassed();
765 block->ResetIndices();
766 block = (TEntryListBlock*)fBlocks->UncheckedAt(i);
767 }
768
769 Long64_t localindex = index - total_passed;
770 Long64_t blockindex = block->GetEntry(localindex);
771 if (blockindex < 0) return -1;
772 Long64_t res = i*kBlockSize + blockindex;
773 fLastIndexQueried = index;
774 fLastIndexReturned = res;
775 return res;
776 } else {
777 //find the corresponding list
779 TIter next(fLists);
780 TEntryList *templist;
781 Long64_t ntotal = 0;
782 if (fCurrent){
783 //reset all indices of the current list
784 if (fCurrent->fBlocks){
787 block->ResetIndices();
790 }
791 }
792 while ((templist = (TEntryList*)next())){
793 if (!fShift){
794 ntotal += templist->GetN();
795 } else {
796 if (templist->GetTreeNumber() >= 0)
797 ntotal += templist->GetN();
798 }
799 if (ntotal > index)
800 break;
801 }
802 fCurrent = templist;
803 if (!fCurrent) return -1;
804 Long64_t localentry = index - (ntotal - fCurrent->GetN());
805 fLastIndexQueried = index;
806 fLastIndexReturned = fCurrent->GetEntry(localentry);
807 return fLastIndexReturned;
808 }
809
810 }
811 return -1;
812}
813
814////////////////////////////////////////////////////////////////////////////////
815/// Return the index of "index"-th non-zero entry in the TTree or TChain
816/// and the # of the corresponding tree in the chain
817
819{
820//If shift is true, then when the requested entry is found in an entry list,
821//for which there is no corresponding tree in the chain, this list is not
822//taken into account, and entry from the next list with a tree is returned.
823//Example:
824//First sublist - 20 entries, second sublist - 5 entries, third sublist - 10 entries
825//Second sublist doesn't correspond to any trees of the chain
826//Then, when GetEntryAndTree(21, treenum, kTRUE) is called, first entry of the
827//third sublist will be returned
828
829 Long64_t result = GetEntry(index);
830 if (result < 0) {
831 treenum = -1;
832 return result;
833 }
834 R__ASSERT(fLists == nullptr || (fLists != nullptr && fCurrent != nullptr));
835 if (fCurrent)
836 treenum = fCurrent->fTreeNumber;
837 else
838 treenum = fTreeNumber;
839 if (treenum < 0)
840 return -1;
841
842 return result;
843}
844
845////////////////////////////////////////////////////////////////////////////////
846/// To be able to re-localize the entry-list we identify the file by just the
847/// name and the anchor, i.e. we drop protocol, host, options, ...
848/// The result in the form 'file#anchor' (or 'file', if no anchor is present)
849/// is saved in 'fn'.
850/// The function optionally (is 'local' is defined) checks file locality (i.e.
851/// protocol 'file://') returning the result in '*local' .
852
853void TEntryList::GetFileName(const char *filename, TString &fn, Bool_t *local)
854{
855 TUrl u(filename, kTRUE);
856 if (local) *local = (!strcmp(u.GetProtocol(), "file")) ? kTRUE : kFALSE;
857 if (strlen(u.GetAnchor()) > 0) {
858 fn.Form("%s#%s", u.GetFile(), u.GetAnchor());
859 } else {
860 fn = u.GetFile();
861 }
862 // Done
863 return;
864}
865
866////////////////////////////////////////////////////////////////////////////////
867/// Return the entry list, corresponding to treename and filename
868/// By default, the filename is first tried as is, and then, if the corresponding list
869/// is not found, the filename is expanded to the absolute path, and compared again.
870/// To avoid it, use option "ne"
871
872TEntryList *TEntryList::GetEntryList(const char *treename, const char *filename, Option_t *opt)
873{
874 if (gDebug > 1)
875 Info("GetEntryList","tree: %s, file: %s",
876 (treename ? treename : "-"), (filename ? filename : "-"));
877
878 if (!treename || !filename) return 0;
879 TString option = opt;
880 option.ToUpper();
881 Bool_t nexp = option.Contains("NE");
882
883 TString fn;
884 Bool_t local;
885 GetFileName(filename, fn, &local);
886 if (nexp) local = kFALSE;
887
888 if (gDebug > 1)
889 Info("GetEntryList", "file: %s, local? %d", filename, local);
890
891 if (!fLists){
892 //there are no sublists
893 if (!strcmp(treename, fTreeName.Data()) && !(strcmp(fn.Data(), fFileName.Data()))){
894 return this;
895 } else {
896 //if the file is local, try the full name, unless "ne" option was specified
897 if (!nexp && local){
899 if (!gSystem->IsAbsoluteFileName(fn))
901 fn = gSystem->UnixPathName(fn);
902 if (!strcmp(treename, fTreeName.Data()) && !(strcmp(fn.Data(), fFileName.Data())))
903 return this;
904 }
905 return 0;
906 }
907 }
908
909 TString stotal = treename;
910 stotal.Append(fn);
911 ULong_t newhash = stotal.Hash();
912
913 TIter next(fLists);
914 TEntryList *templist;
915 while ((templist = (TEntryList*)next())){
916 if (templist->fStringHash==0){
917 stotal = templist->fTreeName + templist->fFileName;
918 templist->fStringHash = stotal.Hash();
919 }
920 if (gDebug > 1)
921 Info("GetEntryList", "file: %s (fn: %s), hash: %lu, element hash: %lu",
922 filename, fn.Data(), newhash, templist->fStringHash);
923 if (newhash == templist->fStringHash){
924 if (!strcmp(templist->GetTreeName(), treename) && !strcmp(templist->GetFileName(), fn.Data())){
925 return templist;
926 }
927 }
928 }
929
930 //didn't find anything for this filename, try the full name too
931 if (!nexp && local){
932 TString longname = fn;
933 gSystem->ExpandPathName(longname);
934 if (!gSystem->IsAbsoluteFileName(longname))
935 gSystem->PrependPathName(gSystem->pwd(), longname);
936 longname = gSystem->UnixPathName(longname);
937 stotal = treename;
938 stotal.Append(longname);
939 newhash = stotal.Hash();
940 next.Reset();
941 while ((templist = (TEntryList*)next())){
942 if (templist->fStringHash==0){
943 stotal = templist->fTreeName + templist->fFileName;
944 templist->fStringHash = stotal.Hash();
945 }
946 if (gDebug > 1)
947 Info("GetEntryList", "file: %s (longname: %s), hash: %lu, element hash: %lu",
948 filename, longname.Data(), newhash, templist->fStringHash);
949 if (newhash == templist->fStringHash){
950 if (templist->fTreeName == treename && templist->fFileName == longname){
951 return templist;
952 }
953 }
954 }
955 }
956 return 0;
957}
958
959////////////////////////////////////////////////////////////////////////////////
960/// Merge this list with the lists from the collection
961
963{
964 if (!list) return -1;
965 TIter next(list);
966 TEntryList *elist = 0;
967 while ((elist = (TEntryList*)next())) {
968 if (!elist->InheritsFrom(TEntryList::Class())) {
969 Error("Add","Attempt to add object of class: %s to a %s",elist->ClassName(),this->ClassName());
970 return -1;
971 }
972 Add(elist);
973 }
974 return 0;
975}
976
977////////////////////////////////////////////////////////////////////////////////
978/// Return the next non-zero entry index (next after fLastIndexQueried)
979/// this function is faster than GetEntry()
980
982{
983 Long64_t result;
984 if (fN == fLastIndexQueried+1 || fN==0){
985 return -1;
986 }
987 if (fBlocks){
989 TEntryListBlock *current_block = (TEntryListBlock*)fBlocks->UncheckedAt(iblock);
990 result = current_block->Next();
991 if (result>=0) {
993 fLastIndexReturned = result+kBlockSize*iblock;
994 return fLastIndexReturned;
995 }
996 else {
997 while (result<0 && iblock<fNBlocks-1) {
998 current_block->ResetIndices();
999 iblock++;
1000 current_block = (TEntryListBlock*)fBlocks->UncheckedAt(iblock);
1001 current_block->ResetIndices();
1002 result = current_block->Next();
1003 }
1004 if (result<0) {
1005 fLastIndexQueried = -1;
1007 return -1;
1008 }
1010 fLastIndexReturned = result+kBlockSize*iblock;
1011
1012 return fLastIndexReturned;
1013 }
1014 } else {
1015 if (!fCurrent) {
1017 if (!fCurrent) return 0;
1018 if (fShift) {
1019 while (fCurrent->GetTreeNumber()<0) {
1021 if (!fCurrent) return 0;
1022 }
1023 }
1024 }
1025 result = fCurrent->Next();
1026 if (result>=0) {
1028 fLastIndexReturned = result;
1029 return result;
1030 } else {
1031 if (fCurrent){
1032 //reset all indices of the current list
1033 if (fCurrent->fBlocks){
1034 Int_t currentblock = (fCurrent->fLastIndexReturned)/kBlockSize;
1035 TEntryListBlock *block = (TEntryListBlock*)fCurrent->fBlocks->UncheckedAt(currentblock);
1036 block->ResetIndices();
1039 }
1040 }
1041
1042 //find the list with the next non-zero entry
1043 while (result<0 && fCurrent!=((TEntryList*)fLists->Last())){
1044 if (!fCurrent) return 0;
1048 // fCurrent is guarantee to be non-zero because it is not the 'last'
1049 // element of the list.
1050 if (!fCurrent) return 0;
1051 if (!fShift)
1052 result = fCurrent->Next();
1053 else {
1054 if (fCurrent->GetTreeNumber() >= 0)
1055 result = fCurrent->Next();
1056 }
1057 }
1059 fLastIndexReturned = result;
1060 return result;
1061 }
1062 }
1063}
1064
1065////////////////////////////////////////////////////////////////////////////////
1066/// Checks if the array representation is more economical and if so, switches to it
1067
1069{
1070 if (fBlocks){
1071 TEntryListBlock *block = 0;
1072 for (Int_t i=0; i<fNBlocks; i++){
1073 block = (TEntryListBlock*)fBlocks->UncheckedAt(i);
1074 block->OptimizeStorage();
1075 }
1076 }
1077}
1078
1079////////////////////////////////////////////////////////////////////////////////
1080/// Print this list
1081/// - option = "" - default - print the name of the tree and file
1082/// - option = "all" - print all the entry numbers
1083
1084void TEntryList::Print(const Option_t* option) const
1085{
1086 TString opt = option;
1087 opt.ToUpper();
1088 if (fBlocks) {
1089 Printf("%s %s %lld", fTreeName.Data(), fFileName.Data(), fN);
1090 if (opt.Contains("A")){
1091 TEntryListBlock* block = 0;
1092 for (Int_t i=0; i<fNBlocks; i++){
1093 block = (TEntryListBlock*)fBlocks->UncheckedAt(i);
1094 Int_t shift = i*kBlockSize;
1095 block->PrintWithShift(shift);
1096 }
1097 }
1098 }
1099 else {
1100 TEntryList *elist = 0;
1101 if (fN>0){
1102 TIter next(fLists);
1103 while((elist = (TEntryList*)next())){
1104 elist->Print(option);
1105 }
1106 } else {
1107 if (!fLists) Printf("%s %s %lld", fTreeName.Data(), fFileName.Data(), fN);
1108 else {
1109 TIter next(fLists);
1110 while ((elist = (TEntryList*)next())){
1111 Printf("%s %s %lld", elist->GetTreeName(), elist->GetFileName(), elist->GetN());
1112 }
1113 }
1114 }
1115 }
1116}
1117
1118////////////////////////////////////////////////////////////////////////////////
1119/// Reset this list
1120
1121void TEntryList::Reset()
1122{
1123 //Maybe not delete, but just reset the number of blocks to 0????
1124
1125 if (fBlocks){
1126 fBlocks->Delete();
1127 delete fBlocks;
1128 fBlocks = 0;
1129 }
1130 if (fLists){
1131 if (!((TEntryList*)fLists->First())->GetDirectory()){
1132 fLists->Delete();
1133 }
1134 delete fLists;
1135 fLists = 0;
1136 }
1137 fCurrent = 0;
1138 fBlocks = 0;
1139 fNBlocks = 0;
1140 fN = 0;
1141 fTreeName = "";
1142 fFileName = "";
1143 fStringHash = 0;
1144 fTreeNumber = -1;
1145 fLastIndexQueried = -1;
1147 fReapply = kFALSE;
1148}
1149
1150////////////////////////////////////////////////////////////////////////////////
1151/// Add reference to directory dir. dir can be 0.
1152
1154{
1155 if (fDirectory == dir) return;
1156 if (fDirectory) fDirectory->Remove(this);
1157 fDirectory = dir;
1158 if (fDirectory) fDirectory->Append(this);
1159}
1160
1161////////////////////////////////////////////////////////////////////////////////
1162/// If a list for a tree with such name and filename exists, sets it as the current sublist
1163/// If not, creates this list and sets it as the current sublist
1164///
1165/// ! the filename is taken as provided, no extensions to full path or url !
1166
1167void TEntryList::SetTree(const char *treename, const char *filename)
1168{
1169 TEntryList *elist = 0;
1170
1171 TString fn;
1172 GetFileName(filename, fn);
1173
1174 TString stotal = treename;
1175 stotal.Append(fn.Data());
1176 //printf("setting tree %s\n", stotal.Data());
1177 ULong_t newhash = stotal.Hash();
1178 if (fLists) {
1179 //find the corresponding entry list and make it current
1181 if (fCurrent->fStringHash == 0){
1182 stotal = fCurrent->fTreeName + fCurrent->fFileName;
1183 fCurrent->fStringHash = stotal.Hash();
1184 }
1185 if (newhash == fCurrent->fStringHash){
1186 //this list is current
1187 if (!strcmp(fCurrent->fTreeName, treename) && !strcmp(fCurrent->fFileName, fn.Data())){
1188 return;
1189 }
1190 }
1191 TIter next(fLists);
1192 while ((elist = (TEntryList*)next())){
1193 if (newhash == elist->fStringHash){
1194 if (elist->fTreeName == treename && elist->fFileName == fn.Data()) {
1195 //the current entry list was changed. reset the fLastIndexQueried,
1196 //so that Next() doesn't start with the wrong current list
1197 //Also, reset those indices in the previously current list
1198 if (fCurrent->fBlocks){
1199 Int_t currentblock = (fCurrent->fLastIndexReturned)/kBlockSize;
1200 TEntryListBlock *block = (TEntryListBlock*)fCurrent->fBlocks->UncheckedAt(currentblock);
1201 block->ResetIndices();
1204 }
1205 fCurrent = elist;
1206 fLastIndexQueried = -3;
1207 return;
1208 }
1209 }
1210 }
1211 //didn't find an entry list for this tree, create a new one
1212 elist = new TEntryList("", "", treename, fn.Data());
1213 if (elist->GetDirectory()) {
1214 //sub lists are not added to the current directory
1215 elist->GetDirectory()->Remove(elist);
1216 elist->SetDirectory(0);
1217 }
1218 fLists->Add(elist);
1219 fCurrent = elist;
1220 return;
1221 } else {
1222 if (fN==0 && fTreeName=="" && fFileName==""){
1223 //this is the first tree set to this list
1224 fTreeName = treename;
1225 fFileName = fn;
1226 stotal = fTreeName + fFileName;
1227 //fStringHash = stotal.Hash();
1228 fStringHash = newhash;
1229 fCurrent = this;
1230 } else {
1231 if (fStringHash == 0){
1232 stotal = fTreeName + fFileName;
1233 fStringHash = stotal.Hash();
1234 }
1235 if (newhash != fStringHash){
1236 //we have a chain and already have an entry list for the first tree
1237 //move the first entry list to the fLists
1238 fLists = new TList();
1239 elist = new TEntryList();
1240 elist->fTreeName = fTreeName;
1241 elist->fFileName = fFileName;
1242 elist->fStringHash = fStringHash;
1243 elist->fN = fN;
1244 elist->fTreeNumber = fTreeNumber;
1245 elist->fBlocks = fBlocks;
1246 fBlocks = 0;
1247 elist->fNBlocks = fNBlocks;
1248 fLists->Add(elist);
1249 elist = new TEntryList("", "", treename, fn.Data());
1250 if (elist->GetDirectory()) {
1251 //sub lists are not added to the current directory
1252 elist->GetDirectory()->Remove(elist);
1253 elist->SetDirectory(0);
1254 }
1255 fLists->Add(elist);
1256 fCurrent = elist;
1257 //the current entry list was changed. reset the fLastIndexQueried,
1258 //so that Next() doesn't start with the wrong current list
1259 fLastIndexQueried = -3;
1260
1261 }
1262 else {
1263 //same tree as in the current entry list, don't do anything
1264 return;
1265 }
1266 }
1267 }
1268}
1269
1270////////////////////////////////////////////////////////////////////////////////
1271/// If a list for a tree with such name and filename exists, sets it as the current sublist
1272/// If not, creates this list and sets it as the current sublist
1273/// The name of the file, where the tree is, is taken as
1274/// `tree->GetTree()->GetCurrentFile()->GetName()`, and then expanded either to the absolute path,
1275/// or to full url. If, for some reason, you want to provide
1276/// the filename in a different format, use SetTree(const char *treename, const char *filename),
1277/// where the filename is taken "as is".
1278
1279void TEntryList::SetTree(const TTree *tree)
1280{
1281 if (!tree) return;
1282 auto thisTree = tree->GetTree();
1283 if (!thisTree) return;
1284
1285 TString treename;
1286 if (tree->GetDirectory()->InheritsFrom("TFile")) {
1287 treename = thisTree->GetName();
1288 } else {
1289 treename = TString::Format("%s/%s",tree->GetDirectory()->GetName(),thisTree->GetName());
1290 }
1291
1292 TString filename;
1293 if (tree->GetTree()->GetCurrentFile()){
1294 filename = tree->GetTree()->GetCurrentFile()->GetName();
1295 TUrl url(filename.Data(), kTRUE);
1296 if (!strcmp(url.GetProtocol(), "file")){
1297 gSystem->ExpandPathName(filename);
1298 if (!gSystem->IsAbsoluteFileName(filename))
1299 gSystem->PrependPathName(gSystem->pwd(), filename);
1300 filename = gSystem->UnixPathName(filename);
1301 url.SetFile(filename);
1302 }
1303 filename = url.GetUrl();
1304 } else {
1305 //memory-resident
1306 filename = "";
1307 }
1308 SetTree(treename, filename);
1309
1310}
1311
1312////////////////////////////////////////////////////////////////////////////////
1313/// Remove all the entries of this entry list, that are contained in elist
1314
1315void TEntryList::Subtract(const TEntryList *elist)
1316{
1317 TEntryList *templist = 0;
1318 if (!fLists){
1319 if (!fBlocks) return;
1320 //check if lists are for the same tree
1321 if (!elist->fLists){
1322 //second list is also only for 1 tree
1323 if (!strcmp(elist->fTreeName.Data(),fTreeName.Data()) &&
1324 !strcmp(elist->fFileName.Data(),fFileName.Data())){
1325 //same tree
1326 Long64_t n2 = elist->GetN();
1327 Long64_t entry;
1328 for (Int_t i=0; i<n2; i++){
1329 entry = (const_cast<TEntryList*>(elist))->GetEntry(i);
1330 Remove(entry);
1331 }
1332 } else {
1333 //different trees
1334 return;
1335 }
1336 } else {
1337 //second list has sublists, try to find one for the same tree as this list
1338 TIter next1(elist->GetLists());
1339 templist = 0;
1340 Bool_t found = kFALSE;
1341 while ((templist = (TEntryList*)next1())){
1342 if (!strcmp(templist->fTreeName.Data(),fTreeName.Data()) &&
1343 !strcmp(templist->fFileName.Data(),fFileName.Data())){
1344 found = kTRUE;
1345 break;
1346 }
1347 }
1348 if (found) {
1349 Subtract(templist);
1350 }
1351 }
1352 } else {
1353 //this list has sublists
1354 TIter next2(fLists);
1355 templist = 0;
1356 Long64_t oldn=0;
1357 while ((templist = (TEntryList*)next2())){
1358 oldn = templist->GetN();
1359 templist->Subtract(elist);
1360 fN = fN - oldn + templist->GetN();
1361 }
1362 }
1363 return;
1364}
1365
1366////////////////////////////////////////////////////////////////////////////////
1367
1369{
1370 TEntryList eresult = elist1;
1371 //eresult = elist1;
1372 // printf("internal in operator1\n");
1373 eresult.Print("all");
1374 eresult.Add(&elist2);
1375 // printf("internal in operator2\n");
1376 eresult.Print("all");
1377
1378 return eresult;
1379}
1380
1381////////////////////////////////////////////////////////////////////////////////
1382/// Relocate the file paths.
1383/// If `oldroot` is defined, replace `oldroot` with `newroot` in all file names,
1384/// i.e. `oldroot/re/st/of/the/path` will become `newroot`/re/st/of/the/path`.
1385/// If `oldroot` is null, the new path will be just `newroot/path`.
1386/// Relocation is mandatory to use the entry-list with the same dataset at a different
1387/// location (i.e. on a different cluster, machine or disks).
1388
1389Int_t TEntryList::RelocatePaths(const char *newroot, const char *oldroot)
1390{
1391 // At least newroot must be given
1392 if (!newroot || (newroot && strlen(newroot) <= 0)) {
1393 Warning("RelocatePaths", "the new location must be given!");
1394 return -1;
1395 }
1396
1397 if (strlen(GetName()) > 0)
1398 Info("RelocatePaths", "'%s': relocating paths '%s' to '%s'",
1399 GetName(), oldroot ? oldroot : "*", newroot);
1400
1401 Int_t nrl = 0, xnrl = 0;
1402 // Apply to all underlying lists, if any
1403 if (fLists) {
1404 TIter nxl(fLists);
1405 TEntryList *enl = 0;
1406 while ((enl = (TEntryList *) nxl())) {
1407 if ((xnrl = enl->RelocatePaths(newroot, oldroot)) < 0) {
1408 Warning("RelocatePaths", "problems relocating '%s'", enl->GetName());
1409 } else {
1410 nrl += xnrl;
1411 }
1412 }
1413 }
1414 // Apply to ourselves
1415 TString temp;
1416 Ssiz_t lo = 0;
1417 if (oldroot && (lo = strlen(oldroot)) > 0) {
1418 if (fFileName.BeginsWith(oldroot)) {
1419 fFileName.Replace(0, lo, newroot);
1420 nrl++;
1421 }
1422 } else {
1423 Ssiz_t ilst = fFileName.Last('/');
1424 if (ilst != kNPOS) {
1425 fFileName.Replace(0, ilst, newroot);
1426 } else {
1427 fFileName.Insert(0, TString::Format("%s/", newroot));
1428 }
1429 nrl++;
1430 }
1431 if (fStringHash != 0) {
1432 temp.Form("%s%s", fTreeName.Data(), fFileName.Data());
1433 fStringHash = temp.Hash();
1434 }
1435
1436 // Done
1437 return nrl;
1438}
1439
1440////////////////////////////////////////////////////////////////////////////////
1441/// Relocate entry list 'enlnm' in file 'fn' replacing 'oldroot' with 'newroot' in
1442/// filenames. If 'enlnm' is null or '*' all entry lists in the file are relocated.
1443/// Relocation is mandatory to use the entry-list with the same dataset at a different
1444/// location (i.e. on a different cluster, machine or disks).
1445/// This function can be called as many times as need to reach the desired result.
1446/// The existing 'locations' can be checked qith TEntryList::Scan .
1447
1448Int_t TEntryList::Relocate(const char *fn,
1449 const char *newroot, const char *oldroot, const char *enlnm)
1450{
1451 // Open the file for updating
1452 TFile *fl = TFile::Open(fn, "UPDATE");
1453 if (!fl || (fl&& fl->IsZombie())) {
1454 ::Error("TEntryList::Relocate", "file '%s' cannot be open for updating", fn);
1455 return -1;
1456 }
1457
1458 Int_t nrl = 0;
1459 // Read the lists
1460 TString nm(enlnm);
1461 if (nm.IsNull()) nm = "*";
1462 TRegexp nmrg(nm, kTRUE);
1463 TIter nxk(fl->GetListOfKeys());
1464 TKey *key = 0;
1465 while ((key = (TKey *) nxk())) {
1466 if (!strcmp(key->GetClassName(), "TEntryList")) {
1467 TString knm(key->GetName());
1468 if (knm.Index(nmrg) != kNPOS) {
1469 TEntryList *enl = dynamic_cast<TEntryList *>(fl->Get(knm));
1470 if (enl) {
1471 Int_t xnrl = enl->RelocatePaths(newroot, oldroot);
1472 if (xnrl >= 0) {
1473 enl->Write(knm, TObject::kOverwrite);
1474 nrl += xnrl;
1475 } else {
1476 ::Error("TEntryList::Relocate", "problems relocating '%s' ...", enl->GetName());
1477 }
1478 }
1479 }
1480 }
1481 }
1482 // Close the file
1483 fl->Close();
1484 delete fl;
1485 // Done
1486 return nrl;
1487}
1488
1489////////////////////////////////////////////////////////////////////////////////
1490/// Get in 'c' the string in common at the beginning of 'a' and 'b'
1491///
1492/// Return:
1493/// - 0 a and b are not contained in each other, i.e. c != a && c != b
1494/// - 1 a is contained in b, i.e. c == a (includes a == empty)
1495/// - 2 b is contained in a, i.e. c == b (includes b == empty)
1496/// - 3 b is a, i.e. c == b == a (includes a == b == empty)
1497/// Auxiliary function for path scans.
1498
1500{
1501 if (a == b) {
1502 c = a;
1503 return 3;
1504 }
1505 if (a.IsNull()) {
1506 c = "";
1507 return 1;
1508 }
1509 if (b.IsNull()) {
1510 c = "";
1511 return 2;
1512 }
1513 Bool_t ashort = (a.Length() > b.Length()) ? kFALSE : kTRUE;
1514 Ssiz_t len = (ashort) ? a.Length() : b.Length();
1515 Int_t lcom = 0;
1516 for (Int_t i = 0; i < len; i++) {
1517 if (a[i] != b[i]) break;
1518 lcom++;
1519 }
1520 if (lcom == len) {
1521 c = ashort ? a : b;
1522 return ashort ? 1 : 2;
1523 }
1524 c = a(0,lcom);
1525 // Done
1526 return 0;
1527}
1528
1529////////////////////////////////////////////////////////////////////////////////
1530/// Scan the paths to find the common roots. If 'roots' is defined, add
1531/// the found roots to the list as TObjStrings.
1532/// Return the number of roots found.
1533
1535{
1536 TList *xrl = roots ? roots : new TList;
1537
1538 Int_t nrl = 0;
1539 // Apply to all underlying lists, if any
1540 if (fLists) {
1541 TIter nxl(fLists);
1542 TEntryList *enl = 0;
1543 while ((enl = (TEntryList *) nxl()))
1544 nrl += enl->ScanPaths(xrl, kFALSE);
1545 }
1546 // Apply to ourselves
1547 Bool_t newobjs = kTRUE;
1548 TString path = gSystem->GetDirName(fFileName), com;
1549 TObjString *objs = nullptr;
1550 TIter nxr(xrl);
1551 while ((objs = (TObjString *) nxr())) {
1552 Int_t rc = 0;
1553 if ((rc = GetCommonString(path, objs->GetString(), com)) != 2) {
1554 TUrl ucom(com);
1555 if (strlen(ucom.GetFile()) > 0 && strcmp(ucom.GetFile(), "/")) {
1556 objs->SetString(com.Data());
1557 newobjs = kFALSE;
1558 break;
1559 }
1560 }
1561 }
1562 if (newobjs) xrl->Add(new TObjString(path));
1563
1564 // Done
1565 nrl = xrl->GetSize();
1566 if (notify) {
1567 Printf(" * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ *");
1568 Printf(" * Entry-list: %s", GetName());
1569 Printf(" * %d common root paths found", nrl);
1570 nxr.Reset();
1571 while ((objs = (TObjString *) nxr())) {
1572 Printf(" * %s", objs->GetName());
1573 }
1574 Printf(" * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ *");
1575 }
1576
1577 if (xrl != roots) {
1578 xrl->SetOwner(kTRUE);
1579 SafeDelete(xrl);
1580 }
1581
1582 // Done
1583 return nrl;
1584}
1585
1586////////////////////////////////////////////////////////////////////////////////
1587/// Scan TEntryList in 'fn' to find the common parts of paths.
1588/// If 'roots' is defined, add the found roots to the list as TObjStrings.
1589/// Return the number of common root paths found.
1590
1591Int_t TEntryList::Scan(const char *fn, TList *roots)
1592{
1593 // Open the file for updating
1594 TFile *fl = TFile::Open(fn);
1595 if (!fl || (fl&& fl->IsZombie())) {
1596 ::Error("TEntryList::Relocate", "file '%s' cannot be open for reading", fn);
1597 return -1;
1598 }
1599
1600 Int_t nrs = 0;
1601 // Read the lists
1602 TIter nxk(fl->GetListOfKeys());
1603 TKey *key = 0;
1604 while ((key = (TKey *) nxk())) {
1605 if (!strcmp(key->GetClassName(), "TEntryList")) {
1606 TEntryList *enl = dynamic_cast<TEntryList *>(fl->Get(key->GetName()));
1607 if (enl) {
1608 nrs += enl->ScanPaths(roots);
1609 } else {
1610 ::Error("TEntryList::Scan", "object entry-list '%s' not found or not loadable!", key->GetName());
1611 }
1612 }
1613 }
1614 // Close the file
1615 fl->Close();
1616 delete fl;
1617
1618 // Done
1619 return nrs;
1620}
1621
1622////////////////////////////////////////////////////////////////////////////////
1623/// Custom streamer for class TEntryList to handle the different interpretation
1624/// of fFileName between version 1 and >1 .
1625
1626void TEntryList::Streamer(TBuffer &b)
1627{
1628 if (b.IsReading()) {
1629 UInt_t R__s, R__c;
1630 Version_t R__v = b.ReadVersion(&R__s, &R__c);
1631 b.ReadClassBuffer(TEntryList::Class(), this, R__v, R__s, R__c);
1632 if (R__v <= 1) {
1633 // The filename contained also the protocol and host: this was dropped
1634 // in version > 1 to allow re-localization
1636 }
1637 } else {
1638 b.WriteClassBuffer(TEntryList::Class(), this);
1639 }
1640}
#define SafeDelete(p)
Definition RConfig.hxx:537
#define b(i)
Definition RSha256.hxx:100
#define c(i)
Definition RSha256.hxx:101
#define a(i)
Definition RSha256.hxx:99
const Ssiz_t kNPOS
Definition RtypesCore.h:124
int Int_t
Definition RtypesCore.h:45
short Version_t
Definition RtypesCore.h:65
int Ssiz_t
Definition RtypesCore.h:67
unsigned int UInt_t
Definition RtypesCore.h:46
const Bool_t kFALSE
Definition RtypesCore.h:101
unsigned long ULong_t
Definition RtypesCore.h:55
bool Bool_t
Definition RtypesCore.h:63
long long Long64_t
Definition RtypesCore.h:80
const Bool_t kTRUE
Definition RtypesCore.h:100
const char Option_t
Definition RtypesCore.h:66
#define ClassImp(name)
Definition Rtypes.h:364
#define gDirectory
Definition TDirectory.h:385
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
char name[80]
Definition TGX11.cxx:110
Int_t gDebug
Definition TROOT.cxx:592
void Printf(const char *fmt,...)
R__EXTERN TSystem * gSystem
Definition TSystem.h:559
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.
Int_t Next()
Return the next non-zero entry Faster than GetEntry() function.
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.
Bool_t Enter(Int_t entry)
If the block has already been optimized and the entries are stored as a list and not as bits,...
Bool_t Remove(Int_t entry)
Remove entry #entry If the block has already been optimized and the entries are stored as a list and ...
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
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
Bool_t fReapply
If true, TTree::Draw will 'reapply' the original cut.
Definition TEntryList.h:49
virtual Int_t GetTreeNumber() const
Definition TEntryList.h:80
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:75
Int_t fTreeNumber
! the index of the tree in the chain (used when the entry list is used as input (TTree::SetEntryList(...
Definition TEntryList.h:41
virtual void 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:76
TObjArray * fBlocks
blocks with indices of passing events (TEntryListBlocks)
Definition TEntryList.h:35
virtual Int_t Contains(Long64_t entry, TTree *tree=0)
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:79
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.
virtual ~TEntryList()
Destructor.
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.
virtual Bool_t Enter(Long64_t entry, TTree *tree=0)
Add entry #entry to the 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().
virtual const char * GetTreeName() const
Definition TEntryList.h:78
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
virtual void Print(const Option_t *option="") const
Print this list.
virtual Int_t RelocatePaths(const char *newloc, const char *oldloc=0)
Relocate the file paths.
virtual Bool_t Remove(Long64_t entry, TTree *tree=0)
Remove entry #entry from the list.
Bool_t 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
static Int_t Relocate(const char *fn, const char *newroot, const char *oldroot=0, const char *enlnm=0)
Relocate entry list 'enlnm' in file 'fn' replacing 'oldroot' with 'newroot' in filenames.
ULong_t fStringHash
! Hash value of a string of treename and filename
Definition TEntryList.h:40
TList * fLists
a list of underlying entry lists for each tree of a chain
Definition TEntryList.h:31
virtual Int_t ScanPaths(TList *roots, Bool_t notify=kTRUE)
Scan the paths to find the common roots.
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
void GetFileName(const char *filename, TString &fn, Bool_t *=0)
To be able to re-localize the entry-list we identify the file by just the name and the anchor,...
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:77
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format.
Definition TFile.h:54
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:4025
void Close(Option_t *option="") override
Close a file.
Definition TFile.cxx:899
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:76
A doubly linked list.
Definition TList.h:38
virtual void Add(TObject *obj)
Definition TList.h:81
virtual TObject * After(const TObject *obj) const
Returns the object after object obj.
Definition TList.cxx:330
virtual TObject * Last() const
Return the last object in the list. Returns 0 when list is empty.
Definition TList.cxx:693
virtual void Delete(Option_t *option="")
Remove all objects from the list AND delete all heap based objects.
Definition TList.cxx:470
virtual TObject * First() const
Return the first object in the list. Returns 0 when list is empty.
Definition TList.cxx:659
The TNamed class is the base class for all named ROOT classes.
Definition TNamed.h:29
virtual const char * GetName() const
Returns name of object.
Definition TNamed.h:47
An array of TObjects.
Definition TObjArray.h:31
void Add(TObject *obj)
Definition TObjArray.h:68
TObject * UncheckedAt(Int_t i) const
Definition TObjArray.h:84
virtual void Delete(Option_t *option="")
Remove all objects from the array AND delete all heap based objects.
Collectable string class.
Definition TObjString.h:28
const char * GetName() const
Returns name of object.
Definition TObjString.h:38
const TString & GetString() const
Definition TObjString.h:46
void SetString(const char *s)
Definition TObjString.h:45
virtual Int_t Write(const char *name=0, Int_t option=0, Int_t bufsize=0)
Write this object to the current directory.
Definition TObject.cxx:868
@ 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:200
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:949
R__ALWAYS_INLINE Bool_t IsZombie() const
Definition TObject.h:153
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:515
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:963
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:937
Regular expression class.
Definition TRegexp.h:31
Basic string class.
Definition TString.h:136
TString & Insert(Ssiz_t pos, const char *s)
Definition TString.h:649
TString & Replace(Ssiz_t pos, Ssiz_t n, const char *s)
Definition TString.h:682
const char * Data() const
Definition TString.h:369
Ssiz_t Last(char c) const
Find last occurrence of a character c.
Definition TString.cxx:916
void ToUpper()
Change string to upper case.
Definition TString.cxx:1163
Bool_t BeginsWith(const char *s, ECaseCompare cmp=kExact) const
Definition TString.h:615
Bool_t IsNull() const
Definition TString.h:407
UInt_t Hash(ECaseCompare cmp=kExact) const
Return hash value.
Definition TString.cxx:662
TString & Append(const char *cs)
Definition TString.h:564
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:2336
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2314
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:624
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:639
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:422
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:952
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:389
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)
Definition TMathBase.h:176
Definition tree.py:1
TCanvas * roots()
Definition roots.C:1