Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
simix: inline a function
[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 XBT_PUBLIC(bool) parseBool(const char* value);
25 XBT_PUBLIC(double) parseDouble(const char* value);
26 XBT_PUBLIC(long int) parseLong(const char* value);
27
28 template<class T> struct parse_option {
29   static inline T parse(const char* value)
30   {
31     return T(value);
32   }
33 };
34
35 template<> struct parse_option<std::string> {
36   static inline std::string parse(const char* value)
37   {
38     return std::string(value);
39   }
40 };
41
42 template<>
43 struct parse_option<double> {
44   static inline double parse(const char* value)
45   {
46     return parseDouble(value);
47   }
48 };
49
50 template<>
51 struct parse_option<int> {
52   static inline double parse(const char* value)
53   {
54     return parseLong(value);
55   }
56 };
57
58 template<>
59 struct parse_option<bool> {
60   static inline bool parse(const char* value)
61   {
62     return parseBool(value);
63   }
64 };
65
66 template<class T> inline
67 T parse(const char* value)
68 {
69   return parse_option<T>::parse(value);
70 }
71
72 template<class T> inline
73 std::string to_string(T&& value)
74 {
75   return std::to_string(std::forward<T>(value));
76 }
77 inline std::string const& to_string(std::string& value)
78 {
79   return value;
80 }
81 inline std::string const& to_string(std::string const& value)
82 {
83   return value;
84 }
85 inline std::string to_string(std::string&& value)
86 {
87   return std::move(value);
88 }
89
90 // Register:
91
92 /** Register a configuration flag
93  *
94  *  @param name        name of the option
95  *  @param description Description of the option
96  *  @param callback    called with the option value
97  */
98 XBT_PUBLIC(void) declareFlag(const char* name, const char* description,
99   std::function<void(const char* value)> callback);
100
101 template<class T, class F>
102 void declareFlag(const char* name, const char* description, F callback)
103 {
104   declareFlag(name, description, [callback](const char* value) {
105     callback(parse<T>(value));
106   });
107 }
108
109 /** Bind a variable to configuration flag
110  *
111  *  @param value Bound variable
112  *  @param name  Flag name
113  *  @param description Option description
114  */
115 template<class T>
116 void bindFlag(T& value, const char* name, const char* description)
117 {
118   using namespace std;
119   declareFlag(name, description, [&value](const char* val) {
120     value = simgrid::config::parse<T>(val);
121   });
122   xbt_cfg_setdefault_string(name, simgrid::config::to_string(value).c_str());
123 }
124
125 /** Bind a variable to configuration flag
126  *
127  *  <pre><code>
128  *  static int x;
129  *  simgrid::config::bindFlag(a, "x", [](const char* value) {
130  *    return simgrid::config::parse(value);
131  *  }
132  *  </pre><code>
133  */
134 // F is a parser, F : const char* -> T
135 template<class T, class F>
136 typename std::enable_if<std::is_same<
137   T,
138   typename std::remove_cv< decltype(
139     std::declval<F>()(std::declval<const char*>())
140   ) >::type
141 >::value, void>::type
142 bindFlag(T& value, const char* name, const char* description,
143   F callback)
144 {
145   declareFlag(name, description, [&value,callback](const char* val) {
146     value = callback(val);
147   });
148   xbt_cfg_setdefault_string(name, to_string(value).c_str());
149 }
150
151 /** Bind a variable to configuration flag
152  *
153  *  <pre><code>
154  *  static int x;
155  *  simgrid::config::bindFlag(a, "x", [](int x) {
156  *    if (x < x_min || x => x_max)
157  *      throw std::range_error("must be in [x_min, x_max)")
158  *  });
159  *  </pre><code>
160  */
161 // F is a checker, F : T& -> ()
162 template<class T, class F>
163 typename std::enable_if<std::is_same<
164   void,
165   decltype( std::declval<F>()(std::declval<const T&>()) )
166 >::value, void>::type
167 bindFlag(T& value, const char* name, const char* description,
168   F callback)
169 {
170   declareFlag(name, description, [&value,callback](const char* val) {
171     T res = parse<T>(val);
172     callback(res);
173     value = std::move(res);
174   });
175   xbt_cfg_setdefault_string(name, to_string(value).c_str());
176 }
177
178 /** Bind a variable to configuration flag
179  *
180  *  <pre><code>
181  *  static int x;
182  *  simgrid::config::bindFlag(a, "x", [](int x) { return return x > 0; });
183  *  </pre><code>
184  */
185 // F is a predicate, F : T const& -> bool
186 template<class T, class F>
187 typename std::enable_if<std::is_same<
188   bool,
189   decltype( std::declval<F>()(std::declval<const T&>()) )
190 >::value, void>::type
191 bindFlag(T& value, const char* name, const char* description,
192   F callback)
193 {
194   declareFlag(name, description, [&value,callback](const char* val) {
195     T res = parse<T>(val);
196     if (!callback(res))
197       throw std::range_error("invalid value");
198     value = std::move(res);
199   });
200   xbt_cfg_setdefault_string(name, to_string(value).c_str());
201 }
202
203 /** A variable bound to a CLI option
204  *
205  *  <pre><code>
206  *  static simgrid::config::flag<int> answer("answer", "Expected answer", 42);
207  *  static simgrid::config::flag<std::string> name("name", "Ford Prefect", "John Doe");
208  *  static simgrid::config::flag<double> gamma("gamma", "Gamma factor", 1.987);
209  *  </code></pre>
210  */
211 template<class T>
212 class Flag {
213   T value_;
214 public:
215
216   /** Constructor
217    *
218    *  @param name  Flag name
219    *  @param desc  Flag description
220    *  @param value Flag initial/default value
221    */
222   Flag(const char* name, const char* desc, T value) : value_(value)
223   {
224     simgrid::config::bindFlag(value_, name, desc);
225   }
226
227   template<class F>
228   Flag(const char* name, const char* desc, T value, F callback) : value_(value)
229   {
230     simgrid::config::bindFlag(value_, name, desc, std::move(callback));
231   }
232
233   // No copy:
234   Flag(Flag const&) = delete;
235   Flag& operator=(Flag const&) = delete;
236
237   // Get the underlying value:
238   T& get() { return value_; }
239   T const& get() const { return value_; }
240
241   // Implicit conversion to the underlying type:
242   operator T&() { return value_; }
243   operator T const&() const{ return value_; }
244
245   // Basic interop with T:
246   Flag& operator=(T const& that) { value_ = that; return *this; }
247   Flag& operator=(T && that)     { value_ = that; return *this; }
248   bool operator==(T const& that) const { return value_ == that; }
249   bool operator!=(T const& that) const { return value_ != that; }
250   bool operator<(T const& that) const { return value_ < that; }
251   bool operator>(T const& that) const { return value_ > that; }
252   bool operator<=(T const& that) const { return value_ <= that; }
253   bool operator>=(T const& that) const { return value_ >= that; }
254 };
255
256 }
257 }
258
259 #endif