]> git.uio.no Git - u/mrichter/AliRoot.git/blob - PWGLF/FORWARD/trains/Option.C
Doxygen updates
[u/mrichter/AliRoot.git] / PWGLF / FORWARD / trains / Option.C
1 /**
2  * @file   Option.C
3  * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
4  * @date   Tue Oct 16 18:59:04 2012
5  * 
6  * @brief  
7  * 
8  * 
9  * @ingroup pwglf_forward_trains_util
10  */
11 #ifndef OPTION_C
12 #define OPTION_C
13 #include <TNamed.h>
14 #include <iomanip>
15 #ifndef __CINT__
16 # include <TString.h>
17 # include <TList.h>
18 # include <TObjArray.h>
19 # include <TObjString.h>
20 # include <TMath.h>
21 # include <iostream>
22 # include <iomanip>
23 # include <cstdarg>
24 # include <cstdio>
25 #else
26 class TString;
27 class TList;
28 class TObjArray;
29 #endif
30
31 /** 
32  * An option.  The value is stored as a string 
33  *
34  * @ingroup pwglf_forward_trains_util
35  */
36 struct Option /* : public TNamed */
37 {
38   /** 
39    * Constructor 
40    * 
41    * @param name           Name of option
42    * @param arg            Dummy argument (possibly null)
43    * @param description    Description
44    * @param value          Default value 
45    */
46   Option(const TString& name, 
47          const TString& arg, 
48          const TString& description,
49          const TString& value)
50     : fName(name), fDescription(description), 
51       fValue(value), fArg(arg), fIsSet(false)
52   {}
53   /** 
54    * Copy constructor 
55    * 
56    * @param other Object to copy from 
57    */
58   Option(const Option& other)
59     : fName(other.fName), 
60       fDescription(other.fDescription),
61       fValue(other.fValue), 
62       fArg(other.fArg), 
63       fIsSet(other.fIsSet)
64   {}
65   /** 
66    * Assignment operator 
67    * 
68    * @param other Object to assign from 
69    *
70    * @return Reference to this object
71    */
72   Option& operator=(const Option& other)
73   {
74     if (&other == this) return *this;
75     
76     fName        = other.fName;
77     fDescription = other.fDescription;
78     fValue       = other.fValue;
79     fArg         = other.fArg;
80     fIsSet       = other.fIsSet;
81     
82     return *this;
83   }
84   /** 
85    * Set the value 
86    * 
87    * @param val New value 
88    */
89   void Set(const TString& val) 
90   { 
91     if (HasArg()) {
92       fIsSet = true;
93       fValue = val;
94       return;
95     }
96
97     // Allow flags to get =true, =1, =false, =0 values
98     if (!val.IsNull() && 
99         (val.EqualTo("false", TString::kIgnoreCase) || 
100          (val.IsDigit() && !val.Atoi()))) {
101       fIsSet = false;
102       fValue = "false";
103     }
104     else {
105       fIsSet = true;
106       fValue = "true";
107     }
108   }
109   /** 
110    * Set the value
111    */
112   void Set() 
113   { 
114     if (HasArg()) { 
115       Error("Option::Set", "Option %s needs an argument", fName.Data());
116       return;
117     }
118     Set("true");
119   }
120   /** 
121    * Reset the set flag
122    * 
123    */
124   void Reset() 
125   { 
126     fIsSet = false; 
127     if (!HasArg()) fValue = "false";
128   }
129   /**
130    * @return constant reference to value 
131    */
132   const TString& Get() const { return fValue; }
133   /**
134    * @return true if this option was set externally
135    */
136   Bool_t IsSet() const { return fIsSet; }
137   /**
138    * @return true if this option needs an argument
139    */
140   Bool_t HasArg() const { return !fArg.IsNull(); }
141   /**
142    * @return value as a boolean value
143    */
144   Bool_t AsBool() const { return fIsSet; }
145   /**
146    * @return value as an integer value
147    */
148   Int_t    AsInt() const { return fValue.Atoi(); }
149   /**
150    * @return value as a long integer value
151    */
152   Long64_t AsLong() const { return fValue.Atoll(); } 
153   /**
154    * @return value as a double precision value
155    */
156   Double_t AsDouble() const { return fValue.Atof(); } 
157   /**
158    * @return value as a C string
159    */
160   const char* AsString() const { return fValue.Data(); } 
161   /** 
162    * @return Width of the name 
163    */
164   Int_t NameWidth() const { return fName.IsNull() ? 0 : fName.Length(); }
165   /** 
166    * @return the width of the dummy argument
167    */
168   Int_t ArgWidth() const { return fArg.IsNull() ? 0 : fArg.Length(); }
169   /** 
170    * Show help 
171    * 
172    * @param o Output stream 
173    * @param w With of option plus argument 
174    */
175   void Help(std::ostream& o, Int_t w=-1) const
176   {
177     TString tmp(fName);
178     if (HasArg()) { 
179       tmp.Append("=");
180       tmp.Append(fArg);
181     }
182     if (w <= 0) w = NameWidth() + ArgWidth() + 1;
183     std::ios::fmtflags oldf = o.setf(std::ios::left);
184     o << std::setw(w) << tmp << "  " << fDescription << " [";
185     if (!HasArg()) o << (IsSet() ? "true" : "false");
186     else           o << fValue;
187     o << "]" << std::endl;
188     o.setf(oldf);
189   }
190   /** 
191    * Show the option
192    * 
193    * @param o Output stream
194    * @param w With of name 
195    */
196   void Show(std::ostream& o, Int_t w=-1) const 
197   {
198     if (w <= 0) w = NameWidth();
199     std::ios::fmtflags oldf = o.setf(std::ios::left);
200     o << std::setw(w) << fName << ": ";
201     if (!HasArg()) o << (IsSet() ? "true" : "false");
202     else           o << fValue;
203     o << std::endl;
204     o.setf(oldf);
205   }
206   /** 
207    * Store option and possible value 
208    * 
209    * @param o Output stream
210    * @param quote If true, quote output 
211    */
212   void Store(std::ostream& o, bool quote=true) const 
213   {
214     o << fName;
215     if (!HasArg()) return;
216     o << "=" << (quote ? "\"" : "") << fValue << (quote ? "\"" : "");
217   }
218   TString fName;        // Name 
219   TString fDescription; // Description
220   TString fValue;       // Value 
221   TString fArg;         // Argument dummy 
222   Bool_t  fIsSet;       // True if this option was set 
223   
224   // ClassDef(Option,1) // Option 
225 };
226
227 /** 
228  * A List of options 
229  */
230 struct OptionList 
231 {
232   // Linked list element
233   struct Link 
234   {
235     Link*   fPrev;
236     Link*   fNext;
237     Option* fThis;
238     Link() : fPrev(0), fNext(0), fThis(0) {}
239     Link(Link* next, Option* opt)
240       : fPrev(next ? next->fPrev : 0), // Set previous 
241         fNext(next), // Set next link
242         fThis(opt) // Set data
243     {
244       if (fPrev) fPrev->fNext = this; // Set forward link
245       if (fNext) fNext->fPrev = this; // Set previous link
246     }
247     ~Link() { 
248       if (fPrev) fPrev->fNext = fNext;
249       if (fNext) fNext->fPrev = fPrev;
250       delete fThis;
251     }
252     Link(const Link& o)
253       : fPrev(o.fPrev), 
254         fNext(o.fNext), 
255         fThis(o.fThis)
256     {
257     }
258     Link& operator=(const Link& o)
259     {
260       if (&o == this) return *this;
261       fPrev = o.fPrev;
262       fNext = o.fNext;
263       fThis = o.fThis;
264       return *this;
265     }   
266   };
267   /** 
268    * Constructor 
269    */
270   OptionList() : fList(0) { }
271   /** 
272    * Copy constructor 
273    *
274    * @param other Object to copy from 
275    */
276   OptionList(const OptionList& other) 
277     : fList(0)
278   { 
279     // fList.SetOwner(); 
280     // TIter next(&other.fList);
281     // Option* o = 0;
282     // while ((o = static_cast<Option*>(next()))) 
283     //   fList.Add(new Option(*o));
284     Copy(other);
285   }
286   /** 
287    * Destructor 
288    */
289   ~OptionList() { Delete(); }
290
291   /** 
292    * Remove all options 
293    */
294   void Delete()
295   { 
296     Link* cur = fList;
297     while (cur) {
298       Link* tmp = cur->fNext;
299       delete cur;
300       cur = tmp;
301       // Remove(cur->fThis->fName);
302       // cur = tmp;
303     }
304     fList = 0;
305   }
306   /** 
307    * Assignment operator 
308    *
309    * @param other  Object to assign from 
310    *
311    * @return reference to this 
312    */
313   OptionList& operator=(const OptionList& other) 
314   { 
315     if (&other == this) return *this;
316     Delete();
317     Copy(other);
318     
319     return *this; 
320   }
321   /** 
322    * Copy list from other object
323    * 
324    * @param other Object to copy from 
325    */
326   void Copy(const OptionList& other)
327   {
328     Delete();
329     const Link* ocur = other.fList;
330     Link*       cur  = fList;
331     Link*       prev = fList;
332     while (ocur) { 
333       cur        = new Link;
334       cur->fThis = new Option(*(ocur->fThis));
335       cur->fNext = 0;
336       cur->fPrev = prev;
337       if (fList == 0) fList = cur;
338       if (prev)       prev->fNext = cur;
339       prev = cur;
340       ocur = ocur->fNext;
341     }
342   }
343   void DebugLink(const Link* link) const
344   {
345     std::cout << "Link=" << link;
346     if (link) {
347       std::cout << " prev=" << link->fPrev 
348                 << " next=" << link->fNext
349                 << " obj=" << link->fThis;
350       if (link->fThis) 
351         std::cout << " name=" << link->fThis->fName;
352     }
353     std::cout <<std::endl;
354   }
355   /** 
356    * Find an optio by name 
357    * 
358    * @param name Name of option to find
359    * 
360    * @return Pointer to option or null
361    */
362   Option* Find(const TString& name) const
363   {
364     const Link* cur = fList;
365     // DebugLink(cur);
366     while (cur && cur->fThis) { 
367       if (name.EqualTo(cur->fThis->fName)) return cur->fThis;
368       cur = cur->fNext;
369     }
370     return 0;
371   }
372   /** 
373    * Add an option with argument 
374    * 
375    * @param name Name of option
376    * @param arg  Dummy argument
377    * @param desc Description
378    * @param val  Default value 
379    * 
380    * @return Newly added option 
381    */
382   Option* Add(const TString& name, 
383               const TString& arg, 
384               const TString& desc, 
385               const TString& val="")
386   {
387     Option* o = Find(name);
388     if (o) { 
389       Warning("OptionList::Add", "Option %s already registered", name.Data());
390       return o;
391     }
392     o = new Option(name, arg, desc, val);
393     Link*  cur  = fList;
394     if (!cur) { 
395       cur = new Link;
396       cur->fThis = o;
397       cur->fNext = 0;
398       cur->fPrev = 0;
399       fList      = cur;
400     }
401     else {
402       Link* n = 0;
403       Link* l = 0;
404       while (cur) { 
405         if (cur->fThis->fName.CompareTo(name) < 0) { 
406           l   = cur;
407           cur = cur->fNext;
408           continue;
409         }
410         n = new Link(cur, o);
411         if (cur == fList) fList = n;
412         break;
413       }
414       if (!n) { 
415         n = new Link;
416         l->fNext = n;
417         n->fPrev = l;
418         n->fNext = 0;
419         n->fThis = o;
420       }
421     }
422     return o;
423   }
424   /** 
425    * Add an option with no argument
426    * 
427    * @param name Name of option
428    * @param desc Description 
429    * 
430    * @return Newly created option 
431    */
432   Option* Add(const TString& name, 
433               const TString& desc)
434   {
435     return Add(name, "", desc, "");
436   }
437   /** 
438    * Add an option with no argument
439    * 
440    * @param name Name of option
441    * @param desc Description 
442    * @param def  Default value (true, or false)
443    * 
444    * @return Newly created option 
445    */
446   Option* Add(const TString& name, 
447               const TString& desc,
448               Bool_t         def)
449   {
450     Option* o = Add(name, "", desc, "");
451     if (o) o->Set(def ? "true" : "false");
452     return o;
453   }
454   /** 
455    * Add an option with argument 
456    * 
457    * @param name Name of option
458    * @param arg  Dummy argument
459    * @param desc Description
460    * @param val  Default value 
461    * @param asHex If true, interpret as hex number 
462    * 
463    * @return Newly added option 
464    */
465   Option* Add(const TString& name, 
466               const TString& arg, 
467               const TString& desc, 
468               Int_t          val, 
469               Bool_t         asHex=false)
470   {
471     if (asHex) {
472       UInt_t uval = val;
473       return Add(name, arg, desc, Form("0x%x", uval));
474     }
475     return Add(name, arg, desc, Form("%d", val));
476   }
477   /** 
478    * Add an option with argument 
479    * 
480    * @param name Name of option
481    * @param arg  Dummy argument
482    * @param desc Description
483    * @param val  Default value 
484    * @param asHex If true, interpret as hex 
485    * 
486    * @return Newly added option 
487    */
488   Option* Add(const TString& name, 
489               const TString& arg, 
490               const TString& desc, 
491               Long64_t       val, 
492               Bool_t         asHex=false)
493   {
494     if (asHex) {
495       ULong64_t uval = val;
496       return Add(name, arg, desc, Form("0x%llx", uval));
497     }
498     return Add(name, arg, desc, Form("%lld", val));
499   }
500   /** 
501    * Add an option with argument 
502    * 
503    * @param name Name of option
504    * @param arg  Dummy argument
505    * @param desc Description
506    * @param val  Default value 
507    * 
508    * @return Newly added option 
509    */
510   Option* Add(const TString& name, 
511               const TString& arg, 
512               const TString& desc, 
513               Double_t val)
514   {
515     return Add(name, arg, desc, Form("%lg", val));
516   }
517
518   /** 
519    * Remove an option 
520    * 
521    * @param name Name of option to remove 
522    */
523   void Remove(const TString& name)
524   {
525     Link* cur = fList;
526     while (cur) { 
527       if (!cur->fThis->fName.EqualTo(name)) {
528         cur = cur->fNext;
529         continue;
530       }
531       if (fList == cur) fList = cur->fNext;
532       delete cur;
533       break;
534     }
535   }
536   /** 
537    * Check if a given option was set externally
538    * 
539    * @param name Name of option
540    * 
541    * @return true if option exists and was set externally 
542    */
543   Bool_t Has(const TString& name) const
544   {
545     Option* o = Find(name);
546     return (o && o->IsSet());
547   }
548   /** 
549    * Get the value of an option
550    * 
551    * @param name Name of option
552    * 
553    * @return Value of option, or empty string 
554    */
555   const TString& Get(const TString& name) const
556   {
557     static TString null("");
558     Option* o = Find(name);
559     if (!o) return null;
560     return o->Get();
561   }
562   /** 
563    * Get a value using a format statement. Remember argument(s) must
564    * be passed by address (as pointers)
565    * 
566    * @param name Name of option @param format Format statement.
567    * Remeber, double and long needs the "l" modifier
568    * 
569    * @return true on success
570    */
571   Bool_t GetF(const TString& name, const Char_t* format, ...) const
572   {
573     Option* o = Find(name);
574     if (!o) return false;
575     
576     va_list ap;
577     va_start(ap, format);
578     int ret = vsscanf(o->fValue.Data(), format, ap);
579     va_end(ap);
580     
581     return ret > 0;
582   }
583   /** 
584    * Get value of an option as a boolean 
585    * 
586    * @param name Name of 
587    * 
588    * @return Value or false if not found
589    */
590   Bool_t AsBool(const TString& name) const 
591   {
592     Option* o = Find(name);
593     if (!o) return false;
594     return o->AsBool();
595   }
596   /** 
597    * Return value of an option as an integer
598    * 
599    * @param name Name of option 
600    * @param def  Default value if options isn't found 
601    * 
602    * @return Value or default value 
603    */
604   Int_t AsInt(const TString& name, Int_t def=0) const
605   {
606     Option* o = Find(name);
607     if (!o) return def;
608     return o->AsInt();
609   }
610   /** 
611    * Return value of an option as an integer
612    * 
613    * @param name Name of option 
614    * @param def  Default value if options isn't found 
615    * 
616    * @return Value or default value 
617    */
618   Long64_t AsLong(const TString& name, Long64_t def=0) const
619   {
620     Option* o = Find(name);
621     if (!o) return def;
622     return o->AsLong();
623   }
624   /** 
625    * Return value of an option as a double precision real number
626    * 
627    * @param name Name of option 
628    * @param def  Default value if options isn't found 
629    * 
630    * @return Value or default value 
631    */
632   Double_t AsDouble(const TString& name, Double_t def=0) const
633   {
634     Option* o = Find(name);
635     if (!o) return def;
636     return o->AsDouble();
637   }
638   /** 
639    * Set value using a format statement 
640    * 
641    * @param name   Name of option.
642    * @param format Format statement
643    */
644   void SetF(const TString& name, const Char_t* format, ...)
645   {
646     Option* o = Find(name);
647     if (!o) return;
648     
649     static char buf[1024];
650     va_list ap;
651     
652     va_start(ap, format);
653     vsnprintf(buf, 1023, format, ap);
654     buf[1023] = '\0';
655     va_end(ap);
656     
657     o->Set(buf);
658   }
659   /** 
660    * Set an option
661    * 
662    * @param name   Name of option
663    * @param value  Value of option
664    */
665   void Set(const TString& name, const TString& value)
666   {
667     Option* o = Find(name);
668     if (!o) return;
669     o->Set(value);
670   }
671   /** 
672    * Set a flag 
673    * 
674    * @param name Name of flag 
675    */
676   void Set(const TString& name)
677   {
678     Option* o = Find(name);
679     if (!o) return;
680     o->Set();
681   }   
682   /** 
683    * Set long integer value 
684    * 
685    * @param name Name of option
686    * @param val  Value 
687    * @param asHex If true, interpret as hex 
688    */
689   void Set(const TString& name, Int_t val, Bool_t asHex=false)
690   {
691     if (asHex) Set(name, Form("0x%x", val));
692     else       Set(name, Form("%d", val));
693   }
694   /** 
695    * Set long integer value 
696    * 
697    * @param name Name of option
698    * @param val  Value 
699    * @param asHex If true, interpret as hex value 
700    */
701   void Set(const TString& name, Long64_t val, Bool_t asHex=false)
702   {
703     ULong64_t uval = val;
704     if (asHex) Set(name, Form("0x%llx", uval));
705     else       Set(name, Form("%lld", val));
706   }
707   /** 
708    * Set double precision floating point value 
709    * 
710    * @param name Name of option
711    * @param val  Value 
712    */
713   void Set(const TString& name, Double_t val) 
714   {
715     Set(name, Form("%lg", val));
716   }
717   /** 
718    * Parse the options given in tmp 
719    * 
720    * @param tmp     String to pass
721    * @param delims  Delimiters 
722    * 
723    * @return true on success 
724    */
725   Bool_t Parse(const TString& tmp, const TString& delims)
726   {
727     TObjArray* opts = tmp.Tokenize(delims);
728     // Info("OptionList::Parse", "Parsing options %s", tmp.Data());
729     Bool_t ret = Parse(opts);
730     opts->Delete();
731     return ret;
732   }
733   /** 
734    * Parse options given in a collection 
735    * 
736    * @param opts List of arguments 
737    * @param ignoreUnknown If true, ignore unknown options 
738    * 
739    * @return true on success
740    */
741   Bool_t Parse(const TCollection* opts, Bool_t ignoreUnknown=false)
742   {
743     // Info("OptionList::Parse", "List of options");
744     // opts->ls();
745     TIter       next(opts);
746     TObjString* o = 0;
747     while ((o = static_cast<TObjString*>(next()))) { 
748       TString& s   = o->String();
749       TString  key = s;
750       TString  val = "";
751       Int_t    eq  = s.Index("=");
752       if (eq != kNPOS) {
753         key = s(0, eq);
754         val = s(eq+1, s.Length()-eq-1);
755       }
756
757       // Info("OptionList::Parse", "Looking for key=%s", key.Data());
758       Option*  opt = Find(key);
759       if (!opt) { 
760         if (!ignoreUnknown)
761           Warning("OptionList::Parse", "Unknown option: \"%s\"", s.Data());
762         continue;
763       }
764       if (opt->HasArg() && val.IsNull()) { 
765         Warning("OptionList::Parse", 
766                 "Option %s needs an argument, using default %s", 
767                 key.Data(), opt->fValue.Data());
768         val = opt->fValue;
769         // return false;
770       }
771       opt->Set(val);
772     }
773     return true;
774   }
775   /** 
776    * Find the widest name and dummy argument
777    * 
778    * @param nWidth On return, the largest width of option names 
779    * @param aWidth On return, the largest width of option dummy args
780    */
781   void Widest(Int_t& nWidth, Int_t& aWidth) const 
782   {
783     nWidth = 0;
784     aWidth = 0;
785     const Link* cur = fList;
786     while (cur) { 
787       Option* opt = cur->fThis;
788       nWidth = TMath::Max(nWidth, opt->NameWidth());
789       aWidth = TMath::Max(aWidth, opt->ArgWidth());
790       cur = cur->fNext;
791     }
792
793     // while ((opt = static_cast<Option*>(next()))) {
794     // }
795   }
796   /** 
797    * Display option help
798    * 
799    * @param o Output stream 
800    * @param prefix Prefix for each option.
801    */
802   void Help(std::ostream& o, const char* prefix="  ") const 
803   {
804     Int_t nWidth, aWidth;
805     Widest(nWidth, aWidth);
806     if (aWidth > 0) nWidth += aWidth+1;
807
808     const Link* cur = fList;
809     while (cur) { 
810       Option* opt = cur->fThis;
811       o << prefix;
812       opt->Help(o, nWidth);
813       cur = cur->fNext;
814     }
815   }
816   /** 
817    * Show the values of options 
818    * 
819    * @param o Output stream
820    * @param prefix Prefix for each option
821    */
822   void Show(std::ostream& o, const char* prefix="  ") const 
823   {
824     Int_t nWidth, aWidth;
825     Widest(nWidth, aWidth);
826
827
828     const Link* cur = fList;
829     while (cur) { 
830       Option* opt = cur->fThis;
831       o << prefix;
832       opt->Show(o, nWidth);
833       cur = cur->fNext;
834     }
835   }
836   /** 
837    * Show the values of options 
838    * 
839    * @param o Output stream
840    * @param prefix Prefix for each option
841    * @param delim Delimters 
842    * @param quote Quote output 
843    * @param onlySet if true, only output set options 
844    */
845   void Store(std::ostream& o, const char* prefix="", 
846              const char* delim=",", bool quote=true, 
847              bool onlySet=false) const 
848   {
849     Int_t nWidth, aWidth;
850     Widest(nWidth, aWidth);
851
852     const Link* cur = fList;
853     while (cur) { 
854       Option* opt = cur->fThis;
855       if ((!opt->HasArg() || onlySet) && !opt->IsSet()) {
856         cur = cur->fNext;
857         continue;
858       }
859       o << prefix;
860       opt->Store(o, quote);
861       o << delim;
862       cur = cur->fNext;
863     }
864   }
865   // Our linked list
866   Link* fList;
867
868   static void Test(const char* opts="")
869   {
870     OptionList l;
871     l.Add("int", "NUMBER", "Integer", "42");
872     l.Add("float", "NUMBER", "Floating point", "3.14");
873     l.Add("bool", "Flag");
874     l.Add("hex", "NUMBER", "Hexadecimal", "0xdead");
875     l.Add("string", "STRING", "A string", "Hello, world");
876     l.Show(std::cout, "\t");
877     
878     std::cout << "Find" << std::endl;
879     Option* b = l.Find("bool");
880     b->Set("true");
881     b->Show(std::cout);
882
883     std::cout << "SetF" << std::endl;
884     l.SetF("float", "%f", 2.17);
885     l.Show(std::cout, "\t");
886     
887     std::cout << "GetF" << std::endl;
888     Float_t f;
889     l.GetF("float", "%f", &f);
890     std::cout << "\tf=" << f << std::endl;
891     std::cout << "Remove" << std::endl;
892     l.Remove("float");
893     l.Show(std::cout, "\t");
894
895     std::cout << "Set" << std::endl;
896     l.Set("int", "10");
897     l.Set("hex", 0xbeef, true);
898     l.Set("bool", "false");
899     l.Show(std::cout, "\t");
900
901     std::cout << "Copy" << std::endl;
902     OptionList c(l);
903     c.Show(std::cout, "\t");
904
905     std::cout << "Parse" << std::endl;
906     c.Parse(opts,",");
907     c.Show(std::cout, "\t");
908     std::cout << "End of test" << std::endl;
909   }
910   // TList fList;
911 };
912
913 #endif
914