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