]> git.uio.no Git - u/mrichter/AliRoot.git/blame - STEER/STEERBase/AliMergeableCollection.cxx
Switching from CMAKE_SOURCE_DIR to AliRoot_SOURCE_DIR
[u/mrichter/AliRoot.git] / STEER / STEERBase / AliMergeableCollection.cxx
CommitLineData
ac4edd2e 1/**************************************************************************
2* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3* *
4* Author: The ALICE Off-line Project. *
5* Contributors are mentioned in the code where appropriate. *
6* *
7* Permission to use, copy, modify and distribute this software and its *
8* documentation strictly for non-commercial purposes is hereby granted *
9* without fee, provided that the above copyright notice appears in all *
10* copies and that both the copyright notice and this permission notice *
11* appear in the supporting documentation. The authors make no claims *
12* about the suitability of this software for any purpose. It is *
13* provided "as is" without express or implied warranty. *
14**************************************************************************/
15
16// $Id: AliMergeableCollection.cxx 50593 2011-07-14 17:42:28Z martinez $
17
18///
19/// A mergeable object container.
20///
21/// For each tuple (key1,key2,..,keyN) a (hash)list of mergeable objects is associated.
22/// Note that key1, key2 (optional), ..., keyN (optional) are strings.
23/// Those strings should not contain "/" themselves.
24///
25/// More helper functions might be added in the future (e.g. Project, etc...)
26
27#include "AliMergeableCollection.h"
28
3a7af7bd 29using std::cout;
30using std::endl;
ac4edd2e 31ClassImp(AliMergeableCollection)
32
33#include "AliLog.h"
34#include "Riostream.h"
35#include "TError.h"
73a1ccd5 36#include "TFolder.h"
1b331634 37#include "TGraph.h"
73a1ccd5 38#include "TH1.h"
39#include "TH2.h"
ac4edd2e 40#include "THashList.h"
73a1ccd5 41#include "THnSparse.h"
ac4edd2e 42#include "TKey.h"
43#include "TMap.h"
44#include "TObjArray.h"
45#include "TObjString.h"
73a1ccd5 46#include "TProfile.h"
ac4edd2e 47#include "TRegexp.h"
48#include "TROOT.h"
49#include "TSystem.h"
d440e2c5 50#include <cassert>
51#include <vector>
73a1ccd5 52#include "TBrowser.h"
ac4edd2e 53
54//_____________________________________________________________________________
55AliMergeableCollection::AliMergeableCollection(const char* name, const char* title)
73a1ccd5 56: TFolder(name,title), fMap(0x0), fMustShowEmptyObject(0), fMapVersion(0), fMessages()
ac4edd2e 57{
58 /// Ctor
59}
60
61//_____________________________________________________________________________
62AliMergeableCollection::~AliMergeableCollection()
63{
64 /// dtor. Note that the map is owner
ac4edd2e 65 delete fMap;
66}
67
68//_____________________________________________________________________________
69Bool_t
70AliMergeableCollection::Adopt(TObject* obj)
71{
72 /// Adopt a given object at top level (i.e. no key)
73 return InternalAdopt("",obj);
74}
75
76//_____________________________________________________________________________
77Bool_t
78AliMergeableCollection::Adopt(const char* identifier, TObject* obj)
79{
80 /// Adopt a given object, and associate it with pair key
81 TString sidentifier(identifier);
82 if ( ! sidentifier.IsNull() ){
83 if ( ! sidentifier.EndsWith("/") ) sidentifier.Append("/");
84 if ( ! sidentifier.BeginsWith("/") ) sidentifier.Prepend("/");
85 }
86 return InternalAdopt(sidentifier.Data(),obj);
87}
88
1b331634 89//_____________________________________________________________________________
90Bool_t AliMergeableCollection::Attach(AliMergeableCollection* mc, const char* identifier, Bool_t pruneFirstIfAlreadyExists)
91{
92 /// Attach an already existing mergeable collection to this one.
93 /// It is attached at level identifier/
94 /// We take ownership of mc
95 /// If identifier is already existing we kill it if pruneFirstIfAlreadyExists is kTRUE
96 /// (and attach mc) otherwise we return kFALSE (and do *not* attach mc)
97
98 THashList* hlist = dynamic_cast<THashList*>(Map()->GetValue(identifier));
99
100 if (hlist)
101 {
102 if (!pruneFirstIfAlreadyExists)
103 {
104 AliError(Form("%s already exist. Will not overwrite it.",identifier));
105 return kFALSE;
106 }
107 else
108 {
109 Int_t n = Prune(identifier);
110 if (!n)
111 {
112 AliError(Form("Could not prune pre-existing %s",identifier));
113 return kFALSE;
114 }
115 }
116 }
117
118 TIter next(mc->fMap);
119 TObjString* str;
120
121 while ( ( str = static_cast<TObjString*>(next())) )
122 {
123 THashList* hl = dynamic_cast<THashList*>(mc->Map()->GetValue(str->String()));
124 TString newid(Form("/%s%s",identifier,str->String().Data()));
125 newid.ReplaceAll("//","/");
126 Map()->Add(new TObjString(newid.Data()),hl);
127 }
128
129 return kTRUE;
130}
131
73a1ccd5 132//_____________________________________________________________________________
133void AliMergeableCollection::Browse(TBrowser* b)
134{
135 /// Create a TFolder structure pointing to our objects, so we
136 /// can be "browsed"
137
138 if ( !fFolders ) return;
139
140 TObjArray* ids = SortAllIdentifiers();
141 TIter nextIdentifier(ids);
142 TObjString* str;
143
144 while ( ( str = static_cast<TObjString*>(nextIdentifier()) ) )
145 {
146 TObjArray* parts = str->String().Tokenize("/");
147 TObjString* s;
148 TIter nextPart(parts);
149 TFolder* base = this;
150
151 while ( ( s = static_cast<TObjString*>(nextPart())))
152 {
153 TFolder* f = static_cast<TFolder*>(base->TFolder::FindObject(s->String()));
154 if (!f)
155 {
156 f = new TFolder(s->String(),"");
157 base->Add(f);
158 }
159 base = f;
160 }
161 delete parts;
162
163 TList* list = CreateListOfObjectNames(str->String());
164 if (list)
165 {
166 TObjString* oname;
167 TIter nextObject(list);
168 while ( ( oname = static_cast<TObjString*>(nextObject())) )
169 {
170 TObject* o = GetObject(str->String(),oname->String());
171 base->Add(o);
172 }
173 }
174 else
175 {
176 AliError("got list=0x0");
177 }
178 delete list;
179 }
180
181 TList* top = CreateListOfKeys(0);
182 TObjString* stop;
183 TIter nextTop(top);
184
185 while ( ( stop = static_cast<TObjString*>(nextTop())) )
186 {
187 b->Add(TFolder::FindObject(stop->String()));
188 }
189
190 delete top;
191
192 delete ids;
193}
194
ac4edd2e 195//_____________________________________________________________________________
196void AliMergeableCollection::ClearMessages()
197{
198 /// clear pending messages
199 fMessages.clear();
200}
201
202//_____________________________________________________________________________
203TIterator*
204AliMergeableCollection::CreateIterator(Bool_t direction) const
205{
206 /// Create an iterator (must be deleted by the client)
207 return fMap ? new AliMergeableCollectionIterator(this,direction) : 0x0;
208}
209
210//_____________________________________________________________________________
211AliMergeableCollection*
212AliMergeableCollection::Clone(const char* name) const
213{
214 /// Clone this collection.
215 /// We loose the messages.
216
217 AliMergeableCollection* newone = new AliMergeableCollection(name,GetTitle());
218
219 newone->fMap = static_cast<TMap*>(fMap->Clone());
220 newone->fMustShowEmptyObject = fMustShowEmptyObject;
221 newone->fMapVersion = fMapVersion;
222
223 return newone;
224}
225
226//_____________________________________________________________________________
227void
228AliMergeableCollection::Delete(Option_t*)
229{
230 /// Delete all the objects
231 fMap->DeleteAll();
232 delete fMap;
233 fMap=0x0;
234}
235
236//_____________________________________________________________________________
237TObject*
238AliMergeableCollection::FindObject(const char* fullIdentifier) const
239{
240 /// Find an object by its full identifier.
241
242 return GetObject(fullIdentifier);
243}
244
245//_____________________________________________________________________________
246TObject*
247AliMergeableCollection::FindObject(const TObject *object) const
248{
249 /// Find an object
250 AliWarning("This method is awfully inefficient. Please improve it or use FindObject(const char*)");
251 TIter next(CreateIterator());
252 TObject* obj;
253 while ( ( obj=next() ) )
254 {
255 if ( obj->IsEqual(object) ) return obj;
256 }
257 return 0x0;
258}
259
260
261//_____________________________________________________________________________
262TList*
263AliMergeableCollection::CreateListOfKeys(Int_t index) const
264{
265 /// Create the list of keys at level index
266
267 TList* list = new TList;
268 list->SetOwner(kTRUE);
269
270 TObjArray* ids = SortAllIdentifiers();
271 TIter next(ids);
272 TObjString* str;
273
274 while ( ( str = static_cast<TObjString*>(next()) ) )
275 {
276 TString oneid = GetKey(str->String().Data(),index,kFALSE);
277 if (oneid.Length()>0 && !list->Contains(oneid))
278 {
279 list->Add(new TObjString(oneid));
280 }
281 }
282
283 delete ids;
284 return list;
285}
286
287//_____________________________________________________________________________
288TList*
289AliMergeableCollection::CreateListOfObjectNames(const char* identifier) const
290{
291 /// Create list of object names for /key1/key2/key...
292 /// Returned list must be deleted by client
293
294 TList* listOfNames = new TList;
295 listOfNames->SetOwner(kTRUE);
296
297 TIter next(Map());
298 TObjString* str;
299
300 while ( ( str = static_cast<TObjString*>(next()) ) )
301 {
302 TString currIdentifier = str->String();
303 if ( currIdentifier.CompareTo(identifier) ) continue;
304
305 THashList* list = static_cast<THashList*>(Map()->GetValue(identifier));
306
307 TIter nextObject(list);
308 TObject* obj;
309
310 while ( ( obj = nextObject() ) )
311 {
312 listOfNames->Add(new TObjString(obj->GetName()));
313 }
314 }
315
316 return listOfNames;
317}
318
319
320//_____________________________________________________________________________
321TString
322AliMergeableCollection::GetIdentifier(const char* fullIdentifier) const
323{
324 /// Extract the identifier from the fullIdentifier
d440e2c5 325
326 TString identifier;
327
328 Int_t n = TString(fullIdentifier).CountChar('/')-1;
329
330 for (Int_t i=0; i < n; ++i)
331 {
332 identifier += "/";
333 identifier += InternalDecode(fullIdentifier,i);
ac4edd2e 334 }
d440e2c5 335 identifier += "/";
ac4edd2e 336 return identifier;
337}
338
339//_____________________________________________________________________________
340TString
341AliMergeableCollection::GetKey(const char* identifier, Int_t index, Bool_t idContainsObjName) const
342{
343 /// Extract the index element of the key pair from the fullIdentifier
d440e2c5 344
345 if ( ! idContainsObjName )
346 {
347 TString sidentifier(identifier);
348 sidentifier.Append("/dummy");
349 return InternalDecode(sidentifier.Data(),index);
350 }
351
352 return InternalDecode(identifier,index);
ac4edd2e 353}
354
355//_____________________________________________________________________________
356TString
357AliMergeableCollection::GetObjectName(const char* fullIdentifier) const
358{
359 /// Extract the object name from an identifier
360
361 return InternalDecode(fullIdentifier,-1);
362}
363
ac4edd2e 364//_____________________________________________________________________________
d440e2c5 365TH1*
366AliMergeableCollection::Histo(const char* fullIdentifier) const
ac4edd2e 367{
d440e2c5 368 /// Get histogram key1/key2/.../objectName:action
369 /// action is used for 2D histograms :
370 /// might be px for projection along x-axis
371 /// py for projection along y-axis
372 /// pfx for profile along x-axis
373 /// pfy for profile along y-axis
374
375 TString sfullIdentifier(fullIdentifier);
376
377 TString fullIdWithoutAction(fullIdentifier);
378 TString action;
379
380 if ( sfullIdentifier.First(':') != kNPOS )
381 {
382 TObjArray* arr = sfullIdentifier.Tokenize(":");
383
384 fullIdWithoutAction = static_cast<TObjString*>(arr->At(0))->String();
385
386 if ( arr->GetLast() > 0 )
387 {
388 action = static_cast<TObjString*>(arr->At(1))->String();
389 action.ToUpper();
390 }
391
392 delete arr;
393 }
394
395 Int_t nslashes = sfullIdentifier.CountChar('/');
396
397 TObject* o(0x0);
398
399 if (!nslashes)
400 {
401 o = GetObject("", fullIdWithoutAction);
402 }
403 else
404 {
405 o = GetObject(GetIdentifier(fullIdWithoutAction).Data(), GetObjectName(fullIdWithoutAction));
406 }
ac4edd2e 407
d440e2c5 408 return HistoWithAction(fullIdWithoutAction.Data(),o,action);
409}
410
411//_____________________________________________________________________________
412TH1*
413AliMergeableCollection::Histo(const char* identifier,
414 const char* objectName) const
415{
5376e016
CP
416 /// Get histogram key1/key2/.../objectName:action
417 /// action is used for 2D histograms :
418 /// might be px for projection along x-axis
419 /// py for projection along y-axis
420 /// pfx for profile along x-axis
421 /// pfy for profile along y-axis
422
d440e2c5 423 TObject* o = GetObject(identifier,objectName);
ac4edd2e 424
d440e2c5 425 TObjArray* arr = TString(objectName).Tokenize(":");
ac4edd2e 426 TString action;
427
d440e2c5 428 if ( arr->GetLast() > 0 )
ac4edd2e 429 {
430 action = static_cast<TObjString*>(arr->At(1))->String();
431 action.ToUpper();
432 }
433
434 delete arr;
d440e2c5 435
436 return HistoWithAction(identifier,o,action);
437}
438
439
440//_____________________________________________________________________________
441TH1*
442AliMergeableCollection::HistoWithAction(const char* identifier, TObject* o, const TString& action) const
443{
444 /// Convert o to an histogram if possible, applying a given action if there
445
446 if (!o) return 0x0;
447
448 if (!o->InheritsFrom("TH1"))
449 {
450 AliError(Form("%s is not an histogram",o->GetName()));
451 return 0x0;
452 }
453
454 TH2* h2 = dynamic_cast<TH2*>(o);
455
456 if (h2)
457 {
458 if ( action == "PX" )
459 {
460 return h2->ProjectionX(NormalizeName(Form("%s/%s",identifier,o->GetName()),action.Data()).Data());
461 }
462 if ( action == "PY" )
463 {
464 return h2->ProjectionY(NormalizeName(Form("%s/%s",identifier,o->GetName()),action.Data()).Data());
465 }
466 if ( action == "PFX" )
467 {
468 return h2->ProfileX(NormalizeName(Form("%s/%s",identifier,o->GetName()),action.Data()).Data());
469 }
470 if ( action == "PFY" )
471 {
472 return h2->ProfileY(NormalizeName(Form("%s/%s",identifier,o->GetName()),action.Data()).Data());
473 }
474 }
ac4edd2e 475
d440e2c5 476 return static_cast<TH1*>(o);
477}
478
5376e016
CP
479//_____________________________________________________________________________
480TH2*
481AliMergeableCollection::H2(const char* fullIdentifier) const
482{
483 /// Short-cut method to grab a 2D histogram
484 /// Will return 0x0 if the object if not a TH2xxx
485
486 TObject* o = GetObject(fullIdentifier);
487
488 if (o->IsA()->InheritsFrom(TH2::Class()))
489 {
490 return static_cast<TH2*>(o);
491 }
492 return 0x0;
493}
494
495//_____________________________________________________________________________
496TH2*
497AliMergeableCollection::H2(const char* identifier,
498 const char* objectName) const
499{
500 /// Short-cut method to grab a 2D histogram
501 /// Will return 0x0 if the object if not a TH2xxx
502
503 TObject* o = GetObject(identifier,objectName);
504
505 if (o->IsA()->InheritsFrom(TH2::Class()))
506 {
507 return static_cast<TH2*>(o);
508 }
509 return 0x0;
510}
511
512//_____________________________________________________________________________
513TProfile*
514AliMergeableCollection::Prof(const char* fullIdentifier) const
515{
516 /// Short-cut method to grab a TProfile histogram
517 /// Will return 0x0 if the object if not a TProfile
518
519 TObject* o = GetObject(fullIdentifier);
520
521 if (o->IsA()->InheritsFrom(TProfile::Class()))
522 {
523 return static_cast<TProfile*>(o);
524 }
525 return 0x0;
526}
527
528//_____________________________________________________________________________
529TProfile*
530AliMergeableCollection::Prof(const char* identifier,
531 const char* objectName) const
532{
533 /// Short-cut method to grab a TProfile histogram
534 /// Will return 0x0 if the object if not a TProfile
535
536 TObject* o = GetObject(identifier,objectName);
537
538 if (o->IsA()->InheritsFrom(TProfile::Class()))
539 {
540 return static_cast<TProfile*>(o);
541 }
542 return 0x0;
543}
d440e2c5 544
545//_____________________________________________________________________________
546TObject*
547AliMergeableCollection::GetObject(const char* fullIdentifier) const
548{
549 /// Get object key1/key2/.../objectName
550 /// Note that no action is allowed for generic objects (only for histograms,
551 /// see Histo() methods)
552
553 TString sfullIdentifier(fullIdentifier);
554
555 Int_t nslashes = sfullIdentifier.CountChar('/');
556
557 if (!nslashes)
558 {
559 return GetObject("", sfullIdentifier);
560 }
561 else
562 {
563 return GetObject(GetIdentifier(fullIdentifier).Data(), GetObjectName(fullIdentifier));
564 }
ac4edd2e 565}
566
ac4edd2e 567//_____________________________________________________________________________
568TObject*
569AliMergeableCollection::GetObject(const char* identifier,
570 const char* objectName) const
571{
572 /// Get object for (identifier,objectName) triplet
573
574 TString sidentifier(identifier);
575 if ( ! sidentifier.IsNull() ) {
576 if ( ! sidentifier.BeginsWith("/") ) sidentifier.Prepend("/");
577 if ( ! sidentifier.EndsWith("/") ) sidentifier.Append("/");
578 }
579 return InternalObject(sidentifier.Data(),objectName);
580}
581
582//_____________________________________________________________________________
d5a197f5 583TObject* AliMergeableCollection::GetSum(const char* idPattern) const
ac4edd2e 584{
585 /// Sum objects
586 /// The pattern must be in the form:
95760506 587 /// /key1_1,key1_2,.../key2_1,key2_2,.../.../objectName_1,objectName_2...
ac4edd2e 588 /// The logical or between patterns separated by commas is taken
95760506 589 /// Exact match is required for keys and objectNames
ac4edd2e 590
591 TObject* sumObject = 0x0;
592
593 // Build array of lists of pattern
594 TString idPatternString(idPattern);
595 TObjArray* keyList = idPatternString.Tokenize("/");
596 TObjArray keyMatrix(keyList->GetEntries());
597 keyMatrix.SetOwner();
598 for ( Int_t ikey=0; ikey<keyList->GetEntries(); ikey++ ) {
599 TObjArray* subKeyList = ((TObjString*)keyList->At(ikey))->GetString().Tokenize(",");
600 keyMatrix.AddAt(subKeyList, ikey);
601 }
602 delete keyList;
603
604 TString debugMsg = "Adding objects:";
605
95760506 606 //
607 // First handle the keys
608 //
ac4edd2e 609 TIter next(Map());
610 TObjString* str;
611 while ( ( str = static_cast<TObjString*>(next()) ) )
612 {
613 TString identifier = str->String();
614
615 Bool_t listMatchPattern = kTRUE;
616 for ( Int_t ikey=0; ikey<keyMatrix.GetEntries()-1; ikey++ ) {
617 TString currKey = GetKey(identifier, ikey, kFALSE);
618 Bool_t matchKey = kFALSE;
619 TObjArray* subKeyList = static_cast<TObjArray*> ( keyMatrix.At(ikey) );
620 for ( Int_t isub=0; isub<subKeyList->GetEntries(); isub++ ) {
621 TString subKeyString = static_cast<TObjString*> (subKeyList->At(isub))->GetString();
95760506 622 if ( currKey == subKeyString ) {
ac4edd2e 623 matchKey = kTRUE;
624 break;
625 }
626 } // loop on the list of patterns of each key
627 if ( ! matchKey ) {
628 listMatchPattern = kFALSE;
629 break;
630 }
631 } // loop on keys in the idPattern
632 if ( ! listMatchPattern ) continue;
633
95760506 634
635 //
636 // Then handle the object name
637 //
ac4edd2e 638 THashList* list = static_cast<THashList*>(Map()->GetValue(identifier.Data()));
639
640 TIter nextObj(list);
641 TObject* obj;
642
643 while ( ( obj = nextObj()) )
644 {
645 TString currKey = obj->GetName();
646 Bool_t matchKey = kFALSE;
647 TObjArray* subKeyList = static_cast<TObjArray*> ( keyMatrix.Last() );
648 for ( Int_t isub=0; isub<subKeyList->GetEntries(); isub++ ) {
649 TString subKeyString = static_cast<TObjString*> (subKeyList->At(isub))->GetString();
95760506 650 if ( currKey == subKeyString ) {
ac4edd2e 651 matchKey = kTRUE;
652 break;
653 }
654 }
655 if ( ! matchKey ) continue;
656 if ( ! sumObject ) sumObject = obj->Clone();
657 else MergeObject(sumObject, obj);
658 debugMsg += Form(" %s%s",identifier.Data(),obj->GetName());
659 } // loop on objects in list
660 } // loop on identifiers in map
661
662 AliDebug(1,debugMsg.Data());
663
664 return sumObject;
665}
666
667//_____________________________________________________________________________
668Bool_t AliMergeableCollection::InternalAdopt(const char* identifier, TObject* obj)
669{
670 /// Adopt an obj
671
672 if (!obj)
673 {
674 Error("Adopt","Cannot adopt a null object");
675 return kFALSE;
676 }
677
678 if ( ! obj->IsA()->InheritsFrom(TObject::Class()) ||
679 ! obj->IsA()->GetMethodWithPrototype("Merge", "TCollection*") ) {
680 Error("Adopt","Cannot adopt an object which is not mergeable!");
681 }
682
683 THashList* hlist = 0x0;
684
685 hlist = static_cast<THashList*>(Map()->GetValue(identifier));
686
687 if (!hlist)
688 {
689 hlist = new THashList;
690 hlist->SetOwner(kTRUE);
691 Map()->Add(new TObjString(identifier),hlist);
692 hlist->SetName(identifier);
693 }
694
695 TObject* existingObj = hlist->FindObject(obj->GetName());
696
697 if (existingObj)
698 {
699 AliError(Form("Cannot adopt an already existing object : %s -> %s",identifier,existingObj->GetName()));
700 return kFALSE;
701 }
702
703 if ( obj->IsA()->InheritsFrom(TH1::Class()) ) (static_cast<TH1*> ( obj ))->SetDirectory(0);
704
705 hlist->AddLast(obj);
5376e016 706
ac4edd2e 707 return kTRUE;
708
709}
710
711//_____________________________________________________________________________
712TString
713AliMergeableCollection::InternalDecode(const char* identifier, Int_t index) const
714{
715 /// Extract the index-th element of the identifier (/key1/key2/.../keyN/objectName)
716 /// object is index=-1 (i.e. last)
717
718 if ( strlen(identifier) > 0 && identifier[0] != '/' )
719 {
720 AliError(Form("identifier %s is malformed (should start with /)",identifier));
721 return "";
722 }
723
d440e2c5 724 std::vector<Int_t> splitIndex;
725
726 Int_t start(0);
727 TString sidentifier(identifier);
728
729 while (start < sidentifier.Length())
ac4edd2e 730 {
d440e2c5 731 Int_t pos = sidentifier.Index('/', start);
732 if (pos == kNPOS) break;
733 splitIndex.push_back(pos);
734 start = pos + 1;
ac4edd2e 735 }
736
d440e2c5 737 Int_t nkeys = splitIndex.size() - 1;
ac4edd2e 738
d440e2c5 739 if ( index >= nkeys )
ac4edd2e 740 {
d440e2c5 741 AliError(Form("Requiring index %i of identifier %s which only have %i",index, identifier, nkeys));
742 return "";
ac4edd2e 743 }
d440e2c5 744
745 if ( index < 0 )
ac4edd2e 746 {
d440e2c5 747 return sidentifier(splitIndex.back()+1,sidentifier.Length()-splitIndex.back()-1);
ac4edd2e 748 }
d440e2c5 749
750 return sidentifier(splitIndex[index]+1,splitIndex[index+1]-splitIndex[index]-1);
ac4edd2e 751}
752
753//_____________________________________________________________________________
754TObject*
755AliMergeableCollection::InternalObject(const char* identifier,
756 const char* objectName) const
757{
758 /// Get object for (identifier,objectName)
759
760 if (!fMap)
761 {
762 return 0x0;
763 }
764
765 THashList* hlist = static_cast<THashList*>(Map()->GetValue(identifier));
766 if (!hlist)
767 {
768 TString msg(Form("Did not find hashlist for identifier=%s dir=%s",identifier,gDirectory ? gDirectory->GetName() : "" ));
769 fMessages[msg.Data()]++;
770 return 0x0;
771 }
772
773 TObject* obj = hlist->FindObject(objectName);
774 if (!obj)
775 {
776 TString msg(Form("Did not find objectName=%s in %s",objectName,identifier));
777 fMessages[msg.Data()]++;
778 }
779 return obj;
780}
781
782
783//_____________________________________________________________________________
784Bool_t AliMergeableCollection::IsEmptyObject(TObject* obj) const
785{
786 /// Check if object is empty
787 /// (done only for TH1, so far)
788
789 if ( obj->IsA()->InheritsFrom(TH1::Class()) ) {
790 TH1* histo = static_cast<TH1*> (obj);
791 if ( histo->GetEntries() == 0 ) return kTRUE;
792 }
793
794 return kFALSE;
795
796}
797
798
799//_____________________________________________________________________________
800TMap* AliMergeableCollection::Map() const
801{
802 /// Wrapper to insure proper key formats (i.e. new vs old)
803
804 if (!fMap)
805 {
806 fMap = new TMap;
807 fMap->SetOwnerKeyValue(kTRUE,kTRUE);
808 fMapVersion = 1;
809 }
810 else
811 {
812 if ( fMapVersion < 1 )
813 {
814 AliInfo("Remapping");
815 // change the keys
816 TIter next(fMap);
817 TObjString* str;
818
819 while ( ( str = static_cast<TObjString*>(next()) ) )
820 {
821 if ( str->String().Contains("./") )
822 {
823 TString newkey(str->String());
824
825 newkey.ReplaceAll("./","");
826
827 TObject* o = fMap->GetValue(str);
828
829 TPair* p = fMap->RemoveEntry(str);
830 if (!p)
831 {
832 AliError("oups oups oups");
833 return 0x0;
834 }
835
836 fMap->Add(new TObjString(newkey.Data()),o);
837
838 delete p;
839 }
840 }
841
842 fMapVersion = 1;
843 }
844 }
845
846 return fMap;
847}
848
849//_____________________________________________________________________________
850Long64_t
851AliMergeableCollection::Merge(TCollection* list)
852{
853 // Merge a list of AliMergeableCollection objects with this
854 // Returns the number of merged objects (including this).
855
856 if (!list) return 0;
857
858 if (list->IsEmpty()) return 1;
859
860 TIter next(list);
861 TObject* currObj;
862 TList mapList;
863 Int_t count(0);
864
865 while ( ( currObj = next() ) )
866 {
867 AliMergeableCollection* mergeCol = dynamic_cast<AliMergeableCollection*>(currObj);
868 if (!mergeCol) {
869 AliFatal(Form("object named \"%s\" is a %s instead of an AliMergeableCollection!", currObj->GetName(), currObj->ClassName()));
870 continue;
871 }
872
873 ++count;
874
875 if ( mergeCol->fMap ) mergeCol->Map(); // to insure keys in the new format
876
877 TIter nextIdentifier(mergeCol->fMap);
878 TObjString* identifier;
879
880 while ( ( identifier = static_cast<TObjString*>(nextIdentifier()) ) )
881 {
882 THashList* otherList = static_cast<THashList*>(mergeCol->fMap->GetValue(identifier->String().Data()));
883
884 TIter nextObject(otherList);
885 TObject* obj;
886
887 while ( ( obj = nextObject() ) )
888 {
889 TString newid(Form("%s%s",identifier->String().Data(),obj->GetName()));
890
891 TObject* thisObject = GetObject(newid.Data());
892
893 if (!thisObject)
894 {
895 AliDebug(1,Form("Adopting a new object = %s%s",identifier->String().Data(),obj->GetName()));
896
897 Bool_t ok = Adopt(identifier->String(), obj->Clone());
898
899 if (!ok)
900 {
901 AliError(Form("Adoption of object %s failed",obj->GetName()));
902 }
903 }
904 else
905 {
906 // add it...
907 AliDebug(1,Form("Merging object = %s%s",
908 identifier->String().Data(),
909 obj->GetName()));
910
911 MergeObject(thisObject, obj);
912 }
913 } // loop on objects in map
914 } // loop on identifiers
915 } // loop on collections in list
916
917 AliDebug(1,Form("count=%d",count));
918
919 return count+1;
920}
921
922//_____________________________________________________________________________
923Bool_t AliMergeableCollection::MergeObject(TObject* baseObject, TObject* objToAdd)
924{
925 /// Add objToAdd to baseObject
926
927 if ( baseObject->IsA()->Class() != objToAdd->IsA()->Class() ) {
928 printf("MergeObject: Cannot add %s to %s", objToAdd->ClassName(), baseObject->ClassName());
929 return kFALSE;
930 }
931 if ( ! baseObject->IsA()->InheritsFrom(TObject::Class()) ||
932 ! baseObject->IsA()->GetMethodWithPrototype("Merge", "TCollection*") ) {
933 printf("MergeObject: Objects are not mergeable!");
934 return kFALSE;
935 }
936
937 TList list;
938 list.Add(objToAdd);
939
940 TString listArgs = Form("((TCollection*)0x%lx)", (ULong_t)&list);
941 Int_t error = 0;
942 baseObject->Execute("Merge", listArgs.Data(), &error);
943 return kTRUE;
944}
945
946//_____________________________________________________________________________
947TString AliMergeableCollection::NormalizeName(const char* identifier,const char* action) const
948{
949 /// Replace / by _ to build a root-compliant histo name
950 TString name(GetName());
951
952 name += "_";
953 name += identifier;
954 name += "_";
955 name += action;
956 name.ReplaceAll("/","_");
957 name.ReplaceAll("-","_");
958 return name;
959}
960
961//_____________________________________________________________________________
962Int_t
963AliMergeableCollection::NumberOfObjects() const
964{
965 /// Get the number of objects we hold
79b4c269 966 TIter next(CreateIterator());
ac4edd2e 967 Int_t count(0);
968 while ( next() ) ++count;
969 return count;
970}
971
972//_____________________________________________________________________________
973Int_t
974AliMergeableCollection::NumberOfKeys() const
975{
976 /// Get the number of keys we have
977 return fMap ? fMap->GetSize() : 0;
978}
979
980//_____________________________________________________________________________
981void
982AliMergeableCollection::Print(Option_t* option) const
983{
984 /// Print all the objects we hold, in a hopefully visually pleasing
985 /// way.
986 ///
987 /// Option can be used to select given part only, using the schema :
988 /// /*/*/*/*/*
989 /// Where the stars are wilcards for /key1/key2/.../objectName
990 ///
991 /// if * is used it is assumed to be a wildcard for objectName
992 ///
993 /// For other selections the full syntax /*/*/*/*/* must be used.
994 ///
995 /// Use "-" as objectName to disable object's name output
d440e2c5 996 ///
997 /// One might also use /*/*/*/*/:classname syntax to restrict
998 /// output to only those objects matching a given classname pattern
999 ///
ac4edd2e 1000
5376e016
CP
1001 cout << Form("AliMergeableCollection(%s,%s)[%p] : %d keys and %d objects",
1002 GetName(),GetTitle(),this,
ac4edd2e 1003 NumberOfKeys(), NumberOfObjects()) << endl;
1004
1005 if (!strlen(option)) return;
d440e2c5 1006
1007 TString soption(option);
1008
1009 TObjArray* classes = soption.Tokenize(":");
1010
1011 TRegexp* classPattern(0x0);
1012
1013 if ( classes->GetLast() > 0 )
1014 {
1015 TString pat = static_cast<TObjString*>(classes->At(1))->String();
1016 classPattern = new TRegexp(pat,kTRUE);
1017 soption = static_cast<TObjString*>(classes->At(0))->String();
1018 }
1019
1020 delete classes;
1021
1022 TObjArray* select = soption.Tokenize("/");
ac4edd2e 1023
1024 TString sreObjectName(select->Last()->GetName());
1025 TRegexp reObjectName(sreObjectName.Data(),kTRUE);
1026
1027 TObjArray* identifiers = SortAllIdentifiers();
1028
5376e016 1029 std::cout << Form("Number of identifiers %d", identifiers->GetEntries()) << std::endl;
ac4edd2e 1030
1031 TIter nextIdentifier(identifiers);
1032
1033 TObjString* sid(0x0);
1034
1035 while ( ( sid = static_cast<TObjString*>(nextIdentifier()) ) )
1036 {
1037 Bool_t identifierPrinted(kFALSE);
1038
1039 TString identifier(sid->String());
1040
1041 Bool_t matchPattern = kTRUE;
1042 for ( Int_t isel=0; isel<select->GetLast(); isel++ ) {
1043 if ( ! GetKey(identifier.Data(), isel, kFALSE).Contains(TRegexp(select->At(isel)->GetName(),kTRUE)) ) {
1044 matchPattern = kFALSE;
1045 break;
1046 }
1047 }
1048 if ( ! matchPattern ) continue;
1049
d440e2c5 1050 if ( sreObjectName == "*" && !classPattern)
1051 {
ac4edd2e 1052 identifierPrinted = kTRUE;
1053 cout << identifier.Data() << endl;
1054 }
1055
d440e2c5 1056 THashList * list = static_cast<THashList*>(Map()->GetValue(sid->String().Data()));
1057
ac4edd2e 1058 TObjArray names;
1059 names.SetOwner(kTRUE);
1060 TIter nextUnsortedObj(list);
1061 TObject* obj;
1062 while ( ( obj = nextUnsortedObj() ) )
1063 {
d440e2c5 1064 TString cname(obj->ClassName());
1065 if ( classPattern && !cname.Contains((*classPattern)) )
1066 {
1067 continue;
1068 }
ac4edd2e 1069 names.Add(new TObjString(obj->GetName()));
1070 }
1071 names.Sort();
1072 TIter nextObjName(&names);
1073 TObjString* oname;
1074 while ( ( oname = static_cast<TObjString*>(nextObjName()) ) )
1075 {
1076 TString objName(oname->String());
1077 if (objName.Contains(reObjectName) )
1078 {
1079 obj = list->FindObject(objName.Data());
1080 if ( IsEmptyObject(obj) && ! fMustShowEmptyObject ) continue;
1b331634 1081
ac4edd2e 1082 if (!identifierPrinted)
1083 {
1084 cout << identifier.Data() << endl;
1085 identifierPrinted = kTRUE;
1086 }
1b331634 1087
1088 TString extra;
1089 TString warning(" ");
1090
1091 if ( obj->IsA()->InheritsFrom(TH1::Class()) )
1092 {
1093
ac4edd2e 1094 TH1* histo = static_cast<TH1*> (obj);
1b331634 1095 extra.Form("%s | Entries=%d Sum=%g",histo->GetTitle(),Int_t(histo->GetEntries()),histo->GetSumOfWeights());
1096 }
1097 else if ( obj->IsA()->InheritsFrom(TGraph::Class()) )
1098 {
1099 TGraph* graph = static_cast<TGraph*> (obj);
1100 if ( ! TMath::Finite(graph->GetMean(2) ) )
1101 {
1102 warning = " ! ";
1103 }
1104 extra.Form("%s | Npts=%d Mean=%g RMS=%g",graph->GetTitle(),graph->GetN(),
1105 graph->GetMean(2),graph->GetRMS(2));
1106
1107 }
1108
1109 std::cout << Form(" (%s) %s %s", obj->ClassName(),
1110 warning.Data(),
1111 obj->GetName());
1112
1113 if ( extra.Length() )
1114 {
1115 std::cout << " | " << extra.Data();
ac4edd2e 1116 }
1b331634 1117 std::cout << std::endl;
ac4edd2e 1118 }
1119 }
1120 if (!identifierPrinted && sreObjectName=="-" )
1121 {
1122 // to handle the case where we used objectName="-" to disable showing the objectNames,
1123 // but we still want to see the matching keys maybe...
1124 cout << identifier.Data() << endl;
1125 }
1126 }
1127
1128 delete select;
1129
1130 delete identifiers;
1131}
1132
1133//_____________________________________________________________________________
1134void
1135AliMergeableCollection::PrintMessages(const char* prefix) const
1136{
1137 /// Print pending messages
1138
1139 std::map<std::string,int>::const_iterator it;
1140
1141 for ( it = fMessages.begin(); it != fMessages.end(); ++it )
1142 {
1143 cout << Form("%s : message %s appeared %5d times",prefix,it->first.c_str(),it->second) << endl;
1144 }
1145}
1146
1147
1148//_____________________________________________________________________________
1149UInt_t
1150AliMergeableCollection::EstimateSize(Bool_t show) const
1151{
1152 /// Estimate the memory (in kilobytes) used by some objects
1153
1154// For TH1:
1155// sizeof(TH1) + (nbins+2)*(nbytes_per_bin) +name+title_sizes
1156// if you have errors add (nbins+2)*8
1157
1158 TIter next(CreateIterator());
1159
1160 TObject* obj;
1161 UInt_t size(0);
1162
1163 while ( ( obj = next() ) )
1164 {
1165 UInt_t thissize=0;
5376e016
CP
1166 if ( obj->IsA()->InheritsFrom(TH1::Class()) || obj->IsA()->InheritsFrom(TProfile::Class()) )
1167 {
ac4edd2e 1168 TH1* histo = static_cast<TH1*> (obj);
1169 Int_t nbins = (histo->GetNbinsX()+2);
1170
1171 if (histo->GetNbinsY()>1)
1172 {
1173 nbins *= (histo->GetNbinsY()+2);
1174 }
1175
1176 if (histo->GetNbinsZ()>1)
1177 {
1178 nbins *= (histo->GetNbinsZ()+2);
1179 }
1180
1181 Bool_t hasErrors = ( histo->GetSumw2N() > 0 );
1182
1183 TString cname(histo->ClassName());
1184
1185 Int_t nbytesPerBin(0);
1186
1187 if (cname.Contains(TRegexp("C$")) ) nbytesPerBin = sizeof(Char_t);
1188 if (cname.Contains(TRegexp("S$")) ) nbytesPerBin = sizeof(Short_t);
1189 if (cname.Contains(TRegexp("I$")) ) nbytesPerBin = sizeof(Int_t);
1190 if (cname.Contains(TRegexp("F$")) ) nbytesPerBin = sizeof(Float_t);
1191 if (cname.Contains(TRegexp("D$")) ) nbytesPerBin = sizeof(Double_t);
5376e016 1192 if (cname=="TProfile") nbytesPerBin = sizeof(Double_t);
ac4edd2e 1193
1194 if (!nbytesPerBin)
1195 {
1196 AliError(Form("Could not get the number of bytes per bin for histo %s of class %s. Thus the size estimate will be wrong !",
1197 histo->GetName(),histo->ClassName()));
1198 continue;
1199 }
1200
1201 thissize = sizeof(histo) + nbins*(nbytesPerBin) + strlen(histo->GetName())
1202 + strlen(histo->GetTitle());
1203
1204 if ( hasErrors) thissize += nbins*8;
5376e016
CP
1205
1206 if ( obj->IsA()->InheritsFrom(TProfile::Class()) )
1207 {
1208 TProfile* prof = static_cast<TProfile*>(obj);
1209 TArrayD* d = prof->GetBinSumw2();
1210 thissize += d->GetSize()*8*2; // 2 TArrayD
1211 thissize += sizeof(prof) - sizeof(histo);
1212 }
ac4edd2e 1213 }
95760506 1214 else if ( obj->IsA()->InheritsFrom(THnSparse::Class()) ) {
1215 THnSparse* sparse = static_cast<THnSparse*> (obj);
1216 thissize = sizeof(Float_t) * (UInt_t)sparse->GetNbins();
1217 }
1218// else if ( obj->IsA() == AliCFGridSparse::Class() ) {
1219// AliCFGridSparse* sparse = static_cast<AliCFGridSparse*> (obj);
1220// thissize = sizeof(Float_t) * (UInt_t)sparse->GetNFilledBins();
1221// }
1222// else if ( obj->IsA() == AliCFContainer::Class() ) {
1223// AliCFContainer* cont = static_cast<AliCFContainer*> (obj);
1224// for ( Int_t istep=0; istep<cont->GetNStep(); istep++ ) {
1225// thissize += sizeof(Float_t) * (UInt_t)cont->GetGrid(istep)->GetNFilledBins();
1226// }
1227// }
ac4edd2e 1228 else {
1229 AliWarning(Form("Cannot estimate size of %s\n", obj->ClassName()));
1230 continue;
1231 }
1232
1233 size += thissize;
1234
1235 if ( show )
1236 {
1237 AliInfo(Form("Size of %30s is %20d bytes",obj->GetName(),thissize));
1238 }
1239 } // loop on objects
1240
1241 return size;
1242}
1243
1b331634 1244//_____________________________________________________________________________
1245Int_t AliMergeableCollection::Prune(const char* identifier)
1246{
1247 // Delete all objects which match the beginning of the identifier
1248 // returns the number of entries removed from the Map()
1249 // (not to be confused with the number of leaf objects removed)
1250 //
1251
1252 TIter next(Map());
1253 TObjString* key;
1254 Int_t ndeleted(0);
1255
1256 while ( ( key = static_cast<TObjString*>(next())) )
1257 {
1258 if (key->String().BeginsWith(identifier))
1259 {
1260 Bool_t ok = Map()->DeleteEntry(key);
1261 if (ok) ++ndeleted;
1262 }
1263 }
1264
1265 return ndeleted;
1266}
1267
ac4edd2e 1268//_____________________________________________________________________________
1269void AliMergeableCollection::PruneEmptyObjects()
1270{
1271 /// Delete the empty objects
1272 /// (Implemented for TH1 only)
1273 TIter next(Map());
1274 TObjString* key;
1275
1276 TList toBeRemoved;
1277 toBeRemoved.SetOwner(kTRUE);
1278
1279 while ( ( key = static_cast<TObjString*>(next()) ) )
1280 {
1281 TString identifier(key->String());
1282 THashList* hlist = static_cast<THashList*>(Map()->GetValue(identifier.Data()));
1283 TIter nextObject(hlist);
1284 TObject* obj;
1285 while ( ( obj = nextObject() ) )
1286 {
1287 if ( IsEmptyObject(obj) ) toBeRemoved.Add(new TObjString(Form("%s%s",identifier.Data(),obj->GetName())));
1288 }
1289 }
1290
1291 TIter nextTBR(&toBeRemoved);
1292 while ( ( key = static_cast<TObjString*>(nextTBR()) ) )
1293 {
1294 Remove(key->GetString().Data());
1295 AliDebug(2,Form("Removing %s", key->GetString().Data()));
1296 }
1297}
1298
1299//_____________________________________________________________________________
1300AliMergeableCollection*
1301AliMergeableCollection::Project(const char* identifier) const
1302{
1303 /// To be implemented : would create a new collection starting at /key1/key2/...
1304
1305 if (!fMap) return 0x0;
1306
1307 AliMergeableCollection* mergCol = new AliMergeableCollection(Form("%s %s",GetName(),identifier),
1308 GetTitle());
1309
1310 TIter next(Map());
1311 TObjString* str;
1312
1313 while ( ( str = static_cast<TObjString*>(next()) ) )
1314 {
1315 TString currIdentifier = str->String();
1316 if ( ! currIdentifier.Contains(identifier) ) continue;
1317
1318 THashList* list = static_cast<THashList*>(Map()->GetValue(identifier));
1319
1320 TIter nextObj(list);
1321 TObject* obj;
1322
1323 while ( ( obj = nextObj()) )
1324 {
1325 TObject* clone = obj->Clone();
1326
1327 TString newkey(currIdentifier.Data());
1328 newkey.ReplaceAll(identifier,"");
1329
1330 if (newkey=="/") newkey="";
1331
1332 mergCol->InternalAdopt(newkey.Data(),clone);
1333 }
1334 }
1335
1336 return mergCol;
1337}
1338
1339//_____________________________________________________________________________
1340TObject*
1341AliMergeableCollection::Remove(const char* fullIdentifier)
1342{
1343 ///
1344 /// Remove a given object (given its fullIdentifier=/key1/key2/.../objectName)
1345 ///
1346 /// Note that we do *not* remove the /key1/key2/... entry even if there's no
1347 /// more object for this triplet.
1348 ///
1349 /// Not very efficient. Could be improved ?
1350 ///
1351
1352 TString identifier = GetIdentifier(fullIdentifier);
1353
1354 THashList* hlist = dynamic_cast<THashList*>(Map()->GetValue(identifier.Data()));
1355
1356 if (!hlist)
1357 {
1358 AliWarning(Form("Could not get hlist for key=%s",identifier.Data()));
1359 return 0x0;
1360 }
1361
1362 TObject* obj = GetObject(fullIdentifier);
1363 if (!obj)
1364 {
1365 AliError(Form("Could not find object %s",fullIdentifier));
1366 return 0x0;
1367 }
1368
1369 TObject* rmObj = hlist->Remove(obj);
1370 if (!rmObj)
1371 {
1372 AliError("Remove failed");
1373 return 0x0;
1374 }
1375
1376 return rmObj;
1377}
1378
d440e2c5 1379//_____________________________________________________________________________
1380Int_t AliMergeableCollection::RemoveByType(const char* typeName)
1381{
1382 /// Remove all the objects in this collection that are of a given type
1383 TIter nextIdentifier(Map());
1384 TObjString* identifier;
1385 Int_t nremoved(0);
1386
1387 while ( (identifier = static_cast<TObjString*>(nextIdentifier()) ) )
1388 {
1389 THashList* list = static_cast<THashList*>(Map()->GetValue(identifier->String()));
1390 TIter next(list);
1391 TObject* o;
1392
1393 while ( ( o = next() ) )
1394 {
1395 if ( strcmp(o->ClassName(),typeName) == 0 )
1396 {
1397 list->Remove(o);
1398 ++nremoved;
1399 }
1400 }
1401 }
1402 return nremoved;
1403}
1404
1405
ac4edd2e 1406//_____________________________________________________________________________
1407TObjArray*
1408AliMergeableCollection::SortAllIdentifiers() const
1409{
1410 /// Sort our internal identifiers. Returned array must be deleted.
1411 TObjArray* identifiers = new TObjArray;
1412 identifiers->SetOwner(kFALSE);
1413 TIter next(Map());
1414 TObjString* sid;
1415
1416 while ( ( sid = static_cast<TObjString*>(next()) ) )
1417 {
1418 if ( !identifiers->FindObject(sid->String().Data()) )
1419 {
1420 identifiers->Add(sid);
1421 }
1422 }
1423 identifiers->Sort();
1424 return identifiers;
1425}
1426
1427
1428///////////////////////////////////////////////////////////////////////////////
1429//
1430// AliMergeableCollectionIterator
1431//
1432///////////////////////////////////////////////////////////////////////////////
1433
1434class AliMergeableCollectionIterator;
1435
1436//_____________________________________________________________________________
1437AliMergeableCollectionIterator::AliMergeableCollectionIterator(const AliMergeableCollection* mcol, Bool_t dir)
1438: fkMergeableCollection(mcol), fMapIterator(0x0), fHashListIterator(0x0), fDirection(dir)
1439{
1440 /// Default ctor
1441}
1442
1443//_____________________________________________________________________________
1444AliMergeableCollectionIterator&
1445AliMergeableCollectionIterator::operator=(const TIterator&)
1446{
1447 /// Overriden operator= (imposed by Root's declaration of TIterator ?)
1448 Fatal("TIterator::operator=","Not implementeable"); // because there's no clone in TIterator :-(
1449 return *this;
1450}
1451
1452//_____________________________________________________________________________
1453AliMergeableCollectionIterator::~AliMergeableCollectionIterator()
1454{
1455 /// dtor
1456 Reset();
1457}
1458
1459//_____________________________________________________________________________
1460TObject* AliMergeableCollectionIterator::Next()
1461{
1462 /// Advance to next object in the collection
1463
1464 if (!fHashListIterator)
1465 {
1466 if ( !fMapIterator )
1467 {
1468 fMapIterator = fkMergeableCollection->fMap->MakeIterator(fDirection);
1469 }
1470 TObjString* key = static_cast<TObjString*>(fMapIterator->Next());
1471 if (!key)
1472 {
1473 // we are done
1474 return 0x0;
1475 }
1476 THashList* list = static_cast<THashList*>(fkMergeableCollection->Map()->GetValue(key->String().Data()));
1477 if (!list) return 0x0;
1478 fHashListIterator = list->MakeIterator(fDirection);
1479 }
1480
1481 TObject* obj = fHashListIterator->Next();
1482
1483 if (!obj)
1484 {
1485 delete fHashListIterator;
1486 fHashListIterator = 0x0;
1487 return Next();
1488 }
1489
1490 return obj;
1491}
1492
1493//_____________________________________________________________________________
1494void AliMergeableCollectionIterator::Reset()
1495{
1496 /// Reset the iterator
1497 delete fHashListIterator;
1498 delete fMapIterator;
1499}