Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'master' of scm.gforge.inria.fr:/gitroot/simgrid/simgrid
[simgrid.git] / include / xbt / config.hpp
1 /* Copyright (c) 2016. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #ifndef _XBT_CONFIG_HPP_
8 #define _XBT_CONFIG_HPP_
9
10 #include <cstdlib>
11
12 #include <functional>
13 #include <stdexcept>
14 #include <string>
15 #include <type_traits>
16 #include <utility>
17
18 #include <xbt/base.h>
19 #include <xbt/config.h>
20
21 namespace simgrid {
22 namespace config {
23
24 template<class T> inline
25 std::string to_string(T&& value)
26 {
27   return std::to_string(std::forward<T>(value));
28 }
29 inline std::string const& to_string(std::string& value)
30 {
31   return value;
32 }
33 inline std::string const& to_string(std::string const& value)
34 {
35   return value;
36 }
37 inline std::string to_string(std::string&& value)
38 {
39   return std::move(value);
40 }
41
42 // Get config
43
44 template<class T>
45 XBT_PUBLIC(T const&) getConfig(const char* name);
46
47 extern template XBT_PUBLIC(int const&) getConfig<int>(const char* name);
48 extern template XBT_PUBLIC(double const&) getConfig<double>(const char* name);
49 extern template XBT_PUBLIC(bool const&) getConfig<bool>(const char* name);
50 extern template XBT_PUBLIC(std::string const&) getConfig<std::string>(const char* name);
51
52 // Register:
53
54 /** Register a configuration flag
55  *
56  *  @param name        name of the option
57  *  @param description Description of the option
58  *  @param value       Initial/default value
59  *  @param callback    called with the option value
60  */
61 template<class T>
62 XBT_PUBLIC(void) declareFlag(const char* name, const char* description,
63   T value, std::function<void(const T&)> callback = std::function<void(const T&)>());
64
65 extern template XBT_PUBLIC(void) declareFlag(const char* name,
66   const char* description, int value, std::function<void(int const &)> callback);
67 extern template XBT_PUBLIC(void) declareFlag(const char* name,
68   const char* description, double value, std::function<void(double const &)> callback);
69 extern template XBT_PUBLIC(void) declareFlag(const char* name,
70   const char* description, bool value, std::function<void(bool const &)> callback);
71 extern template XBT_PUBLIC(void) declareFlag(const char* name,
72   const char* description, std::string value, std::function<void(std::string const &)> callback);
73
74 /** Bind a variable to configuration flag
75  *
76  *  @param value Bound variable
77  *  @param name  Flag name
78  *  @param description Option description
79  */
80 template<class T>
81 void bindFlag(T& value, const char* name, const char* description)
82 {
83   using namespace std;
84   declareFlag<T>(name, description, value, [&value](T const& val) {
85     value = val;
86   });
87 }
88
89 /** Bind a variable to configuration flag
90  *
91  *  <pre><code>
92  *  static int x;
93  *  simgrid::config::bindFlag(a, "x", [](const char* value) {
94  *    return simgrid::config::parse(value);
95  *  }
96  *  </pre><code>
97  */
98 // F is a parser, F : const char* -> T
99 template<class T, class F>
100 typename std::enable_if<std::is_same<
101   T,
102   typename std::remove_cv< decltype(
103     std::declval<F>()(std::declval<const char*>())
104   ) >::type
105 >::value, void>::type
106 bindFlag(T& value, const char* name, const char* description,
107   F callback)
108 {
109   declareFlag(name, description, value, [&value,callback](const char* val) {
110     value = callback(val);
111   });
112 }
113
114 /** Bind a variable to configuration flag
115  *
116  *  <pre><code>
117  *  static int x;
118  *  simgrid::config::bindFlag(a, "x", [](int x) {
119  *    if (x < x_min || x => x_max)
120  *      throw std::range_error("must be in [x_min, x_max)")
121  *  });
122  *  </pre><code>
123  */
124 // F is a checker, F : T& -> ()
125 template<class T, class F>
126 typename std::enable_if<std::is_same<
127   void,
128   decltype( std::declval<F>()(std::declval<const T&>()) )
129 >::value, void>::type
130 bindFlag(T& value, const char* name, const char* description,
131   F callback)
132 {
133   declareFlag(name, description, value, [&value,callback](const T& val) {
134     callback(val);
135     value = std::move(val);
136   });
137 }
138
139 /** Bind a variable to configuration flag
140  *
141  *  <pre><code>
142  *  static int x;
143  *  simgrid::config::bindFlag(a, "x", [](int x) { return return x > 0; });
144  *  </pre><code>
145  */
146 // F is a predicate, F : T const& -> bool
147 template<class T, class F>
148 typename std::enable_if<std::is_same<
149   bool,
150   decltype( std::declval<F>()(std::declval<const T&>()) )
151 >::value, void>::type
152 bindFlag(T& value, const char* name, const char* description,
153   F callback)
154 {
155   declareFlag(name, description, value, [&value,callback](const T& val) {
156     if (!callback(val))
157       throw std::range_error("invalid value");
158     value = std::move(val);
159   });
160 }
161
162 /** A variable bound to a CLI option
163  *
164  *  <pre><code>
165  *  static simgrid::config::flag<int> answer("answer", "Expected answer", 42);
166  *  static simgrid::config::flag<std::string> name("name", "Ford Prefect", "John Doe");
167  *  static simgrid::config::flag<double> gamma("gamma", "Gamma factor", 1.987);
168  *  </code></pre>
169  */
170 template<class T>
171 class Flag {
172   T value_;
173 public:
174
175   /** Constructor
176    *
177    *  @param name  Flag name
178    *  @param desc  Flag description
179    *  @param value Flag initial/default value
180    */
181   Flag(const char* name, const char* desc, T value) : value_(value)
182   {
183     simgrid::config::bindFlag(value_, name, desc);
184   }
185
186   template<class F>
187   Flag(const char* name, const char* desc, T value, F callback) : value_(value)
188   {
189     simgrid::config::bindFlag(value_, name, desc, std::move(callback));
190   }
191
192   // No copy:
193   Flag(Flag const&) = delete;
194   Flag& operator=(Flag const&) = delete;
195
196   // Get the underlying value:
197   T& get() { return value_; }
198   T const& get() const { return value_; }
199
200   // Implicit conversion to the underlying type:
201   operator T&() { return value_; }
202   operator T const&() const{ return value_; }
203
204   // Basic interop with T:
205   Flag& operator=(T const& that) { value_ = that; return *this; }
206   Flag& operator=(T && that)     { value_ = that; return *this; }
207   bool operator==(T const& that) const { return value_ == that; }
208   bool operator!=(T const& that) const { return value_ != that; }
209   bool operator<(T const& that) const { return value_ < that; }
210   bool operator>(T const& that) const { return value_ > that; }
211   bool operator<=(T const& that) const { return value_ <= that; }
212   bool operator>=(T const& that) const { return value_ >= that; }
213 };
214
215 }
216 }
217
218 #endif