]>
Commit | Line | Data |
---|---|---|
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 | 29 | using std::cout; |
30 | using std::endl; | |
ac4edd2e | 31 | ClassImp(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 | //_____________________________________________________________________________ | |
55 | AliMergeableCollection::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 | //_____________________________________________________________________________ | |
62 | AliMergeableCollection::~AliMergeableCollection() | |
63 | { | |
64 | /// dtor. Note that the map is owner | |
ac4edd2e | 65 | delete fMap; |
66 | } | |
67 | ||
68 | //_____________________________________________________________________________ | |
69 | Bool_t | |
70 | AliMergeableCollection::Adopt(TObject* obj) | |
71 | { | |
72 | /// Adopt a given object at top level (i.e. no key) | |
73 | return InternalAdopt("",obj); | |
74 | } | |
75 | ||
76 | //_____________________________________________________________________________ | |
77 | Bool_t | |
78 | AliMergeableCollection::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 | //_____________________________________________________________________________ |
90 | Bool_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 | //_____________________________________________________________________________ |
133 | void 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 | //_____________________________________________________________________________ |
196 | void AliMergeableCollection::ClearMessages() | |
197 | { | |
198 | /// clear pending messages | |
199 | fMessages.clear(); | |
200 | } | |
201 | ||
202 | //_____________________________________________________________________________ | |
203 | TIterator* | |
204 | AliMergeableCollection::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 | //_____________________________________________________________________________ | |
211 | AliMergeableCollection* | |
212 | AliMergeableCollection::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 | //_____________________________________________________________________________ | |
227 | void | |
228 | AliMergeableCollection::Delete(Option_t*) | |
229 | { | |
230 | /// Delete all the objects | |
231 | fMap->DeleteAll(); | |
232 | delete fMap; | |
233 | fMap=0x0; | |
234 | } | |
235 | ||
236 | //_____________________________________________________________________________ | |
237 | TObject* | |
238 | AliMergeableCollection::FindObject(const char* fullIdentifier) const | |
239 | { | |
240 | /// Find an object by its full identifier. | |
241 | ||
242 | return GetObject(fullIdentifier); | |
243 | } | |
244 | ||
245 | //_____________________________________________________________________________ | |
246 | TObject* | |
247 | AliMergeableCollection::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 | //_____________________________________________________________________________ | |
262 | TList* | |
263 | AliMergeableCollection::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 | //_____________________________________________________________________________ | |
288 | TList* | |
289 | AliMergeableCollection::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 | //_____________________________________________________________________________ | |
321 | TString | |
322 | AliMergeableCollection::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 | //_____________________________________________________________________________ | |
340 | TString | |
341 | AliMergeableCollection::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 | //_____________________________________________________________________________ | |
356 | TString | |
357 | AliMergeableCollection::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 | 365 | TH1* |
366 | AliMergeableCollection::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 | //_____________________________________________________________________________ | |
412 | TH1* | |
413 | AliMergeableCollection::Histo(const char* identifier, | |
414 | const char* objectName) const | |
415 | { | |
416 | TObject* o = GetObject(identifier,objectName); | |
ac4edd2e | 417 | |
d440e2c5 | 418 | TObjArray* arr = TString(objectName).Tokenize(":"); |
ac4edd2e | 419 | TString action; |
420 | ||
d440e2c5 | 421 | if ( arr->GetLast() > 0 ) |
ac4edd2e | 422 | { |
423 | action = static_cast<TObjString*>(arr->At(1))->String(); | |
424 | action.ToUpper(); | |
425 | } | |
426 | ||
427 | delete arr; | |
d440e2c5 | 428 | |
429 | return HistoWithAction(identifier,o,action); | |
430 | } | |
431 | ||
432 | ||
433 | //_____________________________________________________________________________ | |
434 | TH1* | |
435 | AliMergeableCollection::HistoWithAction(const char* identifier, TObject* o, const TString& action) const | |
436 | { | |
437 | /// Convert o to an histogram if possible, applying a given action if there | |
438 | ||
439 | if (!o) return 0x0; | |
440 | ||
441 | if (!o->InheritsFrom("TH1")) | |
442 | { | |
443 | AliError(Form("%s is not an histogram",o->GetName())); | |
444 | return 0x0; | |
445 | } | |
446 | ||
447 | TH2* h2 = dynamic_cast<TH2*>(o); | |
448 | ||
449 | if (h2) | |
450 | { | |
451 | if ( action == "PX" ) | |
452 | { | |
453 | return h2->ProjectionX(NormalizeName(Form("%s/%s",identifier,o->GetName()),action.Data()).Data()); | |
454 | } | |
455 | if ( action == "PY" ) | |
456 | { | |
457 | return h2->ProjectionY(NormalizeName(Form("%s/%s",identifier,o->GetName()),action.Data()).Data()); | |
458 | } | |
459 | if ( action == "PFX" ) | |
460 | { | |
461 | return h2->ProfileX(NormalizeName(Form("%s/%s",identifier,o->GetName()),action.Data()).Data()); | |
462 | } | |
463 | if ( action == "PFY" ) | |
464 | { | |
465 | return h2->ProfileY(NormalizeName(Form("%s/%s",identifier,o->GetName()),action.Data()).Data()); | |
466 | } | |
467 | } | |
ac4edd2e | 468 | |
d440e2c5 | 469 | return static_cast<TH1*>(o); |
470 | } | |
471 | ||
472 | ||
473 | //_____________________________________________________________________________ | |
474 | TObject* | |
475 | AliMergeableCollection::GetObject(const char* fullIdentifier) const | |
476 | { | |
477 | /// Get object key1/key2/.../objectName | |
478 | /// Note that no action is allowed for generic objects (only for histograms, | |
479 | /// see Histo() methods) | |
480 | ||
481 | TString sfullIdentifier(fullIdentifier); | |
482 | ||
483 | Int_t nslashes = sfullIdentifier.CountChar('/'); | |
484 | ||
485 | if (!nslashes) | |
486 | { | |
487 | return GetObject("", sfullIdentifier); | |
488 | } | |
489 | else | |
490 | { | |
491 | return GetObject(GetIdentifier(fullIdentifier).Data(), GetObjectName(fullIdentifier)); | |
492 | } | |
ac4edd2e | 493 | } |
494 | ||
495 | ||
496 | //_____________________________________________________________________________ | |
497 | TObject* | |
498 | AliMergeableCollection::GetObject(const char* identifier, | |
499 | const char* objectName) const | |
500 | { | |
501 | /// Get object for (identifier,objectName) triplet | |
502 | ||
503 | TString sidentifier(identifier); | |
504 | if ( ! sidentifier.IsNull() ) { | |
505 | if ( ! sidentifier.BeginsWith("/") ) sidentifier.Prepend("/"); | |
506 | if ( ! sidentifier.EndsWith("/") ) sidentifier.Append("/"); | |
507 | } | |
508 | return InternalObject(sidentifier.Data(),objectName); | |
509 | } | |
510 | ||
511 | //_____________________________________________________________________________ | |
d5a197f5 | 512 | TObject* AliMergeableCollection::GetSum(const char* idPattern) const |
ac4edd2e | 513 | { |
514 | /// Sum objects | |
515 | /// The pattern must be in the form: | |
95760506 | 516 | /// /key1_1,key1_2,.../key2_1,key2_2,.../.../objectName_1,objectName_2... |
ac4edd2e | 517 | /// The logical or between patterns separated by commas is taken |
95760506 | 518 | /// Exact match is required for keys and objectNames |
ac4edd2e | 519 | |
520 | TObject* sumObject = 0x0; | |
521 | ||
522 | // Build array of lists of pattern | |
523 | TString idPatternString(idPattern); | |
524 | TObjArray* keyList = idPatternString.Tokenize("/"); | |
525 | TObjArray keyMatrix(keyList->GetEntries()); | |
526 | keyMatrix.SetOwner(); | |
527 | for ( Int_t ikey=0; ikey<keyList->GetEntries(); ikey++ ) { | |
528 | TObjArray* subKeyList = ((TObjString*)keyList->At(ikey))->GetString().Tokenize(","); | |
529 | keyMatrix.AddAt(subKeyList, ikey); | |
530 | } | |
531 | delete keyList; | |
532 | ||
533 | TString debugMsg = "Adding objects:"; | |
534 | ||
95760506 | 535 | // |
536 | // First handle the keys | |
537 | // | |
ac4edd2e | 538 | TIter next(Map()); |
539 | TObjString* str; | |
540 | while ( ( str = static_cast<TObjString*>(next()) ) ) | |
541 | { | |
542 | TString identifier = str->String(); | |
543 | ||
544 | Bool_t listMatchPattern = kTRUE; | |
545 | for ( Int_t ikey=0; ikey<keyMatrix.GetEntries()-1; ikey++ ) { | |
546 | TString currKey = GetKey(identifier, ikey, kFALSE); | |
547 | Bool_t matchKey = kFALSE; | |
548 | TObjArray* subKeyList = static_cast<TObjArray*> ( keyMatrix.At(ikey) ); | |
549 | for ( Int_t isub=0; isub<subKeyList->GetEntries(); isub++ ) { | |
550 | TString subKeyString = static_cast<TObjString*> (subKeyList->At(isub))->GetString(); | |
95760506 | 551 | if ( currKey == subKeyString ) { |
ac4edd2e | 552 | matchKey = kTRUE; |
553 | break; | |
554 | } | |
555 | } // loop on the list of patterns of each key | |
556 | if ( ! matchKey ) { | |
557 | listMatchPattern = kFALSE; | |
558 | break; | |
559 | } | |
560 | } // loop on keys in the idPattern | |
561 | if ( ! listMatchPattern ) continue; | |
562 | ||
95760506 | 563 | |
564 | // | |
565 | // Then handle the object name | |
566 | // | |
ac4edd2e | 567 | THashList* list = static_cast<THashList*>(Map()->GetValue(identifier.Data())); |
568 | ||
569 | TIter nextObj(list); | |
570 | TObject* obj; | |
571 | ||
572 | while ( ( obj = nextObj()) ) | |
573 | { | |
574 | TString currKey = obj->GetName(); | |
575 | Bool_t matchKey = kFALSE; | |
576 | TObjArray* subKeyList = static_cast<TObjArray*> ( keyMatrix.Last() ); | |
577 | for ( Int_t isub=0; isub<subKeyList->GetEntries(); isub++ ) { | |
578 | TString subKeyString = static_cast<TObjString*> (subKeyList->At(isub))->GetString(); | |
95760506 | 579 | if ( currKey == subKeyString ) { |
ac4edd2e | 580 | matchKey = kTRUE; |
581 | break; | |
582 | } | |
583 | } | |
584 | if ( ! matchKey ) continue; | |
585 | if ( ! sumObject ) sumObject = obj->Clone(); | |
586 | else MergeObject(sumObject, obj); | |
587 | debugMsg += Form(" %s%s",identifier.Data(),obj->GetName()); | |
588 | } // loop on objects in list | |
589 | } // loop on identifiers in map | |
590 | ||
591 | AliDebug(1,debugMsg.Data()); | |
592 | ||
593 | return sumObject; | |
594 | } | |
595 | ||
596 | //_____________________________________________________________________________ | |
597 | Bool_t AliMergeableCollection::InternalAdopt(const char* identifier, TObject* obj) | |
598 | { | |
599 | /// Adopt an obj | |
600 | ||
601 | if (!obj) | |
602 | { | |
603 | Error("Adopt","Cannot adopt a null object"); | |
604 | return kFALSE; | |
605 | } | |
606 | ||
607 | if ( ! obj->IsA()->InheritsFrom(TObject::Class()) || | |
608 | ! obj->IsA()->GetMethodWithPrototype("Merge", "TCollection*") ) { | |
609 | Error("Adopt","Cannot adopt an object which is not mergeable!"); | |
610 | } | |
611 | ||
612 | THashList* hlist = 0x0; | |
613 | ||
614 | hlist = static_cast<THashList*>(Map()->GetValue(identifier)); | |
615 | ||
616 | if (!hlist) | |
617 | { | |
618 | hlist = new THashList; | |
619 | hlist->SetOwner(kTRUE); | |
620 | Map()->Add(new TObjString(identifier),hlist); | |
621 | hlist->SetName(identifier); | |
622 | } | |
623 | ||
624 | TObject* existingObj = hlist->FindObject(obj->GetName()); | |
625 | ||
626 | if (existingObj) | |
627 | { | |
628 | AliError(Form("Cannot adopt an already existing object : %s -> %s",identifier,existingObj->GetName())); | |
629 | return kFALSE; | |
630 | } | |
631 | ||
632 | if ( obj->IsA()->InheritsFrom(TH1::Class()) ) (static_cast<TH1*> ( obj ))->SetDirectory(0); | |
633 | ||
634 | hlist->AddLast(obj); | |
635 | ||
73a1ccd5 | 636 | // invalidate the TFolder structure, if any, so it will |
637 | // be recomputed next time Browse() is called | |
638 | delete fFolders; | |
639 | fFolders = 0x0; | |
640 | ||
ac4edd2e | 641 | return kTRUE; |
642 | ||
643 | } | |
644 | ||
645 | //_____________________________________________________________________________ | |
646 | TString | |
647 | AliMergeableCollection::InternalDecode(const char* identifier, Int_t index) const | |
648 | { | |
649 | /// Extract the index-th element of the identifier (/key1/key2/.../keyN/objectName) | |
650 | /// object is index=-1 (i.e. last) | |
651 | ||
652 | if ( strlen(identifier) > 0 && identifier[0] != '/' ) | |
653 | { | |
654 | AliError(Form("identifier %s is malformed (should start with /)",identifier)); | |
655 | return ""; | |
656 | } | |
657 | ||
d440e2c5 | 658 | std::vector<Int_t> splitIndex; |
659 | ||
660 | Int_t start(0); | |
661 | TString sidentifier(identifier); | |
662 | ||
663 | while (start < sidentifier.Length()) | |
ac4edd2e | 664 | { |
d440e2c5 | 665 | Int_t pos = sidentifier.Index('/', start); |
666 | if (pos == kNPOS) break; | |
667 | splitIndex.push_back(pos); | |
668 | start = pos + 1; | |
ac4edd2e | 669 | } |
670 | ||
d440e2c5 | 671 | Int_t nkeys = splitIndex.size() - 1; |
ac4edd2e | 672 | |
d440e2c5 | 673 | if ( index >= nkeys ) |
ac4edd2e | 674 | { |
d440e2c5 | 675 | AliError(Form("Requiring index %i of identifier %s which only have %i",index, identifier, nkeys)); |
676 | return ""; | |
ac4edd2e | 677 | } |
d440e2c5 | 678 | |
679 | if ( index < 0 ) | |
ac4edd2e | 680 | { |
d440e2c5 | 681 | return sidentifier(splitIndex.back()+1,sidentifier.Length()-splitIndex.back()-1); |
ac4edd2e | 682 | } |
d440e2c5 | 683 | |
684 | return sidentifier(splitIndex[index]+1,splitIndex[index+1]-splitIndex[index]-1); | |
ac4edd2e | 685 | } |
686 | ||
687 | //_____________________________________________________________________________ | |
688 | TObject* | |
689 | AliMergeableCollection::InternalObject(const char* identifier, | |
690 | const char* objectName) const | |
691 | { | |
692 | /// Get object for (identifier,objectName) | |
693 | ||
694 | if (!fMap) | |
695 | { | |
696 | return 0x0; | |
697 | } | |
698 | ||
699 | THashList* hlist = static_cast<THashList*>(Map()->GetValue(identifier)); | |
700 | if (!hlist) | |
701 | { | |
702 | TString msg(Form("Did not find hashlist for identifier=%s dir=%s",identifier,gDirectory ? gDirectory->GetName() : "" )); | |
703 | fMessages[msg.Data()]++; | |
704 | return 0x0; | |
705 | } | |
706 | ||
707 | TObject* obj = hlist->FindObject(objectName); | |
708 | if (!obj) | |
709 | { | |
710 | TString msg(Form("Did not find objectName=%s in %s",objectName,identifier)); | |
711 | fMessages[msg.Data()]++; | |
712 | } | |
713 | return obj; | |
714 | } | |
715 | ||
716 | ||
717 | //_____________________________________________________________________________ | |
718 | Bool_t AliMergeableCollection::IsEmptyObject(TObject* obj) const | |
719 | { | |
720 | /// Check if object is empty | |
721 | /// (done only for TH1, so far) | |
722 | ||
723 | if ( obj->IsA()->InheritsFrom(TH1::Class()) ) { | |
724 | TH1* histo = static_cast<TH1*> (obj); | |
725 | if ( histo->GetEntries() == 0 ) return kTRUE; | |
726 | } | |
727 | ||
728 | return kFALSE; | |
729 | ||
730 | } | |
731 | ||
732 | ||
733 | //_____________________________________________________________________________ | |
734 | TMap* AliMergeableCollection::Map() const | |
735 | { | |
736 | /// Wrapper to insure proper key formats (i.e. new vs old) | |
737 | ||
738 | if (!fMap) | |
739 | { | |
740 | fMap = new TMap; | |
741 | fMap->SetOwnerKeyValue(kTRUE,kTRUE); | |
742 | fMapVersion = 1; | |
743 | } | |
744 | else | |
745 | { | |
746 | if ( fMapVersion < 1 ) | |
747 | { | |
748 | AliInfo("Remapping"); | |
749 | // change the keys | |
750 | TIter next(fMap); | |
751 | TObjString* str; | |
752 | ||
753 | while ( ( str = static_cast<TObjString*>(next()) ) ) | |
754 | { | |
755 | if ( str->String().Contains("./") ) | |
756 | { | |
757 | TString newkey(str->String()); | |
758 | ||
759 | newkey.ReplaceAll("./",""); | |
760 | ||
761 | TObject* o = fMap->GetValue(str); | |
762 | ||
763 | TPair* p = fMap->RemoveEntry(str); | |
764 | if (!p) | |
765 | { | |
766 | AliError("oups oups oups"); | |
767 | return 0x0; | |
768 | } | |
769 | ||
770 | fMap->Add(new TObjString(newkey.Data()),o); | |
771 | ||
772 | delete p; | |
773 | } | |
774 | } | |
775 | ||
776 | fMapVersion = 1; | |
777 | } | |
778 | } | |
779 | ||
780 | return fMap; | |
781 | } | |
782 | ||
783 | //_____________________________________________________________________________ | |
784 | Long64_t | |
785 | AliMergeableCollection::Merge(TCollection* list) | |
786 | { | |
787 | // Merge a list of AliMergeableCollection objects with this | |
788 | // Returns the number of merged objects (including this). | |
789 | ||
790 | if (!list) return 0; | |
791 | ||
792 | if (list->IsEmpty()) return 1; | |
793 | ||
794 | TIter next(list); | |
795 | TObject* currObj; | |
796 | TList mapList; | |
797 | Int_t count(0); | |
798 | ||
799 | while ( ( currObj = next() ) ) | |
800 | { | |
801 | AliMergeableCollection* mergeCol = dynamic_cast<AliMergeableCollection*>(currObj); | |
802 | if (!mergeCol) { | |
803 | AliFatal(Form("object named \"%s\" is a %s instead of an AliMergeableCollection!", currObj->GetName(), currObj->ClassName())); | |
804 | continue; | |
805 | } | |
806 | ||
807 | ++count; | |
808 | ||
809 | if ( mergeCol->fMap ) mergeCol->Map(); // to insure keys in the new format | |
810 | ||
811 | TIter nextIdentifier(mergeCol->fMap); | |
812 | TObjString* identifier; | |
813 | ||
814 | while ( ( identifier = static_cast<TObjString*>(nextIdentifier()) ) ) | |
815 | { | |
816 | THashList* otherList = static_cast<THashList*>(mergeCol->fMap->GetValue(identifier->String().Data())); | |
817 | ||
818 | TIter nextObject(otherList); | |
819 | TObject* obj; | |
820 | ||
821 | while ( ( obj = nextObject() ) ) | |
822 | { | |
823 | TString newid(Form("%s%s",identifier->String().Data(),obj->GetName())); | |
824 | ||
825 | TObject* thisObject = GetObject(newid.Data()); | |
826 | ||
827 | if (!thisObject) | |
828 | { | |
829 | AliDebug(1,Form("Adopting a new object = %s%s",identifier->String().Data(),obj->GetName())); | |
830 | ||
831 | Bool_t ok = Adopt(identifier->String(), obj->Clone()); | |
832 | ||
833 | if (!ok) | |
834 | { | |
835 | AliError(Form("Adoption of object %s failed",obj->GetName())); | |
836 | } | |
837 | } | |
838 | else | |
839 | { | |
840 | // add it... | |
841 | AliDebug(1,Form("Merging object = %s%s", | |
842 | identifier->String().Data(), | |
843 | obj->GetName())); | |
844 | ||
845 | MergeObject(thisObject, obj); | |
846 | } | |
847 | } // loop on objects in map | |
848 | } // loop on identifiers | |
849 | } // loop on collections in list | |
850 | ||
851 | AliDebug(1,Form("count=%d",count)); | |
852 | ||
853 | return count+1; | |
854 | } | |
855 | ||
856 | //_____________________________________________________________________________ | |
857 | Bool_t AliMergeableCollection::MergeObject(TObject* baseObject, TObject* objToAdd) | |
858 | { | |
859 | /// Add objToAdd to baseObject | |
860 | ||
861 | if ( baseObject->IsA()->Class() != objToAdd->IsA()->Class() ) { | |
862 | printf("MergeObject: Cannot add %s to %s", objToAdd->ClassName(), baseObject->ClassName()); | |
863 | return kFALSE; | |
864 | } | |
865 | if ( ! baseObject->IsA()->InheritsFrom(TObject::Class()) || | |
866 | ! baseObject->IsA()->GetMethodWithPrototype("Merge", "TCollection*") ) { | |
867 | printf("MergeObject: Objects are not mergeable!"); | |
868 | return kFALSE; | |
869 | } | |
870 | ||
871 | TList list; | |
872 | list.Add(objToAdd); | |
873 | ||
874 | TString listArgs = Form("((TCollection*)0x%lx)", (ULong_t)&list); | |
875 | Int_t error = 0; | |
876 | baseObject->Execute("Merge", listArgs.Data(), &error); | |
877 | return kTRUE; | |
878 | } | |
879 | ||
880 | //_____________________________________________________________________________ | |
881 | TString AliMergeableCollection::NormalizeName(const char* identifier,const char* action) const | |
882 | { | |
883 | /// Replace / by _ to build a root-compliant histo name | |
884 | TString name(GetName()); | |
885 | ||
886 | name += "_"; | |
887 | name += identifier; | |
888 | name += "_"; | |
889 | name += action; | |
890 | name.ReplaceAll("/","_"); | |
891 | name.ReplaceAll("-","_"); | |
892 | return name; | |
893 | } | |
894 | ||
895 | //_____________________________________________________________________________ | |
896 | Int_t | |
897 | AliMergeableCollection::NumberOfObjects() const | |
898 | { | |
899 | /// Get the number of objects we hold | |
79b4c269 | 900 | TIter next(CreateIterator()); |
ac4edd2e | 901 | Int_t count(0); |
902 | while ( next() ) ++count; | |
903 | return count; | |
904 | } | |
905 | ||
906 | //_____________________________________________________________________________ | |
907 | Int_t | |
908 | AliMergeableCollection::NumberOfKeys() const | |
909 | { | |
910 | /// Get the number of keys we have | |
911 | return fMap ? fMap->GetSize() : 0; | |
912 | } | |
913 | ||
914 | //_____________________________________________________________________________ | |
915 | void | |
916 | AliMergeableCollection::Print(Option_t* option) const | |
917 | { | |
918 | /// Print all the objects we hold, in a hopefully visually pleasing | |
919 | /// way. | |
920 | /// | |
921 | /// Option can be used to select given part only, using the schema : | |
922 | /// /*/*/*/*/* | |
923 | /// Where the stars are wilcards for /key1/key2/.../objectName | |
924 | /// | |
925 | /// if * is used it is assumed to be a wildcard for objectName | |
926 | /// | |
927 | /// For other selections the full syntax /*/*/*/*/* must be used. | |
928 | /// | |
929 | /// Use "-" as objectName to disable object's name output | |
d440e2c5 | 930 | /// |
931 | /// One might also use /*/*/*/*/:classname syntax to restrict | |
932 | /// output to only those objects matching a given classname pattern | |
933 | /// | |
ac4edd2e | 934 | |
935 | cout << Form("AliMergeableCollection(%s,%s) : %d keys and %d objects", | |
936 | GetName(),GetTitle(), | |
937 | NumberOfKeys(), NumberOfObjects()) << endl; | |
938 | ||
939 | if (!strlen(option)) return; | |
d440e2c5 | 940 | |
941 | TString soption(option); | |
942 | ||
943 | TObjArray* classes = soption.Tokenize(":"); | |
944 | ||
945 | TRegexp* classPattern(0x0); | |
946 | ||
947 | if ( classes->GetLast() > 0 ) | |
948 | { | |
949 | TString pat = static_cast<TObjString*>(classes->At(1))->String(); | |
950 | classPattern = new TRegexp(pat,kTRUE); | |
951 | soption = static_cast<TObjString*>(classes->At(0))->String(); | |
952 | } | |
953 | ||
954 | delete classes; | |
955 | ||
956 | TObjArray* select = soption.Tokenize("/"); | |
ac4edd2e | 957 | |
958 | TString sreObjectName(select->Last()->GetName()); | |
959 | TRegexp reObjectName(sreObjectName.Data(),kTRUE); | |
960 | ||
961 | TObjArray* identifiers = SortAllIdentifiers(); | |
962 | ||
963 | printf("identifiers entries %i\n", identifiers->GetEntries()); | |
964 | ||
965 | TIter nextIdentifier(identifiers); | |
966 | ||
967 | TObjString* sid(0x0); | |
968 | ||
969 | while ( ( sid = static_cast<TObjString*>(nextIdentifier()) ) ) | |
970 | { | |
971 | Bool_t identifierPrinted(kFALSE); | |
972 | ||
973 | TString identifier(sid->String()); | |
974 | ||
975 | Bool_t matchPattern = kTRUE; | |
976 | for ( Int_t isel=0; isel<select->GetLast(); isel++ ) { | |
977 | if ( ! GetKey(identifier.Data(), isel, kFALSE).Contains(TRegexp(select->At(isel)->GetName(),kTRUE)) ) { | |
978 | matchPattern = kFALSE; | |
979 | break; | |
980 | } | |
981 | } | |
982 | if ( ! matchPattern ) continue; | |
983 | ||
d440e2c5 | 984 | if ( sreObjectName == "*" && !classPattern) |
985 | { | |
ac4edd2e | 986 | identifierPrinted = kTRUE; |
987 | cout << identifier.Data() << endl; | |
988 | } | |
989 | ||
d440e2c5 | 990 | THashList * list = static_cast<THashList*>(Map()->GetValue(sid->String().Data())); |
991 | ||
ac4edd2e | 992 | TObjArray names; |
993 | names.SetOwner(kTRUE); | |
994 | TIter nextUnsortedObj(list); | |
995 | TObject* obj; | |
996 | while ( ( obj = nextUnsortedObj() ) ) | |
997 | { | |
d440e2c5 | 998 | TString cname(obj->ClassName()); |
999 | if ( classPattern && !cname.Contains((*classPattern)) ) | |
1000 | { | |
1001 | continue; | |
1002 | } | |
ac4edd2e | 1003 | names.Add(new TObjString(obj->GetName())); |
1004 | } | |
1005 | names.Sort(); | |
1006 | TIter nextObjName(&names); | |
1007 | TObjString* oname; | |
1008 | while ( ( oname = static_cast<TObjString*>(nextObjName()) ) ) | |
1009 | { | |
1010 | TString objName(oname->String()); | |
1011 | if (objName.Contains(reObjectName) ) | |
1012 | { | |
1013 | obj = list->FindObject(objName.Data()); | |
1014 | if ( IsEmptyObject(obj) && ! fMustShowEmptyObject ) continue; | |
1b331634 | 1015 | |
ac4edd2e | 1016 | if (!identifierPrinted) |
1017 | { | |
1018 | cout << identifier.Data() << endl; | |
1019 | identifierPrinted = kTRUE; | |
1020 | } | |
1b331634 | 1021 | |
1022 | TString extra; | |
1023 | TString warning(" "); | |
1024 | ||
1025 | if ( obj->IsA()->InheritsFrom(TH1::Class()) ) | |
1026 | { | |
1027 | ||
ac4edd2e | 1028 | TH1* histo = static_cast<TH1*> (obj); |
1b331634 | 1029 | extra.Form("%s | Entries=%d Sum=%g",histo->GetTitle(),Int_t(histo->GetEntries()),histo->GetSumOfWeights()); |
1030 | } | |
1031 | else if ( obj->IsA()->InheritsFrom(TGraph::Class()) ) | |
1032 | { | |
1033 | TGraph* graph = static_cast<TGraph*> (obj); | |
1034 | if ( ! TMath::Finite(graph->GetMean(2) ) ) | |
1035 | { | |
1036 | warning = " ! "; | |
1037 | } | |
1038 | extra.Form("%s | Npts=%d Mean=%g RMS=%g",graph->GetTitle(),graph->GetN(), | |
1039 | graph->GetMean(2),graph->GetRMS(2)); | |
1040 | ||
1041 | } | |
1042 | ||
1043 | std::cout << Form(" (%s) %s %s", obj->ClassName(), | |
1044 | warning.Data(), | |
1045 | obj->GetName()); | |
1046 | ||
1047 | if ( extra.Length() ) | |
1048 | { | |
1049 | std::cout << " | " << extra.Data(); | |
ac4edd2e | 1050 | } |
1b331634 | 1051 | std::cout << std::endl; |
ac4edd2e | 1052 | } |
1053 | } | |
1054 | if (!identifierPrinted && sreObjectName=="-" ) | |
1055 | { | |
1056 | // to handle the case where we used objectName="-" to disable showing the objectNames, | |
1057 | // but we still want to see the matching keys maybe... | |
1058 | cout << identifier.Data() << endl; | |
1059 | } | |
1060 | } | |
1061 | ||
1062 | delete select; | |
1063 | ||
1064 | delete identifiers; | |
1065 | } | |
1066 | ||
1067 | //_____________________________________________________________________________ | |
1068 | void | |
1069 | AliMergeableCollection::PrintMessages(const char* prefix) const | |
1070 | { | |
1071 | /// Print pending messages | |
1072 | ||
1073 | std::map<std::string,int>::const_iterator it; | |
1074 | ||
1075 | for ( it = fMessages.begin(); it != fMessages.end(); ++it ) | |
1076 | { | |
1077 | cout << Form("%s : message %s appeared %5d times",prefix,it->first.c_str(),it->second) << endl; | |
1078 | } | |
1079 | } | |
1080 | ||
1081 | ||
1082 | //_____________________________________________________________________________ | |
1083 | UInt_t | |
1084 | AliMergeableCollection::EstimateSize(Bool_t show) const | |
1085 | { | |
1086 | /// Estimate the memory (in kilobytes) used by some objects | |
1087 | ||
1088 | // For TH1: | |
1089 | // sizeof(TH1) + (nbins+2)*(nbytes_per_bin) +name+title_sizes | |
1090 | // if you have errors add (nbins+2)*8 | |
1091 | ||
1092 | TIter next(CreateIterator()); | |
1093 | ||
1094 | TObject* obj; | |
1095 | UInt_t size(0); | |
1096 | ||
1097 | while ( ( obj = next() ) ) | |
1098 | { | |
1099 | UInt_t thissize=0; | |
1100 | if ( obj->IsA()->InheritsFrom(TH1::Class()) ) { | |
1101 | TH1* histo = static_cast<TH1*> (obj); | |
1102 | Int_t nbins = (histo->GetNbinsX()+2); | |
1103 | ||
1104 | if (histo->GetNbinsY()>1) | |
1105 | { | |
1106 | nbins *= (histo->GetNbinsY()+2); | |
1107 | } | |
1108 | ||
1109 | if (histo->GetNbinsZ()>1) | |
1110 | { | |
1111 | nbins *= (histo->GetNbinsZ()+2); | |
1112 | } | |
1113 | ||
1114 | Bool_t hasErrors = ( histo->GetSumw2N() > 0 ); | |
1115 | ||
1116 | TString cname(histo->ClassName()); | |
1117 | ||
1118 | Int_t nbytesPerBin(0); | |
1119 | ||
1120 | if (cname.Contains(TRegexp("C$")) ) nbytesPerBin = sizeof(Char_t); | |
1121 | if (cname.Contains(TRegexp("S$")) ) nbytesPerBin = sizeof(Short_t); | |
1122 | if (cname.Contains(TRegexp("I$")) ) nbytesPerBin = sizeof(Int_t); | |
1123 | if (cname.Contains(TRegexp("F$")) ) nbytesPerBin = sizeof(Float_t); | |
1124 | if (cname.Contains(TRegexp("D$")) ) nbytesPerBin = sizeof(Double_t); | |
1125 | ||
1126 | if (!nbytesPerBin) | |
1127 | { | |
1128 | AliError(Form("Could not get the number of bytes per bin for histo %s of class %s. Thus the size estimate will be wrong !", | |
1129 | histo->GetName(),histo->ClassName())); | |
1130 | continue; | |
1131 | } | |
1132 | ||
1133 | thissize = sizeof(histo) + nbins*(nbytesPerBin) + strlen(histo->GetName()) | |
1134 | + strlen(histo->GetTitle()); | |
1135 | ||
1136 | if ( hasErrors) thissize += nbins*8; | |
1137 | } | |
95760506 | 1138 | else if ( obj->IsA()->InheritsFrom(THnSparse::Class()) ) { |
1139 | THnSparse* sparse = static_cast<THnSparse*> (obj); | |
1140 | thissize = sizeof(Float_t) * (UInt_t)sparse->GetNbins(); | |
1141 | } | |
1142 | // else if ( obj->IsA() == AliCFGridSparse::Class() ) { | |
1143 | // AliCFGridSparse* sparse = static_cast<AliCFGridSparse*> (obj); | |
1144 | // thissize = sizeof(Float_t) * (UInt_t)sparse->GetNFilledBins(); | |
1145 | // } | |
1146 | // else if ( obj->IsA() == AliCFContainer::Class() ) { | |
1147 | // AliCFContainer* cont = static_cast<AliCFContainer*> (obj); | |
1148 | // for ( Int_t istep=0; istep<cont->GetNStep(); istep++ ) { | |
1149 | // thissize += sizeof(Float_t) * (UInt_t)cont->GetGrid(istep)->GetNFilledBins(); | |
1150 | // } | |
1151 | // } | |
ac4edd2e | 1152 | else { |
1153 | AliWarning(Form("Cannot estimate size of %s\n", obj->ClassName())); | |
1154 | continue; | |
1155 | } | |
1156 | ||
1157 | size += thissize; | |
1158 | ||
1159 | if ( show ) | |
1160 | { | |
1161 | AliInfo(Form("Size of %30s is %20d bytes",obj->GetName(),thissize)); | |
1162 | } | |
1163 | } // loop on objects | |
1164 | ||
1165 | return size; | |
1166 | } | |
1167 | ||
1b331634 | 1168 | //_____________________________________________________________________________ |
1169 | Int_t AliMergeableCollection::Prune(const char* identifier) | |
1170 | { | |
1171 | // Delete all objects which match the beginning of the identifier | |
1172 | // returns the number of entries removed from the Map() | |
1173 | // (not to be confused with the number of leaf objects removed) | |
1174 | // | |
1175 | ||
1176 | TIter next(Map()); | |
1177 | TObjString* key; | |
1178 | Int_t ndeleted(0); | |
1179 | ||
1180 | while ( ( key = static_cast<TObjString*>(next())) ) | |
1181 | { | |
1182 | if (key->String().BeginsWith(identifier)) | |
1183 | { | |
1184 | Bool_t ok = Map()->DeleteEntry(key); | |
1185 | if (ok) ++ndeleted; | |
1186 | } | |
1187 | } | |
1188 | ||
1189 | return ndeleted; | |
1190 | } | |
1191 | ||
ac4edd2e | 1192 | //_____________________________________________________________________________ |
1193 | void AliMergeableCollection::PruneEmptyObjects() | |
1194 | { | |
1195 | /// Delete the empty objects | |
1196 | /// (Implemented for TH1 only) | |
1197 | TIter next(Map()); | |
1198 | TObjString* key; | |
1199 | ||
1200 | TList toBeRemoved; | |
1201 | toBeRemoved.SetOwner(kTRUE); | |
1202 | ||
1203 | while ( ( key = static_cast<TObjString*>(next()) ) ) | |
1204 | { | |
1205 | TString identifier(key->String()); | |
1206 | THashList* hlist = static_cast<THashList*>(Map()->GetValue(identifier.Data())); | |
1207 | TIter nextObject(hlist); | |
1208 | TObject* obj; | |
1209 | while ( ( obj = nextObject() ) ) | |
1210 | { | |
1211 | if ( IsEmptyObject(obj) ) toBeRemoved.Add(new TObjString(Form("%s%s",identifier.Data(),obj->GetName()))); | |
1212 | } | |
1213 | } | |
1214 | ||
1215 | TIter nextTBR(&toBeRemoved); | |
1216 | while ( ( key = static_cast<TObjString*>(nextTBR()) ) ) | |
1217 | { | |
1218 | Remove(key->GetString().Data()); | |
1219 | AliDebug(2,Form("Removing %s", key->GetString().Data())); | |
1220 | } | |
1221 | } | |
1222 | ||
1223 | //_____________________________________________________________________________ | |
1224 | AliMergeableCollection* | |
1225 | AliMergeableCollection::Project(const char* identifier) const | |
1226 | { | |
1227 | /// To be implemented : would create a new collection starting at /key1/key2/... | |
1228 | ||
1229 | if (!fMap) return 0x0; | |
1230 | ||
1231 | AliMergeableCollection* mergCol = new AliMergeableCollection(Form("%s %s",GetName(),identifier), | |
1232 | GetTitle()); | |
1233 | ||
1234 | TIter next(Map()); | |
1235 | TObjString* str; | |
1236 | ||
1237 | while ( ( str = static_cast<TObjString*>(next()) ) ) | |
1238 | { | |
1239 | TString currIdentifier = str->String(); | |
1240 | if ( ! currIdentifier.Contains(identifier) ) continue; | |
1241 | ||
1242 | THashList* list = static_cast<THashList*>(Map()->GetValue(identifier)); | |
1243 | ||
1244 | TIter nextObj(list); | |
1245 | TObject* obj; | |
1246 | ||
1247 | while ( ( obj = nextObj()) ) | |
1248 | { | |
1249 | TObject* clone = obj->Clone(); | |
1250 | ||
1251 | TString newkey(currIdentifier.Data()); | |
1252 | newkey.ReplaceAll(identifier,""); | |
1253 | ||
1254 | if (newkey=="/") newkey=""; | |
1255 | ||
1256 | mergCol->InternalAdopt(newkey.Data(),clone); | |
1257 | } | |
1258 | } | |
1259 | ||
1260 | return mergCol; | |
1261 | } | |
1262 | ||
1263 | //_____________________________________________________________________________ | |
1264 | TObject* | |
1265 | AliMergeableCollection::Remove(const char* fullIdentifier) | |
1266 | { | |
1267 | /// | |
1268 | /// Remove a given object (given its fullIdentifier=/key1/key2/.../objectName) | |
1269 | /// | |
1270 | /// Note that we do *not* remove the /key1/key2/... entry even if there's no | |
1271 | /// more object for this triplet. | |
1272 | /// | |
1273 | /// Not very efficient. Could be improved ? | |
1274 | /// | |
1275 | ||
1276 | TString identifier = GetIdentifier(fullIdentifier); | |
1277 | ||
1278 | THashList* hlist = dynamic_cast<THashList*>(Map()->GetValue(identifier.Data())); | |
1279 | ||
1280 | if (!hlist) | |
1281 | { | |
1282 | AliWarning(Form("Could not get hlist for key=%s",identifier.Data())); | |
1283 | return 0x0; | |
1284 | } | |
1285 | ||
1286 | TObject* obj = GetObject(fullIdentifier); | |
1287 | if (!obj) | |
1288 | { | |
1289 | AliError(Form("Could not find object %s",fullIdentifier)); | |
1290 | return 0x0; | |
1291 | } | |
1292 | ||
1293 | TObject* rmObj = hlist->Remove(obj); | |
1294 | if (!rmObj) | |
1295 | { | |
1296 | AliError("Remove failed"); | |
1297 | return 0x0; | |
1298 | } | |
1299 | ||
1300 | return rmObj; | |
1301 | } | |
1302 | ||
d440e2c5 | 1303 | //_____________________________________________________________________________ |
1304 | Int_t AliMergeableCollection::RemoveByType(const char* typeName) | |
1305 | { | |
1306 | /// Remove all the objects in this collection that are of a given type | |
1307 | TIter nextIdentifier(Map()); | |
1308 | TObjString* identifier; | |
1309 | Int_t nremoved(0); | |
1310 | ||
1311 | while ( (identifier = static_cast<TObjString*>(nextIdentifier()) ) ) | |
1312 | { | |
1313 | THashList* list = static_cast<THashList*>(Map()->GetValue(identifier->String())); | |
1314 | TIter next(list); | |
1315 | TObject* o; | |
1316 | ||
1317 | while ( ( o = next() ) ) | |
1318 | { | |
1319 | if ( strcmp(o->ClassName(),typeName) == 0 ) | |
1320 | { | |
1321 | list->Remove(o); | |
1322 | ++nremoved; | |
1323 | } | |
1324 | } | |
1325 | } | |
1326 | return nremoved; | |
1327 | } | |
1328 | ||
1329 | ||
ac4edd2e | 1330 | //_____________________________________________________________________________ |
1331 | TObjArray* | |
1332 | AliMergeableCollection::SortAllIdentifiers() const | |
1333 | { | |
1334 | /// Sort our internal identifiers. Returned array must be deleted. | |
1335 | TObjArray* identifiers = new TObjArray; | |
1336 | identifiers->SetOwner(kFALSE); | |
1337 | TIter next(Map()); | |
1338 | TObjString* sid; | |
1339 | ||
1340 | while ( ( sid = static_cast<TObjString*>(next()) ) ) | |
1341 | { | |
1342 | if ( !identifiers->FindObject(sid->String().Data()) ) | |
1343 | { | |
1344 | identifiers->Add(sid); | |
1345 | } | |
1346 | } | |
1347 | identifiers->Sort(); | |
1348 | return identifiers; | |
1349 | } | |
1350 | ||
1351 | ||
1352 | /////////////////////////////////////////////////////////////////////////////// | |
1353 | // | |
1354 | // AliMergeableCollectionIterator | |
1355 | // | |
1356 | /////////////////////////////////////////////////////////////////////////////// | |
1357 | ||
1358 | class AliMergeableCollectionIterator; | |
1359 | ||
1360 | //_____________________________________________________________________________ | |
1361 | AliMergeableCollectionIterator::AliMergeableCollectionIterator(const AliMergeableCollection* mcol, Bool_t dir) | |
1362 | : fkMergeableCollection(mcol), fMapIterator(0x0), fHashListIterator(0x0), fDirection(dir) | |
1363 | { | |
1364 | /// Default ctor | |
1365 | } | |
1366 | ||
1367 | //_____________________________________________________________________________ | |
1368 | AliMergeableCollectionIterator& | |
1369 | AliMergeableCollectionIterator::operator=(const TIterator&) | |
1370 | { | |
1371 | /// Overriden operator= (imposed by Root's declaration of TIterator ?) | |
1372 | Fatal("TIterator::operator=","Not implementeable"); // because there's no clone in TIterator :-( | |
1373 | return *this; | |
1374 | } | |
1375 | ||
1376 | //_____________________________________________________________________________ | |
1377 | AliMergeableCollectionIterator::~AliMergeableCollectionIterator() | |
1378 | { | |
1379 | /// dtor | |
1380 | Reset(); | |
1381 | } | |
1382 | ||
1383 | //_____________________________________________________________________________ | |
1384 | TObject* AliMergeableCollectionIterator::Next() | |
1385 | { | |
1386 | /// Advance to next object in the collection | |
1387 | ||
1388 | if (!fHashListIterator) | |
1389 | { | |
1390 | if ( !fMapIterator ) | |
1391 | { | |
1392 | fMapIterator = fkMergeableCollection->fMap->MakeIterator(fDirection); | |
1393 | } | |
1394 | TObjString* key = static_cast<TObjString*>(fMapIterator->Next()); | |
1395 | if (!key) | |
1396 | { | |
1397 | // we are done | |
1398 | return 0x0; | |
1399 | } | |
1400 | THashList* list = static_cast<THashList*>(fkMergeableCollection->Map()->GetValue(key->String().Data())); | |
1401 | if (!list) return 0x0; | |
1402 | fHashListIterator = list->MakeIterator(fDirection); | |
1403 | } | |
1404 | ||
1405 | TObject* obj = fHashListIterator->Next(); | |
1406 | ||
1407 | if (!obj) | |
1408 | { | |
1409 | delete fHashListIterator; | |
1410 | fHashListIterator = 0x0; | |
1411 | return Next(); | |
1412 | } | |
1413 | ||
1414 | return obj; | |
1415 | } | |
1416 | ||
1417 | //_____________________________________________________________________________ | |
1418 | void AliMergeableCollectionIterator::Reset() | |
1419 | { | |
1420 | /// Reset the iterator | |
1421 | delete fHashListIterator; | |
1422 | delete fMapIterator; | |
1423 | } |