ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/UserCode/MitAna/TAM/src/TAMOutput.cxx
Revision: 1.2
Committed: Sat Sep 27 06:03:36 2008 UTC (16 years, 7 months ago) by loizides
Content type: text/plain
Branch: MAIN
CVS Tags: Mit_006, Mit_005, Mit_004
Changes since 1.1: +3 -2 lines
Log Message:
Rehash in THashTables.

File Contents

# User Rev Content
1 loizides 1.1 //
2 loizides 1.2 // $Id: TAMOutput.cxx,v 1.1 2008/05/27 19:13:21 loizides Exp $
3 loizides 1.1 //
4    
5     #include "TAMOutput.h"
6    
7    
8     #ifndef G__API_H
9     #include "Api.h"
10     #endif
11     #ifndef ROOT_Riostream
12     #include "Riostream.h"
13     #endif
14     #ifndef ROOT_RVersion
15     #include "RVersion.h"
16     #endif
17     #ifndef ROOT_TIterator
18     #include "TIterator.h"
19     #endif
20     #ifndef ROOT_TObjArray
21     #include "TObjArray.h"
22     #endif
23     #ifndef ROOT_TError
24     #include "TError.h"
25     #endif
26     #ifndef ROOT_TH1
27     #include "TH1.h"
28     #endif
29     #ifndef ROOT_TROOT
30     #include "TROOT.h"
31     #endif
32     #ifndef ROOT_TDataMember
33     #include "TDataMember.h"
34     #endif
35     #ifndef TAM_TAModule
36     #include "TAModule.h"
37     #endif
38    
39    
40     //////////////////////////////////////////////////////////////////////////
41     // //
42     // TAMOutput //
43     // //
44     // Stores the output objects of a module for use with the Proof //
45     // facility. This object is itself a list of all sub modules output //
46     // objects, so that whatever TAModule hierarchy exists is duplicated in //
47     // the TAMOutput hierarchy. Thus, only the tree of TAMOutput objects //
48     // needs to be streamed in to the master from the worker computers when //
49     // merging output objects in a Proof analsys, and not the complete //
50     // TAModule objects themselves. This is useful since an TAModule object //
51     // is in principal arbitrarily large, and only the list of output //
52     // objects needs to be merged. //
53     // //
54     // This class provides the functionality to merge the list of output //
55     // objects correctly throughout the hierarchy of TAMOutput objects. //
56     // //
57     // The existence of this class is hidden to classes inheritting from //
58     // TAModule. Such end-user modules need only add the desired output //
59     // objects (such as histograms) to their output list by calling //
60     // TAModule::AddOutput(TObject*&). //
61     // //
62     // Author : Corey Reed 07/20/2004 //
63     // //
64     //////////////////////////////////////////////////////////////////////////
65    
66     ClassImp(TAMOutput)
67     ClassImp(TAMOutput::TAMModInspector)
68     ClassImp(TAMOutput::TAMModInspector::TAMModMember)
69    
70    
71     #if ROOT_VERSION_CODE < ROOT_VERSION(5,11,3)
72     #define R__ASSERT(e) \
73     if (!(e)) Fatal("", kAssertMsg, _QUOTE_(e), __LINE__, __FILE__)
74     #endif
75    
76    
77     //______________________________________________________________________________
78 loizides 1.2 TAMOutput::TAMModInspector::TAMModInspector() :
79     fOutputMembers(TCollection::kInitHashTableCapacity, 1)
80 loizides 1.1 {
81     // Default constructor.
82    
83     fOutputMembers.SetOwner(kTRUE);
84     }
85    
86    
87     //______________________________________________________________________________
88     TAMOutput::TAMModInspector::~TAMModInspector()
89     {
90     // Destructor.
91     }
92    
93    
94     //______________________________________________________________________________
95     void TAMOutput::TAMModInspector::AddOutput(TObject* obj, const void* adr)
96     {
97     // Set the title of the TAMModMember for this object to the name of the obj.
98    
99     TAMModMember* mem = FindModMemberWithAddr(adr);
100     if (mem!=0) {
101     mem->SetName(obj->GetName());
102     } // else output object is not (pointed to by) a member of the module
103     }
104    
105    
106     //______________________________________________________________________________
107     void TAMOutput::TAMModInspector::Inspect(TClass* cl, const Char_t* parent,
108     const Char_t* name, const void* addr)
109     {
110     // Set the address of the mod member to addr.
111     // If no mod member yet exists for this member, make it (but with no name).
112    
113     if (cl->InheritsFrom(TAModule::Class())) {
114     TAMModMember* mem = FindModMemberWithMemberName(name);
115     if (mem==0) {
116     if ( (cl!=0) && (name!=0) && (addr!=0) ) {
117     TString fullname(parent);
118     fullname.Append(name);
119     fOutputMembers.Add(new TAMModMember(0, fullname.Data(),
120     const_cast<void*>(addr), cl));
121     } else {
122     ::Error("TAMOutput::TAMModInspector::Inspect",
123     "Can not store TAMModMember with class at %p, "
124     "name=%s, addr=%p",
125     static_cast<void*>(cl),
126     name, static_cast<const void*>(addr));
127     }
128     } else {
129     mem->fAddr = const_cast<void*>(addr);
130     }
131     } // else don't bother; it can't point to an output object
132     }
133    
134    
135     //______________________________________________________________________________
136     void TAMOutput::TAMModInspector::RemoveOutput(TObject* obj)
137     {
138     // Remove the TAMModMember for this object.
139    
140     TAMModMember* mem = dynamic_cast<TAMModMember*>(
141     fOutputMembers.FindObject(obj->GetName()));
142     if (mem!=0) {
143     fOutputMembers.Remove(mem);
144     }
145     }
146    
147    
148     //______________________________________________________________________________
149     TAMOutput::TAMModInspector::TAMModMember*
150     TAMOutput::TAMModInspector::FindModMemberWithAddr(const void* addr)
151     {
152     // Find the mod member that has the specified address
153    
154     TIter nextmem(fOutputMembers.MakeIterator());
155     TAMModMember* mem=0;
156     while ( (mem = dynamic_cast<TAMModMember*>(nextmem())) ) {
157     if (mem->fAddr == addr) return mem;
158     }
159     return 0;
160     }
161    
162    
163     //______________________________________________________________________________
164     TAMOutput::TAMModInspector::TAMModMember*
165     TAMOutput::TAMModInspector::FindModMemberWithMemberName(const Char_t* mn)
166     {
167     // Find the mod member that has the specified member name.
168    
169     TIter nextmem(fOutputMembers.MakeIterator());
170     TString memname(mn);
171     TAMModMember* mem=0;
172     while ( (mem = dynamic_cast<TAMModMember*>(nextmem())) ) {
173     if (memname.CompareTo(mem->GetTitle())==0) return mem;
174     }
175     return 0;
176     }
177    
178    
179     //______________________________________________________________________________
180     void TAMOutput::TAMModInspector::SetMemberAddrFor(TObject* obj,
181     const UInt_t verbose)
182     {
183     // Find the specified module's member for the specified object
184     // and make the member point to the specified object.
185     // If the member is not a pointer, does nothing.
186    
187     if (obj!=0) {
188     TAMModMember* mem = dynamic_cast<TAMModMember*>(
189     fOutputMembers.FindObject(obj->GetName()));
190     if (mem!=0) {
191     // it's silly, but mem->fMClass comes from IsA(), which does
192     // not "load" the class, so the data member list is empty.
193     TClass* cl = TClass::GetClass(mem->fMClass->GetName());
194     if (cl!=0) {
195     // test if the module's member is actually a pointer to a class
196     // (as opposed to an array of pointers,
197     // an instance of the class, etc.)
198     TDataMember* dm = cl->GetDataMember(mem->GetTitle());
199     if (dm!=0) {
200     TString memberString(dm->GetTypeName());
201     memberString += "*";
202     if (memberString.CompareTo(dm->GetFullTypeName())==0) {
203     void*& modobj = *(static_cast<void**>(mem->fAddr));
204     if (modobj!=obj) {
205     if (modobj!=0) {
206     ::Warning("TAMOutput::TAMModInspector::"
207     "SetMemberAddrFor",
208     "Module pointer [%s] is pointing to "
209     "non-zero address "
210     "%p. Setting it to point to "
211     "output object [%s] at %p. "
212     "Possible memory leak/stomp.",
213     mem->GetTitle(),
214     static_cast<void*>(modobj),
215     obj->GetName(),
216     static_cast<void*>(obj));
217     }
218     modobj = obj;
219     } // else it's already pointing to the right place
220     } else {
221     // not a pointer to a class
222     if (verbose>9) {
223     ::Warning("TAMOutput::TAMModInspector::"
224     "SetMemberAddrFor",
225     "Module member [%s] is of type "
226     "[%s], not a pointer "
227     "to a class (inheriting from TObject). "
228     "Could not "
229     "automatically make this member "
230     "point to [%s] "
231     "from the output list.\n"
232     "Set verbosity below 10 to "
233     "remove this message.",
234     mem->GetTitle(), dm->GetFullTypeName(),
235     obj->GetName());
236     }
237     }
238     } else {
239     ::Error("TAMOutput::TAMModInspector::SetMemberAddrFor",
240     "Could not get data member (%p) [%s] of module [%s]. "
241     "Could not set member address for object [%s].",
242     static_cast<void*>(dm),
243     mem->GetTitle(), mem->fMClass->GetName(),
244     obj->GetName());
245     }
246     } else {
247     ::Error("TAMOutput::TAMModInspector::SetMemberAddrFor",
248     "No class info for the module. "
249     "Can not set member address for [%s].",
250     obj->GetName());
251     }
252     } // else output object is not (pointed to by) a member of the module
253     } else {
254     ::Error("TAMOutput::TAMModInspector::SetMemberAddrFor",
255     "Can not set member address for null object.");
256     }
257     }
258    
259    
260     //______________________________________________________________________________
261     void TAMOutput::TAMModInspector::Streamer(TBuffer &R__b)
262     {
263     // Stream an object of class TAMOutput::TAMModInspector.
264    
265     //This works around a msvc bug and should be harmless on other platforms
266     typedef TAMOutput::TAMModInspector thisClass;
267     UInt_t R__s, R__c;
268     if (R__b.IsReading()) {
269     Version_t R__v = R__b.ReadVersion(&R__s, &R__c); if (R__v) { }
270     fOutputMembers.Streamer(R__b);
271     R__b.CheckByteCount(R__s, R__c, thisClass::IsA());
272     } else {
273     R__c = R__b.WriteVersion(thisClass::IsA(), kTRUE);
274     fOutputMembers.Streamer(R__b);
275     R__b.SetByteCount(R__c, kTRUE);
276     }
277     }
278    
279    
280     //______________________________________________________________________________
281     TAMOutput::TAMOutput() :
282     fMod(0)
283     {
284     // Default constructor.
285    
286     SetOwner(kTRUE);
287     fOutput.SetOwner(kFALSE);
288     }
289    
290    
291     //______________________________________________________________________________
292     TAMOutput::TAMOutput(TAModule* mod) :
293     fMod(mod)
294     {
295     // Normal constructor.
296    
297     SetOwner(kTRUE);
298     fOutput.SetOwner(kFALSE);
299     fCurOutput.SetOwner(kFALSE);
300     if (mod!=0) SetName(mod->GetName());
301     }
302    
303    
304     //______________________________________________________________________________
305     TAMOutput::~TAMOutput()
306     {
307     // Destructor.
308     }
309    
310    
311     //______________________________________________________________________________
312     void TAMOutput::Browse(TBrowser* b)
313     {
314     // Browse the output of this module
315    
316     fOutput.Browse(b);
317     TList::Browse(b);
318     }
319    
320    
321     //______________________________________________________________________________
322     void TAMOutput::CallMerge(TObject* obj, TList& list)
323     {
324     // Uses CINT to call merge on 'obj' given a list of all the
325     // objects from the worker computers that correspond to 'obj'.
326     // If no merge function exists for 'obj', it simply adds all the
327     // objects in list to the output list of this module.
328     // To be called only by MergeOutput(TCollection*)
329    
330     R__ASSERT(obj);
331    
332     Long_t offset=0;
333     G__ClassInfo ci(obj->ClassName());
334     G__CallFunc cf;
335    
336     if (ci.IsValid()) {
337     cf.SetFuncProto(&ci, "Merge", "TCollection*", &offset);
338     }
339     if (cf.IsValid()) {
340     cf.SetArg((Long_t)&list);
341     cf.Exec(obj);
342     } else {
343     // No Merge interface, return individual objects
344     TObject* obj=0;
345     while ( (obj = list.First()) ) {
346     fCurOutput.Add(obj);
347     list.Remove(obj);
348     }
349     }
350     }
351    
352    
353     //______________________________________________________________________________
354     void TAMOutput::CheckHistDir(TObject* obj)
355     {
356     // If obj is a histogram, set directory to null.
357    
358     if (obj->InheritsFrom(TH1::Class())) {
359     TH1* hist = dynamic_cast<TH1*>(obj);
360     if (hist!=0) hist->SetDirectory(0);
361     }
362     }
363    
364    
365     //______________________________________________________________________________
366     void TAMOutput::DeleteIterators(vector<TIterator*>& iters) {
367     // Deletes each iterator in the vector.
368    
369     vector<TIterator*>::const_iterator send = iters.end();
370     for (vector<TIterator*>::iterator siter = iters.begin();
371     siter!=send; siter++) {
372     delete (*siter);
373     }
374     }
375    
376    
377     //______________________________________________________________________________
378     TAMOutput* TAMOutput::FindModOutput(const TAModule* mod)
379     {
380     // Finds the TAMOutput object associated with the specified TAModule
381     // (either being this one, or one of its sub modules).
382     // Returns 0 if no such TAMOutput object is found.
383    
384     if (fMod==mod) {
385     return this;
386     } else {
387     TIter nextModOutput(MakeIterator());
388     TAMOutput* out=0, * tout=0;
389     while ( (out = dynamic_cast<TAMOutput*>(nextModOutput())) ) {
390     tout = out->FindModOutput(mod);
391     if (tout!=0) return tout;
392     }
393     }
394     return 0;
395     }
396    
397    
398     //______________________________________________________________________________
399     TAMOutput* TAMOutput::FindModOutput(const Char_t* name)
400     {
401     // Finds the (first) TAMOutput object with the specified name
402     // (either being this one, or one of its sub modules)
403     // Returns 0 if no such TAMOutput object is found.
404     TString nm(name);
405     if (nm.CompareTo(GetName())==0) {
406     return this;
407     } else {
408     TIter nextModOutput(MakeIterator());
409     TAMOutput* out=0, * tout=0;
410     while ( (out = dynamic_cast<TAMOutput*>(nextModOutput())) ) {
411     tout = out->FindModOutput(name);
412     if (tout!=0) return tout;
413     }
414     }
415     return 0;
416     }
417    
418    
419     //______________________________________________________________________________
420     TObject* TAMOutput::FindOutput(const Char_t* obj)
421     {
422     // Finds the object with the specified name in the list of output objects
423     // of this module.
424     // First check the saved output, then check the output for this current
425     // processing.
426    
427     TObject* fobj = fOutput.FindObject(obj);
428     if (fobj==0) {
429     fobj = fCurOutput.FindObject(obj);
430     }
431     return fobj;
432     }
433    
434    
435     //______________________________________________________________________________
436     TObject* TAMOutput::FindOutput(const TObject* obj)
437     {
438     // Finds the specified object in the list of output objects of this module.
439     // First check the saved output, then check the output for this current
440     // processing.
441    
442     TObject* fobj = fOutput.FindObject(obj);
443     if (fobj==0) {
444     fobj = fCurOutput.FindObject(obj);
445     }
446     return fobj;
447    
448     }
449    
450    
451     //______________________________________________________________________________
452     TObject* TAMOutput::FindOutput(const Char_t* module, const Char_t* obj) {
453     // Finds the specified object from the output of the specified module
454     // Note: "module" must be either this module, or a submodule of this module
455     // First check the saved output, then check the output for this current
456     // processing.
457    
458     TAMOutput* outmod = FindModOutput(module);
459     if (outmod!=0) {
460     TObject* outp = outmod->FindOutput(obj);
461     if (outp==0) {
462     Warning("FindOutput",
463     "Could not find output named [%s] in module [%s].",
464     obj, outmod->GetName());
465     }
466     return outp;
467     } else {
468     Warning("FindOutput","Could not find (sub)module with name [%s].",
469     module);
470     }
471     return 0;
472     }
473    
474    
475     //______________________________________________________________________________
476     void TAMOutput::ls(Option_t* option) const
477     {
478     // List the output objects inside this module and its submodules.
479    
480     TROOT::IndentLevel();
481     cout << "Output of " << GetName() << ":" << endl;
482    
483     fOutput.ls(option);
484    
485     TROOT::IncreaseDirLevel();
486     TList::ls(option);
487     TROOT::DecreaseDirLevel();
488     }
489    
490    
491     //______________________________________________________________________________
492     void TAMOutput::Merge(TCollection* list)
493     {
494     // Called by Proof after SlaveTerminate() and before Terminate()
495     // to merge the output objects from each worker ("slave") computer.
496     // First merge the actual output objects from this module, then
497     // recursively proceed through the sub modules to merge their objects.
498    
499     // merge this module's output objects
500     MergeOutput(list);
501    
502     // then merge its sub modules' objects:
503     if (!IsEmpty()) { // (if we have any sub modules)
504     TAMOutput* out=0, * tout=0;
505     // for each slave, get an iterator over sub modules
506     // can't use any TCollection since TIterators are not TObjects
507     vector<TIterator*> slaveIters;
508     TIter nextSlave(list);
509     while ( (tout = dynamic_cast<TAMOutput*>(nextSlave())) ) {
510     slaveIters.push_back(tout->MakeIterator());
511     }
512    
513     // loop over sub modules
514     TIter nextModOutput(MakeIterator());
515     while ( (out = dynamic_cast<TAMOutput*>(nextModOutput())) ) {
516     // make a list of sub modules from each slave
517     TObjArray subList(list->GetSize());
518    
519     vector<TIterator*>::const_iterator send = slaveIters.end();
520     for (vector<TIterator*>::iterator siter = slaveIters.begin();
521     siter!=send; siter++) {
522     // add the object corresponding to 'out' from each slave
523     subList.Add((*siter)->Next());
524     }
525     // merge the list of sub modules
526     out->Merge(&subList);
527     }
528    
529     // cleanup
530     DeleteIterators(slaveIters);
531     }
532    
533     }
534    
535    
536     //______________________________________________________________________________
537     void TAMOutput::MergeOutput(TCollection* list)
538     {
539     // Merges the actual output objects in fCurOutput given a list of
540     // all the TAMOutput objects from the worker computers that
541     // correspond to this one.
542     // To be called only by Merge(TCollection*)
543    
544     if (!(fCurOutput.IsEmpty())) { // (if there are any output objects)
545     TAMOutput* tout=0;
546     // for each slave, get an iterator over the fCurOutput list
547     // can't use any TCollection since TIterators are not TObjects
548     vector<TIterator*> slaveIters;
549     TIter nextSlave(list);
550     while ( (tout = dynamic_cast<TAMOutput*>(nextSlave())) ) {
551     slaveIters.push_back(tout->GetCurOutputList()->MakeIterator());
552     }
553    
554     // loop over fCurOutput
555     TIter nextOutputObj(fCurOutput.MakeIterator());
556     TObject* outObj=0;
557     while ( (outObj = nextOutputObj()) ) {
558     // make a list of 'outObj' from each slave
559     TList objsToMerge;
560    
561     vector<TIterator*>::const_iterator send = slaveIters.end();
562     for (vector<TIterator*>::iterator siter = slaveIters.begin();
563     siter!=send; siter++) {
564     // add the object corresponding to 'outObj' from each slave
565     objsToMerge.AddLast((*siter)->Next());
566     }
567     // merge 'outObj'
568     CallMerge(outObj, objsToMerge);
569     }
570    
571     // cleanup
572     DeleteIterators(slaveIters);
573     }
574    
575     }
576    
577    
578     //______________________________________________________________________________
579     void TAMOutput::NullClassFor(void* adr, const Char_t* tid) const
580     {
581     // Print warning that the class for the pointer sent to AddOutput() is not
582     // in the ROOT class dictionary.
583    
584     Error("AddOutput",
585     "(%s): Could not get class info for object at %p with typeid %s.",
586     GetName(), adr, tid);
587     }
588    
589    
590     //______________________________________________________________________________
591     void TAMOutput::NullObjInAddOutput() const
592     {
593     // Print warning that a null pointer was sent to AddOutput().
594     Error("AddOutput",
595     "(%s): Can not add null object to output.", GetName());
596     }
597    
598    
599     //______________________________________________________________________________
600     void TAMOutput::Print(Option_t *wildcard) const
601     {
602     // Print the output objects inside this module and its submodules.
603    
604     TROOT::IndentLevel();
605     cout << "Output of " << GetName() << ":" << endl;
606    
607     fOutput.Print(wildcard);
608    
609     TROOT::IncreaseDirLevel();
610     TList::Print(wildcard);
611     TROOT::DecreaseDirLevel();
612     }
613    
614    
615     //______________________________________________________________________________
616     void TAMOutput::Print(Option_t* wildcard, Option_t* option) const
617     {
618     // Print the output objects inside this module and its submodules.
619    
620     #if ROOT_VERSION_CODE > ROOT_VERSION(4,0,8)
621     cout << "Output of " << GetName() << ":" << endl;
622     fOutput.Print(wildcard,option);
623     TList::Print(wildcard,option);
624     #else
625     // backward compatible
626     Warning("Print","This version of Root does not handle wildcards.");
627     Print(option);
628     #endif
629     }
630    
631    
632     //______________________________________________________________________________
633     void TAMOutput::RemoveOutput(TObject* obj)
634     {
635     // Removes the object from the list of output objects of this module.
636    
637     fInspector.RemoveOutput(obj);
638     fOutput.Remove(obj);
639     fCurOutput.Remove(obj);
640     }
641    
642    
643     //______________________________________________________________________________
644     void TAMOutput::SetAllOutputMembers(const Bool_t setAddresses) {
645     // Recursively set the module's output members.
646     // If setAddresses is true, make them point to the output objects.
647    
648     SetOutputMembers(setAddresses);
649    
650     TIter nextout(MakeIterator());
651     TAMOutput* out=0;
652     while ( (out = dynamic_cast<TAMOutput*>(nextout())) ) {
653     out->SetAllOutputMembers(setAddresses);
654     }
655     }
656    
657    
658     //______________________________________________________________________________
659     void TAMOutput::SetOutputMembers(const Bool_t setAddresses)
660     {
661     // Det the module's output members.
662     // If setAddresses is true, make them point to the output objects.
663    
664     R__ASSERT(fMod!=0);
665    
666     // first update the addresses of the members
667     Char_t parent[kParentStrLen];
668     memset(parent, 0, kParentStrLen * sizeof(Char_t));
669     fMod->ShowMembers(fInspector, parent);
670    
671     if (setAddresses) {
672     // loop through output objects and set the corresponding members
673     TIter nextout(fCurOutput.MakeIterator());
674     TObject* obj=0;
675     while ( (obj = nextout()) ) {
676     fInspector.SetMemberAddrFor(obj, fMod->GetVerbosity());
677     }
678     }
679     }
680    
681    
682     //______________________________________________________________________________
683     void TAMOutput::StoreAllOutputObjs()
684     {
685     // Recursively set move output objects from fCutOutput to fOutput
686     // to be called after Merge, but before Terminate.
687     // To be called only by TAModule.
688    
689     StoreOutputObjs();
690    
691     TIter nextout(MakeIterator());
692     TAMOutput* out=0;
693     while ( (out = dynamic_cast<TAMOutput*>(nextout())) ) {
694     out->StoreAllOutputObjs();
695     }
696     }
697    
698    
699     //______________________________________________________________________________
700     void TAMOutput::StoreOutputObjs()
701     {
702     // Iterate over fCurOutput and move the objects to fOutput
703     // to be called after Merge, but before Terminate.
704     // To be called only by StoreAllOutputObjs.
705    
706     if (fCurOutput.IsEmpty()==kFALSE) { // (if there are any output objects)
707     // loop over fCurOutput
708     TIter nextOutputObj(fCurOutput.MakeIterator());
709     TObject* outObj=0;
710     while ( (outObj = nextOutputObj()) ) {
711     fOutput.Add(outObj);
712     }
713     fCurOutput.Clear("nodelete");
714     }
715     }
716    
717    
718     //______________________________________________________________________________
719     void TAMOutput::WarnNameDuplicate(const TObject* obj) const
720     {
721     // Print warning that the output list already contains an object with
722     // the same name.
723    
724     Warning("AddOutput",
725     "(%s): Output list already contains object with name [%s]. "
726     "Adding object at %p with duplicate name.",
727     GetName(),
728     (obj!=0) ? obj->GetName() : "",
729     static_cast<const void*>(obj));
730     }
731    
732    
733     #if ROOT_VERSION_CODE > ROOT_VERSION(4,0,8)
734     //______________________________________________________________________________
735     Int_t TAMOutput::Write(const char* name, Int_t option, Int_t bsize)
736     {
737     // For this (newer) root version, put the code in the const function.
738     // Wow this is ugly.. but it's backward compatible!
739    
740     return (static_cast<const TAMOutput*>(this))->Write(name,option,bsize);
741     }
742    
743     Int_t TAMOutput::Write(const char* name, Int_t option, Int_t bsize) const
744     #else
745     //______________________________________________________________________________
746     Int_t TAMOutput::Write(const char* name, Int_t option, Int_t bsize) const
747     {
748     // For older root, put the code in the non-const function (so TList::Write
749     // can be called).
750     // Wow this is ugly.. but it's backward compatible!
751    
752     return (const_cast<TAMOutput*>(this))->Write(name,option,bsize);
753     }
754    
755     //______________________________________________________________________________
756     Int_t TAMOutput::Write(const char* name, Int_t option, Int_t bsize)
757     #endif
758     {
759     // Write all output objects.
760     // Default behavior is to go through this module and all sub modules and
761     // write all the output objects, flattening the module hierarchy.
762     // If the 'TObject::kSingleKey' option is specified, the TAMOutput
763     // objects themselves will be written, thus preserving the module hierarchy.
764    
765     if ( (option & TObject::kSingleKey) ) {
766     // here, the TList write will work just fine since it will actually
767     // call the streamer on the module output objects
768     // (through TObject::Write)
769     return TList::Write(name, option, bsize);
770     } else {
771     // flatten the module hierarchy and dump all output objects to the file
772     Int_t nbytes = 0;
773     fOutput.Write(name, option, bsize);
774     TIter nextMod(MakeIterator());
775     TObject* obj=0;
776     while ( (obj = nextMod()) ) {
777     nbytes += obj->Write(name, option, bsize);
778     }
779     return nbytes;
780     }
781     }
782