source: trunk/MagicSoft/Mars/mbase/MParContainer.cc@ 2979

Last change on this file since 2979 was 2490, checked in by tbretz, 21 years ago
*** empty log message ***
File size: 17.8 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Bretz 12/2000 <mailto:tbretz@uni-sw.gwdg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2002
21!
22!
23\* ======================================================================== */
24
25//////////////////////////////////////////////////////////////////////////////
26// //
27// MParContainer //
28// //
29// The MParContainer class is the base class for all MARS parameter //
30// containers. At the moment it is almost the same than ROOT's TNamed. //
31// A TNamed contains the essential elements (name, title) //
32// to identify a derived object in lists like our MParList or MTaskList. //
33// The main difference is that the name and title isn't stored and read //
34// to and from root files ("//!") //
35// //
36//////////////////////////////////////////////////////////////////////////////
37#include "MParContainer.h"
38
39#include <ctype.h> // isdigit
40#include <fstream> // ofstream, AsciiWrite
41
42#include <TEnv.h> // Env::Lookup
43#include <TClass.h> // IsA
44#include <TObjArray.h> // TObjArray
45#include <TBaseClass.h> // GetClassPointer
46#include <TMethodCall.h> // TMethodCall, AsciiWrite
47#include <TDataMember.h> // TDataMember, AsciiWrite
48#include <TVirtualPad.h> // gPad
49
50#include "MLog.h"
51#include "MLogManip.h"
52
53TList *gListOfPrimitives; // forard declaration in MParContainer.h
54
55#undef DEBUG
56//#define DEBUG
57
58ClassImp(MParContainer);
59
60using namespace std;
61
62// --------------------------------------------------------------------------
63//
64// MParContainer copy ctor
65//
66MParContainer::MParContainer(const MParContainer &named)
67{
68 fName = named.fName;
69 fTitle = named.fTitle;
70
71 fLog = named.fLog;
72
73 fReadyToSave = named.fReadyToSave;
74
75 fDisplay = named.fDisplay;
76}
77
78MParContainer::~MParContainer()
79{
80#ifdef DEBUG
81 *fLog << all << "Deleting " << GetDescriptor() << endl;
82#endif
83}
84
85// --------------------------------------------------------------------------
86//
87// MParContainer assignment operator.
88//
89MParContainer& MParContainer::operator=(const MParContainer& rhs)
90{
91 if (this == &rhs)
92 return *this;
93
94 TObject::operator=(rhs);
95
96 fName = rhs.fName;
97 fTitle = rhs.fTitle;
98
99 fLog = rhs.fLog;
100 fReadyToSave = rhs.fReadyToSave;
101
102 return *this;
103}
104
105// --------------------------------------------------------------------------
106//
107// Make a clone of an object using the Streamer facility.
108// If newname is specified, this will be the name of the new object
109//
110TObject *MParContainer::Clone(const char *newname) const
111{
112
113 MParContainer *named = (MParContainer*)TObject::Clone();
114 if (newname && strlen(newname)) named->SetName(newname);
115 return named;
116}
117
118// --------------------------------------------------------------------------
119//
120// Compare two MParContainer objects. Returns 0 when equal, -1 when this is
121// smaller and +1 when bigger (like strcmp).
122//
123Int_t MParContainer::Compare(const TObject *obj) const
124{
125 if (this == obj) return 0;
126 return fName.CompareTo(obj->GetName());
127}
128
129// --------------------------------------------------------------------------
130//
131// Copy this to obj.
132//
133void MParContainer::Copy(TObject &obj)
134#if ROOT_VERSION_CODE > ROOT_VERSION(3,04,01)
135const
136#endif
137{
138 MParContainer &cont = (MParContainer&)obj;
139
140 TObject::Copy(obj);
141
142 cont.fName = fName;
143 cont.fTitle = fTitle;
144
145 cont.fLog = fLog;
146 cont.fReadyToSave = fReadyToSave;
147}
148
149// --------------------------------------------------------------------------
150//
151// Encode MParContainer into output buffer.
152//
153void MParContainer::FillBuffer(char *&buffer)
154{
155 fName.FillBuffer(buffer);
156 fTitle.FillBuffer(buffer);
157}
158
159// --------------------------------------------------------------------------
160//
161// Returns the name of the object. If the name of the object is not the
162// class name it returns the object name and in []-brackets the class name.
163//
164const char *MParContainer::GetDescriptor() const
165{
166 //
167 // Because it returns a (const char*) we cannot return a casted
168 // local TString. The pointer would - immediatly after return -
169 // point to a random memory segment, because the TString has gone.
170 //
171 return fName==ClassName() ? ClassName() : Form("%s [%s]", fName.Data(), ClassName());
172}
173
174// --------------------------------------------------------------------------
175//
176// Return a unique name for this container. It is created from
177// the container name and the unique Id. (This is mostly used
178// in the StreamPrimitive member functions)
179//
180const TString MParContainer::GetUniqueName() const
181{
182 TString ret = ToLower(fName);
183
184 if (isdigit(ret[ret.Length()-1]))
185 ret+="_";
186
187 ret+=GetUniqueID();
188
189 return ret;
190}
191
192// --------------------------------------------------------------------------
193//
194// List MParContainer name and title.
195//
196void MParContainer::ls(Option_t *) const
197{
198 TROOT::IndentLevel();
199 *fLog << all << GetDescriptor() << " " << GetTitle() << ": kCanDelete=";
200 *fLog << Int_t(TestBit(kCanDelete)) << endl;
201}
202
203// --------------------------------------------------------------------------
204//
205// Print MParContainer name and title.
206//
207void MParContainer::Print(Option_t *) const
208{
209 *fLog << all << GetDescriptor() << " " << GetTitle() << endl;
210}
211
212// --------------------------------------------------------------------------
213//
214// Change (i.e. set) the name of the MParContainer.
215// WARNING !!
216// If the object is a member of a THashTable, THashList container
217// The HashTable must be Rehashed after SetName
218// For example the list of objects in the current directory is a THashList
219//
220void MParContainer::SetName(const char *name)
221{
222 fName = name;
223 ResetBit(kIsSavedAsPrimitive);
224 if (gPad && TestBit(kMustCleanup)) gPad->Modified();
225}
226
227// --------------------------------------------------------------------------
228//
229// Change (i.e. set) all the MParContainer parameters (name and title).
230// See also WARNING in SetName
231//
232void MParContainer::SetObject(const char *name, const char *title)
233{
234 fName = name;
235 fTitle = title;
236 ResetBit(kIsSavedAsPrimitive);
237 if (gPad && TestBit(kMustCleanup)) gPad->Modified();
238}
239
240// --------------------------------------------------------------------------
241//
242// Change (i.e. set) the title of the MParContainer.
243//
244void MParContainer::SetTitle(const char *title)
245{
246 fTitle = title;
247 ResetBit(kIsSavedAsPrimitive);
248 if (gPad && TestBit(kMustCleanup)) gPad->Modified();
249}
250
251// --------------------------------------------------------------------------
252//
253// Return size of the MParContainer part of the TObject.
254//
255Int_t MParContainer::Sizeof() const
256{
257 Int_t nbytes = fName.Sizeof() + fTitle.Sizeof();
258 return nbytes;
259}
260
261// --------------------------------------------------------------------------
262//
263// If you want to use Ascii-Input/-Output (eg. MWriteAsciiFile) of a
264// container, overload this function.
265//
266void MParContainer::AsciiRead(ifstream &fin)
267{
268 *fLog << warn << "To use the the ascii input of " << GetName();
269 *fLog << " you have to overload " << ClassName() << "::AsciiRead." << endl;
270}
271
272// --------------------------------------------------------------------------
273//
274// Write out a data member given as a TDataMember object to an output stream.
275//
276Bool_t MParContainer::WriteDataMember(ostream &out, const TDataMember *member, Double_t scale) const
277{
278 if (!member)
279 return kFALSE;
280
281 if (!member->IsPersistent() || member->Property()&kIsStatic)
282 return kFALSE;
283
284 /*const*/ TMethodCall *call = ((TDataMember*)member)->GetterMethod(); //FIXME: Root
285 if (!call)
286 {
287 *fLog << warn << "Sorry, no getter method found for " << member->GetName() << endl;
288 return kFALSE;
289 }
290
291 // For debugging: out << member->GetName() << ":";
292
293 switch (call->ReturnType())
294 {
295 case TMethodCall::kLong:
296 Long_t l;
297 call->Execute((void*)this, l); // FIXME: const, root
298 out << l << " ";
299 return kTRUE;
300
301 case TMethodCall::kDouble:
302 Double_t d;
303 call->Execute((void*)this, d); // FIXME: const, root
304 out << (scale*d) << " ";
305 return kTRUE;
306
307 default:
308 //case TMethodCall::kString:
309 //case TMethodCall::kOther:
310 /* someone may want to enhance this? */
311 return kFALSE;
312 }
313}
314
315// --------------------------------------------------------------------------
316//
317// Write out a data member given by name to an output stream.
318//
319Bool_t MParContainer::WriteDataMember(ostream &out, const char *member, Double_t scale) const
320{
321 /*const*/ TClass *cls = IsA()->GetBaseDataMember(member);
322 if (!cls)
323 return kFALSE;
324
325 return WriteDataMember(out, cls->GetDataMember(member), scale);
326}
327
328// --------------------------------------------------------------------------
329//
330// Write out a data member from a given TList of TDataMembers.
331// returns kTRUE when at least one member was successfully written
332//
333Bool_t MParContainer::WriteDataMember(ostream &out, const TList *list) const
334{
335 Bool_t rc = kFALSE;
336
337 TDataMember *data = NULL;
338
339 TIter Next(list);
340 while ((data=(TDataMember*)Next()))
341 rc |= WriteDataMember(out, data);
342
343 return rc;
344}
345
346// --------------------------------------------------------------------------
347//
348// If you want to use Ascii-Input/-Output (eg. MWriteAsciiFile) of a
349// container, you may overload this function. If you don't overload it
350// the data member of a class are written to the file in the order of
351// appearance in the class header (be more specfic: root dictionary)
352// Only data members which are of integer (Bool_t, Int_t, ...) or
353// floating point (Float_t, Double_t, ...) type are written.
354// returns kTRUE when at least one member was successfully written
355//
356Bool_t MParContainer::AsciiWrite(ostream &out) const
357{
358 // *fLog << warn << "To use the the ascii output of " << GetName();
359 // *fLog << " you have to overload " << ClassName() << "::AsciiWrite." << endl;
360
361 Bool_t rc = WriteDataMember(out, IsA()->GetListOfDataMembers());
362
363 TIter NextBaseClass(IsA()->GetListOfBases());
364 TBaseClass *base;
365 while ((base = (TBaseClass*) NextBaseClass()))
366 {
367 /*const*/ TClass *cls = base->GetClassPointer();
368
369 if (!cls)
370 continue;
371
372 if (cls->GetClassVersion())
373 rc |= WriteDataMember(out, cls->GetListOfDataMembers());
374 }
375
376 return rc;
377}
378
379TMethodCall *MParContainer::GetterMethod(const char *name) const
380{
381 TClass *cls = IsA()->GetBaseDataMember(name);
382 if (cls)
383 {
384 TDataMember *member = cls->GetDataMember(name);
385 if (!member)
386 {
387 *fLog << err << "Datamember '" << name << "' not in " << GetDescriptor() << endl;
388 return NULL;
389 }
390
391 TMethodCall *call = member->GetterMethod();
392 if (call)
393 return call;
394 }
395
396 *fLog << warn << "No standard access for '" << name << "' in ";
397 *fLog << GetDescriptor() << " or one of its base classes." << endl;
398
399 TMethodCall *call = NULL;
400
401 *fLog << warn << "Trying to find MethodCall '" << ClassName();
402 *fLog << "::Get" << name << "' instead <LEAKS MEMORY>" << endl;
403 call = new TMethodCall(IsA(), (TString)"Get"+name, "");
404 if (call->GetMethod())
405 return call;
406
407 delete call;
408
409 *fLog << warn << "Trying to find MethodCall '" << ClassName();
410 *fLog << "::" << name << "' instead <LEAKS MEMORY>" << endl;
411 call = new TMethodCall(IsA(), name, "");
412 if (call->GetMethod())
413 return call;
414
415 delete call;
416
417 *fLog << err << "Sorry, no getter method found for " << name << endl;
418 return NULL;
419}
420
421// --------------------------------------------------------------------------
422//
423// Implementation of SavePrimitive. Used to write the call to a constructor
424// to a macro. In the original root implementation it is used to write
425// gui elements to a macro-file.
426//
427void MParContainer::SavePrimitive(ofstream &out, Option_t *o)
428{
429 static UInt_t uid = 0;
430
431 if (IsSavedAsPrimitive())
432 return;
433
434 SetUniqueID(uid++);
435 SetBit(kIsSavedAsPrimitive);
436
437 if (gListOfPrimitives && !gListOfPrimitives->FindObject(this))
438 gListOfPrimitives->Add(this);
439
440 StreamPrimitive(out);
441}
442
443// --------------------------------------------------------------------------
444//
445// Creates the string written by SavePrimitive and returns it.
446//
447void MParContainer::StreamPrimitive(ofstream &out) const
448{
449 out << " // Using MParContainer::StreamPrimitive" << endl;
450 out << " " << ClassName() << " " << GetUniqueName() << "(\"";
451 out << fName << "\", \"" << fTitle << "\");" << endl;
452}
453
454void MParContainer::GetNames(TObjArray &arr) const
455{
456 arr.AddLast(new TNamed(fName, fTitle));
457}
458
459void MParContainer::SetNames(TObjArray &arr)
460{
461 TNamed *name = (TNamed*)arr.First();
462
463 fName = name->GetName();
464 fTitle = name->GetTitle();
465
466 delete arr.Remove(name);
467 arr.Compress();
468}
469
470// --------------------------------------------------------------------------
471//
472// Creates a new instance of this class. The idea is to create a clone of
473// this class in its initial state.
474//
475MParContainer *MParContainer::New() const
476{
477 return (MParContainer*)IsA()->New();
478}
479
480// --------------------------------------------------------------------------
481//
482// Read the contents/setup of a parameter container/task from a TEnv
483// instance (steering card/setup file).
484// The key to search for in the file should be of the syntax:
485// prefix.vname
486// While vname is a name which is specific for a single setup date
487// (variable) of this container and prefix is something like:
488// evtloopname.name
489// While name is the name of the containers/tasks in the parlist/tasklist
490//
491// eg. Job4.MImgCleanStd.CleaningLevel1: 3.0
492// Job4.MImgCleanStd.CleaningLevel2: 2.5
493//
494// If this cannot be found the next step is to search for
495// MImgCleanStd.CleaningLevel1: 3.0
496// And if this doesn't exist, too, we should search for:
497// CleaningLevel1: 3.0
498//
499// Warning: The programmer is responsible for the names to be unique in
500// all Mars classes.
501//
502Bool_t MParContainer::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
503{
504 if (!IsEnvDefined(env, prefix, "", print))
505 return kFALSE;
506
507 *fLog << warn << "WARNING - Resource " << prefix+fName << " found, but no " << ClassName() << "::ReadEnv." << endl;
508 return kTRUE;
509}
510
511// --------------------------------------------------------------------------
512//
513// Write the contents/setup of a parameter container/task to a TEnv
514// instance (steering card/setup file).
515// The key to search for in the file should be of the syntax:
516// prefix.vname
517// While vname is a name which is specific for a single setup date
518// (variable) of this container and prefix is something like:
519// evtloopname.name
520// While name is the name of the containers/tasks in the parlist/tasklist
521//
522// eg. Job4.MImgCleanStd.CleaningLevel1: 3.0
523// Job4.MImgCleanStd.CleaningLevel2: 2.5
524//
525// If this cannot be found the next step is to search for
526// MImgCleanStd.CleaningLevel1: 3.0
527// And if this doesn't exist, too, we should search for:
528// CleaningLevel1: 3.0
529//
530// Warning: The programmer is responsible for the names to be unique in
531// all Mars classes.
532//
533Bool_t MParContainer::WriteEnv(TEnv &env, TString prefix, Bool_t print) const
534{
535 if (!IsEnvDefined(env, prefix, "", print))
536 return kFALSE;
537
538 *fLog << warn << "WARNING - Resource " << prefix+fName << " found, but " << ClassName() << "::WriteEnv not overloaded." << endl;
539 return kTRUE;
540}
541
542Bool_t MParContainer::IsEnvDefined(const TEnv &env, TString prefix, TString postfix, Bool_t print) const
543{
544 if (!postfix.IsNull())
545 postfix.Insert(0, ".");
546
547 return IsEnvDefined(env, prefix+postfix, print);
548}
549
550Bool_t MParContainer::IsEnvDefined(const TEnv &env, TString name, Bool_t print) const
551{
552 if (print)
553 *fLog << all << GetDescriptor() << " - " << name << "... " << flush;
554
555 if (!((TEnv&)env).Defined(name))
556 {
557 if (print)
558 *fLog << "not found." << endl;
559 return kFALSE;
560 }
561
562 if (print)
563 *fLog << "found." << endl;
564
565 return kTRUE;
566}
567
568Int_t MParContainer::GetEnvValue(const TEnv &env, TString prefix, TString postfix, Int_t dflt) const
569{
570 return GetEnvValue(env, prefix+"."+postfix, dflt);
571}
572
573Double_t MParContainer::GetEnvValue(const TEnv &env, TString prefix, TString postfix, Double_t dflt) const
574{
575 return GetEnvValue(env, prefix+"."+postfix, dflt);
576}
577
578const char *MParContainer::GetEnvValue(const TEnv &env, TString prefix, TString postfix, const char *dflt) const
579{
580 return GetEnvValue(env, prefix+"."+postfix, dflt);
581}
582
583Int_t MParContainer::GetEnvValue(const TEnv &env, TString prefix, Int_t dflt) const
584{
585 return ((TEnv&)env).GetValue(prefix, dflt);
586}
587
588Double_t MParContainer::GetEnvValue(const TEnv &env, TString prefix, Double_t dflt) const
589{
590 return ((TEnv&)env).GetValue(prefix, dflt);
591}
592
593const char *MParContainer::GetEnvValue(const TEnv &env, TString prefix, const char *dflt) const
594{
595 return ((TEnv&)env).GetValue(prefix, dflt);
596}
Note: See TracBrowser for help on using the repository browser.