Logo AND Algorithmique Numérique Distribuée

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