source: trunk/MagicSoft/Mars/mbase/MParList.cc@ 1886

Last change on this file since 1886 was 1880, checked in by tbretz, 21 years ago
*** empty log message ***
File size: 24.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// MParList //
28// //
29// This class contains a list of different parameter containers. //
30// //
31// A parameter container is an object which is derived from //
32// MParContainer. //
33// //
34// Normally a parameter container is used for data exchange between two //
35// tasks at runtime. //
36// //
37// You can add every parameter container (Named object) to the //
38// instance and access it from somewhere else via its Name. //
39// //
40/////////////////////////////////////////////////////////////////////////////
41#include "MParList.h"
42
43#include <fstream.h> // ofstream, SavePrimitive
44
45#include <TNamed.h>
46#include <TClass.h>
47#include <TOrdCollection.h>
48
49#include "MLog.h"
50#include "MLogManip.h"
51
52#include "MIter.h"
53
54ClassImp(MParList);
55
56static const TString gsDefName = "MParList";
57static const TString gsDefTitle = "A list of Parameter Containers";
58
59// --------------------------------------------------------------------------
60//
61// default constructor
62// creates an empty list
63//
64MParList::MParList(const char *name, const char *title)
65{
66 fName = name ? name : gsDefName.Data();
67 fTitle = title ? title : gsDefTitle.Data();
68
69 //
70 // This sets a flag that the list is the owner, which means
71 // that the destructor of the list deletes all it's objects
72 //
73 fContainer = new TOrdCollection;
74 fAutodelete = new TOrdCollection;
75}
76
77// --------------------------------------------------------------------------
78//
79// Copy constructor. It copies all entries of the parameter list, but it
80// takes care of, that the automatically created entries are only deleted
81// once. (doesn't copy the list which holds the automatically created
82// entries)
83//
84MParList::MParList(MParList &ts)
85{
86 fContainer->AddAll(ts.fContainer);
87}
88
89// --------------------------------------------------------------------------
90//
91// If the 'IsOwner' bit is set (via SetOwner()) all containers are deleted
92// by the destructor
93//
94MParList::~MParList()
95{
96 //
97 // Case:
98 // 1) MParList is owner of the containers:
99 // All container are stored in fContainer, and become deleted by
100 // 'delete fContainer'. Some of these containers, which were
101 // created automatically are stored in fAutodelete, too. To prevent
102 // double deletion this containers are not deleted by the destructor
103 // of fAutodelete.
104 // 2) MParList is not owner of the containers:
105 // The containers which were Added by AddToList are not touched.
106 // Only the containers which were created automatically are also
107 // automatically deleted.
108 //
109 IsOwner() ? fContainer->SetOwner() : fAutodelete->SetOwner();
110
111 // FIXME? If fContainer is owner do we have to remove the object
112 // from fAutodelete due to the acces when checking for a
113 // garbage collection?
114
115 delete fContainer;
116 delete fAutodelete;
117}
118
119// --------------------------------------------------------------------------
120//
121// If the 'IsOwner' bit is set (via SetOwner()) all containers are deleted
122// by the destructor
123//
124void MParList::SetOwner(Bool_t enable)
125{
126 enable ? SetBit(kIsOwner) : ResetBit(kIsOwner);
127}
128
129// --------------------------------------------------------------------------
130//
131// Set the logging streamer of the parameter list and all contained
132// parameter containers
133//
134void MParList::SetLogStream(MLog *log)
135{
136 fContainer->ForEach(MParContainer, SetLogStream)(log);
137 MParContainer::SetLogStream(log);
138}
139
140// --------------------------------------------------------------------------
141//
142// Add a single container to the list.
143//
144// If 'where' is given, the object will be added after this.
145//
146Bool_t MParList::AddToList(MParContainer *cont, MParContainer *where)
147{
148 //
149 // check if the object (you want to add) exists
150 //
151
152 if (!cont)
153 return kFALSE;
154
155 //
156 // Get Name of new container
157 //
158 const char *name = cont->GetName();
159
160 //
161 // Check if the new container is already existing in the list
162 //
163 const TObject *objn = fContainer->FindObject(name);
164 const TObject *objt = fContainer->FindObject(cont);
165
166 if (objn || objt)
167 {
168 //
169 // If the container is already in the list ignore it.
170 //
171 if (objt || objn==cont)
172 {
173 *fLog << warn << dbginf << "Warning: Container '" << cont->GetName() << ", 0x" << (void*)cont;
174 *fLog << "' already existing in '" << GetName() << "'... ignoring." << endl;
175 return kTRUE;
176 }
177
178 //
179 // Otherwise add it to the list, but print a warning message
180 //
181 *fLog << warn << dbginf << "Warning: Container with the same name '" << cont->GetName();
182 *fLog << "' already existing in '" << GetName() << "'." << endl;
183 *fLog << "You may not be able to get a pointer to container task by name." << endl;
184 }
185
186 //
187 // check if you want to add the new parameter container somewhere
188 // special (in that case you specify "where")
189 //
190 if (where)
191 {
192 if (!fContainer->FindObject(where))
193 {
194 *fLog << dbginf << "Error: Cannot find parameter container after which the new one should be added!" << endl;
195 return kFALSE;
196 }
197 }
198
199 *fLog << inf << "Adding " << name << " to " << GetName() << "... " << flush;
200
201 fContainer->Add(cont);
202 *fLog << "Done." << endl;
203
204 return kTRUE;
205}
206
207// --------------------------------------------------------------------------
208//
209// Add all entries of the TObjArray to the list.
210//
211void MParList::AddToList(TObjArray *list)
212{
213 //
214 // check if the object (you want to add) exists
215 //
216 if (!list)
217 return;
218
219 TObjArrayIter Next(list);
220
221 MParContainer *cont = NULL;
222 while ((cont=(MParContainer*)Next()))
223 AddToList(cont);
224}
225
226// --------------------------------------------------------------------------
227//
228// Find an object with the same name in the list and replace it with
229// the new one. If the kIsOwner flag is set and the object was not
230// created automatically, the object is deleted.
231//
232Bool_t MParList::Replace(MParContainer *cont)
233{
234 //
235 // check if the object (you want to add) exists
236 //
237 if (!cont)
238 return kFALSE;
239
240 TObject *obj = FindObject(cont->GetName());
241 if (!obj)
242 {
243 *fLog << warn << "No object with the same name '";
244 *fLog << cont->GetName() << "' in list... adding." << endl;
245 return AddToList(cont);
246 }
247
248 fContainer->Remove(obj);
249
250 if (IsOwner() && !fAutodelete->FindObject(obj))
251 delete obj;
252
253 *fLog << inf << "MParContainer '" << cont->GetName() << "' found and replaced..." << endl;
254
255 return AddToList(cont);
256}
257
258// --------------------------------------------------------------------------
259//
260// Find an object with the same name in the list and remove it.
261// If the kIsOwner flag is set and the object was not created
262// automatically, the object is deleted.
263//
264void MParList::Remove(MParContainer *cont)
265{
266 //
267 // check if the object (you want to add) exists
268 //
269 if (!cont)
270 return;
271
272 TObject *obj = fContainer->Remove(cont);
273 if (!obj)
274 {
275 *fLog << warn << "Object not found in list..." << endl;
276 return;
277 }
278
279 *fLog << inf << "MParContainer '" << cont->GetName() << "' removed..." << endl;
280
281 if (IsOwner() && !fAutodelete->FindObject(obj))
282 delete obj;
283}
284
285// --------------------------------------------------------------------------
286//
287// Find an object in the list.
288// 'name' is the name of the object you are searching for.
289//
290TObject *MParList::FindObject(const char *name) const
291{
292 return fContainer->FindObject(name);
293}
294
295// --------------------------------------------------------------------------
296//
297// check if the object is in the list or not
298//
299TObject *MParList::FindObject(const TObject *obj) const
300{
301 return fContainer->FindObject(obj);
302}
303
304// --------------------------------------------------------------------------
305//
306// Find an object in the list and check for the correct inheritance.
307// 'name' is the name of the object you are searching for.
308//
309TObject *MParList::FindObject(const char *name, const char *classname) const
310{
311 TObject *obj = fContainer->FindObject(name);
312
313 if (!obj)
314 return NULL;
315
316 if (obj->InheritsFrom(classname))
317 return obj;
318
319 *fLog << dbginf << warn << "Found object '" << name << "' doesn't ";
320 *fLog << "inherit from " << "'" << classname << "'" << endl;
321 return NULL;
322}
323
324// --------------------------------------------------------------------------
325//
326// check if the object is in the list or not and check for the correct
327// inheritance
328//
329TObject *MParList::FindObject(const TObject *obj, const char *classname) const
330{
331 TObject *nobj = fContainer->FindObject(obj);
332
333 if (!nobj)
334 return NULL;
335
336 if (nobj->InheritsFrom(classname))
337 return nobj;
338
339 *fLog << dbginf << warn << "Found object '" << nobj->GetName() << "' ";
340 *fLog << "doesn't inherit from " << "'" << classname << "'" << endl;
341 return NULL;
342}
343
344// --------------------------------------------------------------------------
345//
346// returns the ClassName without anything which is behind that last ';' in
347// string.
348//
349TString MParList::GetClassName(const char *classname)
350{
351 TString cname(classname);
352 const char *semicolon = strrchr(cname, ';');
353
354 if (semicolon)
355 cname.Remove(semicolon-cname);
356
357 return cname;
358}
359
360// --------------------------------------------------------------------------
361//
362// returns the ObjectName. It is created from a class and object name.
363// If no object name is given the objectname is the same than the
364// class name. Leading dots are removed from the object name
365//
366TString MParList::GetObjectName(const char *classname, const char *objname)
367{
368 TString cname(classname);
369 const char *semicolon = strrchr(cname, ';');
370
371 TString oname(objname ? objname : classname);
372
373 if (semicolon)
374 {
375 //
376 // Remove leading dots from objectname (eg. "MMcTrig;5.")
377 //
378 Int_t sz = oname.Sizeof()-2;
379
380 while (sz>=0 && oname[sz]=='.')
381 oname.Remove(sz--);
382 }
383 return oname;
384}
385
386// --------------------------------------------------------------------------
387//
388// Find an object in the list.
389// 'name' is the name of the object you are searching for.
390// If the object doesn't exist we try to create one from the
391// dictionary. If this isn't possible NULL is returned.
392//
393// An object which was created automatically is deleted automatically in
394// the destructor of the parameter list, too. This means, that if an
395// object should survive (eg. Histograms) you MUST create it by yourself
396// and add it to the parameter list.
397//
398// By default (you don't specify an object name) the object name is
399// the same as the classname
400//
401// If the classname (default classname) is of the structure
402// "Name;something" - containing a semicolon - evarything which is
403// after the last appearance of a semicolon is stripped to get the
404// Name of the Class. Normally this is used to number your objects.
405// "Name;1", "Name;2", ... If a semicolon is detected leading dots
406// are stripped from the object-name (eg. "name;5.")
407//
408MParContainer *MParList::FindCreateObj(const char *classname, const char *objname)
409{
410 //
411 // If now object name (name of the object to identify it in the
412 // List) is given use it's classname as the objectname
413 //
414
415 //
416 // Check if the classname is a 'numbered' name (like: "MTime;2")
417 // if so strip the number from the classname.
418 //
419 // Becareful: We check for the last occurance of a ';' only and we
420 // also don't check if a number follows or something else.
421 //
422 // Rem: I use a TString to make the code more readyble and to get
423 // the new object deleted automatically
424 //
425 TString cname = GetClassName(classname);
426 TString oname = GetObjectName(classname, objname);
427
428 //
429 // Try to find a object with this object name which is already
430 // in the List. If we can find one we are done.
431 //
432 MParContainer *pcont = (MParContainer*)FindObject(oname);
433
434 if (pcont)
435 {
436 if (pcont->InheritsFrom(cname))
437 return pcont;
438
439 *fLog << err << "Warning: Object '" << oname << "' found in list doesn't inherit from " << cname << "." << endl;
440 return NULL;
441 }
442
443 //
444 // if object is not existing in the list try to create one
445 //
446 *fLog << inf << "Object '" << oname << "' [" << cname << "] not yet in " << GetName() << "... creating." << endl;
447
448 //
449 // try to get class from root environment
450 //
451 TClass *cls = gROOT->GetClass(cname);
452 if (!cls)
453 {
454 //
455 // if class is not existing in the root environment
456 //
457 *fLog << err << dbginf << "Class '" << cname << "' not existing in dictionary." << endl;
458 return NULL;
459 }
460
461 //
462 // create the parameter container of the the given class type
463 //
464 pcont = (MParContainer*)cls->New();
465 if (!pcont)
466 {
467 *fLog << err << dbginf << "Cannot create new instance of class '" << cname << "' (Maybe no def. constructor)" << endl;
468 return NULL;
469 }
470
471 //
472 // Set the name of the container
473 //
474 pcont->SetName(oname);
475
476 //
477 // Now add the object to the parameter list
478 //
479 AddToList(pcont);
480
481 //
482 // The object was automatically created. This makes sure, that such an
483 // object is deleted together with the list
484 //
485 fAutodelete->Add(pcont);
486
487 //
488 // Find an object in the list.
489 // 'name' is the name of the object you are searching for.
490 //
491 return pcont;
492}
493
494// --------------------------------------------------------------------------
495//
496// print some information about the current status of MParList
497//
498void MParList::Print(Option_t *t) const
499{
500 *fLog << all << " " << GetDescriptor() << endl;
501 *fLog << setfill('-') << setw(strlen(GetDescriptor())+2) << "" << endl;
502 MParContainer *obj = NULL;
503 TIter Next(fContainer);
504 while ((obj=(MParContainer*)Next()))
505 {
506 *fLog << " " << obj->GetDescriptor();
507 if (fAutodelete->FindObject(obj))
508 *fLog << " <autodel>";
509 *fLog << endl;
510 }
511 *fLog << endl;
512}
513
514// --------------------------------------------------------------------------
515//
516// Sets the flags off all containers in the list (and the list
517// itself) to unchanged
518//
519void MParList::SetReadyToSave(Bool_t flag)
520{
521 fContainer->ForEach(MParContainer, SetReadyToSave)(flag);
522 MParContainer::SetReadyToSave(flag);
523}
524
525// --------------------------------------------------------------------------
526//
527// Reset all containers in the list
528//
529void MParList::Reset()
530{
531 fContainer->ForEach(MParContainer, Reset)();
532}
533
534// --------------------------------------------------------------------------
535//
536// This finds numbered objects. The objects are returned in a copy of a
537// TObjArray.
538//
539// If from only is given (or to=0) object are assumed numbered
540// from 1 to from.
541//
542TObjArray MParList::FindObjectList(const char *name, UInt_t first, const UInt_t last) const
543{
544 TObjArray list;
545
546 if (first>0 && last<first)
547 {
548 *fLog << err << dbginf << "Cannot create entries backwards (last<first)...skipped." << endl;
549 return list;
550 }
551
552 const UInt_t len = strlen(name);
553
554 char *auxname = new char[len+7];
555 strcpy(auxname, name);
556
557 if (first==0 && last!=0)
558 first = 1;
559
560 //
561 // If only 'from' is specified the number of entries are ment
562 //
563 for (UInt_t i=first; i<=last; i++)
564 {
565 if (first!=0 || last!=0)
566 sprintf(auxname+len, ";%d", i);
567
568 TObject *obj = FindObject(auxname);
569 if (!obj)
570 continue;
571
572 list.AddLast(obj);
573 }
574 delete auxname;
575
576 return list;
577}
578
579// --------------------------------------------------------------------------
580//
581// This finds numbered objects. The objects are returned in a copy of a
582// TObjArray. If one of the objects doesn't exist it is created from the
583// meaning of cname and oname (s. FindCreateObj)
584//
585// If from only is given (or to=0) object are assumed numbered
586// from 1 to from.
587//
588TObjArray MParList::FindCreateObjList(const char *cname, UInt_t first, const UInt_t last, const char *oname)
589{
590 TObjArray list;
591
592 if (first>0 && last<first)
593 {
594 *fLog << err << dbginf << "Cannot create entries backwards (last<first)...skipped." << endl;
595 return list;
596 }
597
598 const UInt_t len = strlen(cname);
599
600 char *auxname = new char[len+7];
601 strcpy(auxname, cname);
602
603 //
604 // If only 'from' is specified the number of entries are ment
605 //
606 if (first==0 && last!=0)
607 first = 1;
608
609 for (UInt_t i=first; i<=last; i++)
610 {
611 if (first!=0 || last!=0)
612 sprintf(auxname+len, ";%d", i);
613
614 TObject *obj = FindCreateObj(auxname, oname);
615 if (!obj)
616 break;
617
618 list.AddLast(obj);
619 }
620 delete auxname;
621
622 return list;
623}
624
625// --------------------------------------------------------------------------
626//
627// This finds numbered objects. The objects are returned in a copy of a
628// TObjArray. If one of the objects doesn't exist it is created from the
629// meaning of cname and oname (s. FindCreateObj)
630//
631// If from only is given (or to=0) object are assumed numbered
632// from 1 to from.
633//
634// Remark: Because it is static the object are only created and not added to
635// the parameter list. You must also take care of deleting these objects!
636// This function is mainly made for use in root macros. Don't use it in
637// compiled programs if you are not 100% sure what you are doing.
638//
639TObjArray MParList::CreateObjList(const char *cname, UInt_t first, const UInt_t last, const char *oname)
640{
641 TObjArray list;
642
643 if (first>0 && last<first)
644 {
645 gLog << err << dbginf << "Cannot create entries backwards (last<first)...skipped." << endl;
646 return list;
647 }
648
649 //
650 // try to get class from root environment
651 //
652 TClass *cls = gROOT->GetClass(cname);
653 if (!cls)
654 {
655 //
656 // if class is not existing in the root environment
657 //
658 gLog << dbginf << "Class '" << cname << "' not existing in dictionary." << endl;
659 return list;
660 }
661
662 const UInt_t len = strlen(cname);
663
664 char *auxname = new char[len+7];
665 strcpy(auxname, cname);
666
667 //
668 // If only 'from' is specified the number of entries are ment
669 //
670 if (first==0 && last!=0)
671 first = 1;
672
673 for (UInt_t i=first; i<=last; i++)
674 {
675 if (first!=0 || last!=0)
676 sprintf(auxname+len, ";%d", i);
677
678 //
679 // create the parameter container of the the given class type
680 //
681 MParContainer *pcont = (MParContainer*)cls->New();
682 if (!pcont)
683 {
684 gLog << err << dbginf << "Cannot create new instance of class '" << cname << "' (Maybe no def. constructor)" << endl;
685 return list;
686 }
687
688 //
689 // Set the name of the container
690 //
691 pcont->SetName(auxname);
692
693 //
694 // Add new object to the return list
695 //
696 list.AddLast(pcont);
697 }
698 delete auxname;
699
700 return list;
701}
702
703void MParList::SavePrimitive(ofstream &out, Option_t *o)
704{
705 Bool_t saved = IsSavedAsPrimitive();
706
707 MParContainer::SavePrimitive(out);
708
709 MIter Next(fContainer);
710
711 MParContainer *cont = NULL;
712 while ((cont=Next()))
713 {
714 //
715 // Because it was automatically created don't store its primitive
716 // I guess it will be automatically created again
717 //
718 if (fAutodelete->FindObject(cont) || cont->IsSavedAsPrimitive())
719 continue;
720
721 cont->SavePrimitive(out, "");
722
723 out << " " << GetUniqueName() << ".";
724 out << (cont->InheritsFrom("MTaskList") && saved ? "Replace" : "AddToList");
725 out << "(&" << cont->GetUniqueName() << ");" << endl << endl;
726 }
727}
728
729// --------------------------------------------------------------------------
730//
731// Implementation of SavePrimitive. Used to write the call to a constructor
732// to a macro. In the original root implementation it is used to write
733// gui elements to a macro-file.
734//
735void MParList::StreamPrimitive(ofstream &out) const
736{
737 out << " MParList " << GetUniqueName();
738 if (fName!=gsDefName || fTitle!=gsDefTitle)
739 {
740 out << "(\"" << fName << "\"";
741 if (fTitle!=gsDefTitle)
742 out << ", \"" << fTitle << "\"";
743 out <<")";
744 }
745 out << ";" << endl << endl;
746}
747
748// --------------------------------------------------------------------------
749//
750// Adds one TNamed object per object in the list. The TNamed object must
751// be deleted by the user.
752//
753void MParList::GetNames(TObjArray &arr) const
754{
755 MParContainer::GetNames(arr);
756 fContainer->ForEach(MParContainer, GetNames)(arr);
757}
758
759// --------------------------------------------------------------------------
760//
761// Sets name and title of each object in the list from the objects in
762// the array.
763//
764void MParList::SetNames(TObjArray &arr)
765{
766 MParContainer::SetNames(arr);
767 fContainer->ForEach(MParContainer, SetNames)(arr);
768}
769
770// --------------------------------------------------------------------------
771//
772// Read the contents/setup of a parameter container/task from a TEnv
773// instance (steering card/setup file).
774// The key to search for in the file should be of the syntax:
775// prefix.vname
776// While vname is a name which is specific for a single setup date
777// (variable) of this container and prefix is something like:
778// evtloopname.name
779// While name is the name of the containers/tasks in the parlist/tasklist
780//
781// eg. Job4.MImgCleanStd.CleaningLevel1: 3.0
782// Job4.MImgCleanStd.CleaningLevel2: 2.5
783//
784// If this cannot be found the next step is to search for
785// MImgCleanStd.CleaningLevel1: 3.0
786// And if this doesn't exist, too, we search for:
787// CleaningLevel1: 3.0
788//
789// Warning: The programmer is responsible for the names to be unique in
790// all Mars classes.
791//
792Bool_t MParList::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
793{
794 MParContainer *cont = NULL;
795
796 TIter Next(fContainer);
797 while ((cont=(MParContainer*)Next()))
798 if (cont->ReadEnv(env, print)==kERROR)
799 return kERROR;
800
801 Next.Reset();
802 while ((cont=(MParContainer*)Next()))
803 if (cont->ReadEnv(env, prefix, print)==kERROR)
804 return kERROR;
805
806 return kTRUE;
807}
808
809// --------------------------------------------------------------------------
810//
811// Write the contents/setup of a parameter container/task to a TEnv
812// instance (steering card/setup file).
813// The key to search for in the file should be of the syntax:
814// prefix.vname
815// While vname is a name which is specific for a single setup date
816// (variable) of this container and prefix is something like:
817// evtloopname.name
818// While name is the name of the containers/tasks in the parlist/tasklist
819//
820// eg. Job4.MImgCleanStd.CleaningLevel1: 3.0
821// Job4.MImgCleanStd.CleaningLevel2: 2.5
822//
823// If this cannot be found the next step is to search for
824// MImgCleanStd.CleaningLevel1: 3.0
825// And if this doesn't exist, too, we search for:
826// CleaningLevel1: 3.0
827//
828// Warning: The programmer is responsible for the names to be unique in
829// all Mars classes.
830//
831Bool_t MParList::WriteEnv(TEnv &env, TString prefix, Bool_t print) const
832{
833 MParContainer *cont = NULL;
834
835 TIter Next(fContainer);
836 while ((cont=(MParContainer*)Next()))
837 if (!cont->WriteEnv(env, prefix, print))
838 return kFALSE;
839 return kTRUE;
840}
Note: See TracBrowser for help on using the repository browser.