monotone

monotone Mtn Source Tree

Root/option.hh

1#ifndef __OPTION_HH__
2#define __OPTION_HH__
3
4#include <stdexcept>
5#include <map>
6#include <set>
7#include "vector.hh"
8
9#include <boost/function.hpp>
10#include "lexical_cast.hh"
11
12#include "sanity.hh"
13#include "vocab.hh"
14
15// The types to represent the command line's parameters.
16class arg_type : public utf8 {
17public:
18 explicit arg_type(void) : utf8() {}
19 explicit arg_type(std::string const & s) : utf8(s) {}
20 explicit arg_type(utf8 const & u) : utf8(u) {}
21};
22template <>
23inline void dump(arg_type const & a, std::string & out) { out = a(); }
24typedef std::vector< arg_type > args_vector;
25
26namespace option {
27 // Base for errors thrown by this code.
28 struct option_error : public std::invalid_argument
29 {
30 option_error(std::string const & str);
31 };
32 struct unknown_option : public option_error
33 {
34 unknown_option(std::string const & opt);
35 };
36 struct missing_arg : public option_error
37 {
38 missing_arg(std::string const & opt);
39 };
40 // -ofoo or --opt=foo when the option doesn't take an argument
41 struct extra_arg : public option_error
42 {
43 extra_arg(std::string const & opt);
44 };
45 // thrown by from_command_line when setting an option fails
46 // by either boost::bad_lexical_cast or bad_arg_internal
47 struct bad_arg : public option_error
48 {
49 bad_arg(std::string const & opt, arg_type const & arg);
50 bad_arg(std::string const & opt,
51 arg_type const & arg,
52 std::string const & reason);
53 };
54 // from_command_line() catches this and boost::bad_lexical_cast
55 // and converts them to bad_arg exceptions
56 struct bad_arg_internal
57 {
58 std::string reason;
59 bad_arg_internal(std::string const & str = "");
60 };
61
62 // Split a "long,s" option name into long and short names.
63 void splitname(std::string const & from, std::string & name, std::string & n);
64
65 // An option that can be set and reset.
66 struct concrete_option
67 {
68 std::string description;
69 std::string longname;
70 std::string shortname;
71 bool has_arg;
72 boost::function<void (std::string)> setter;
73 boost::function<void ()> resetter;
74
75 concrete_option();
76 concrete_option(std::string const & names,
77 std::string const & desc,
78 bool arg,
79 boost::function<void (std::string)> set,
80 boost::function<void ()> reset);
81
82 bool operator<(concrete_option const & other) const;
83 };
84
85 // A group of options, which can be set from a command line
86 // and can produce a usage string.
87 struct concrete_option_set
88 {
89 std::set<concrete_option> options;
90 concrete_option_set();
91 concrete_option_set(std::set<concrete_option> const & other);
92 concrete_option_set(concrete_option const & opt);
93
94 // for building a concret_option_set directly (as done in unit_tests.cc),
95 // rather than using intermediate machinery like in options*
96 concrete_option_set &
97 operator()(std::string const & names,
98 std::string const & desc,
99 boost::function<void ()> set,
100 boost::function<void ()> reset = 0);
101 concrete_option_set &
102 operator()(std::string const & names,
103 std::string const & desc,
104 boost::function<void (std::string)> set,
105 boost::function<void ()> reset = 0);
106
107 concrete_option_set operator | (concrete_option_set const & other) const;
108 void reset() const;
109 std::string get_usage_str() const;
110 void from_command_line(args_vector & args, bool allow_xargs = true);
111 void from_command_line(int argc, char const * const * argv);
112 void from_key_value_pairs(std::vector<std::pair<std::string, std::string> > const & keyvals);
113 };
114 concrete_option_set
115 operator | (concrete_option const & a, concrete_option const & b);
116
117 // used by the setter() functions below
118 template<typename T>
119 struct setter_class
120 {
121 T & item;
122 setter_class(T & i)
123 : item(i)
124 {}
125 void operator()(std::string s)
126 {
127 item = boost::lexical_cast<T>(s);
128 }
129 };
130 template<>
131 struct setter_class<bool>
132 {
133 bool & item;
134 setter_class(bool & i)
135 : item(i)
136 {}
137 void operator()()
138 {
139 item = true;
140 }
141 };
142 template<typename T>
143 struct setter_class<std::vector<T> >
144 {
145 std::vector<T> & items;
146 setter_class(std::vector<T> & i)
147 : items(i)
148 {}
149 void operator()(std::string s)
150 {
151 items.push_back(boost::lexical_cast<T>(s));
152 }
153 };
154 template<typename T>
155 struct resetter_class
156 {
157 T & item;
158 T value;
159 resetter_class(T & i, T const & v)
160 : item(i), value(v)
161 {}
162 void operator()()
163 {
164 item = value;
165 }
166 };
167
168 // convenience functions to generate a setter for a var
169 template<typename T> inline
170 boost::function<void(std::string)> setter(T & item)
171 {
172 return setter_class<T>(item);
173 }
174 inline boost::function<void()> setter(bool & item)
175 {
176 return setter_class<bool>(item);
177 }
178 // convenience function to generate a resetter for a var
179 template<typename T> inline
180 boost::function<void()> resetter(T & item, T const & value = T())
181 {
182 return resetter_class<T>(item, value);
183 }
184
185 // because std::bind1st can't handle producing a nullary functor
186 template<typename T>
187 struct binder_only
188 {
189 T * obj;
190 boost::function<void(T*)> fun;
191 binder_only(boost::function<void(T*)> const & f, T * o)
192 : obj(o), fun(f)
193 {}
194 void operator()()
195 {
196 fun(obj);
197 }
198 };
199
200 // Options that need to be attached to some other object
201 // in order for set and reset to be meaningful.
202 template<typename T>
203 struct option
204 {
205 std::string description;
206 std::string names;
207 bool has_arg;
208 boost::function<void (T*, std::string)> setter;
209 boost::function<void (T*)> resetter;
210
211 option(std::string const & name,
212 std::string const & desc,
213 bool arg,
214 void(T::*set)(std::string),
215 void(T::*reset)())
216 {
217 I(!name.empty() || !desc.empty());
218 description = desc;
219 names = name;
220 has_arg = arg;
221 setter = set;
222 resetter = reset;
223 }
224
225 concrete_option instantiate(T * obj) const
226 {
227 concrete_option out;
228 out.description = description;
229 splitname(names, out.longname, out.shortname);
230 out.has_arg = has_arg;
231
232 if (setter)
233out.setter = std::bind1st(setter, obj);
234 if (resetter)
235out.resetter = binder_only<T>(resetter, obj);
236 return out;
237 }
238
239 bool operator<(option const & other) const
240 {
241 if (names != other.names)
242 return names < other.names;
243 return description < other.description;
244 }
245 };
246
247 // A group of unattached options, which can be given an object
248 // to attach themselves to.
249 template<typename T>
250 struct option_set
251 {
252 std::set<option<T> > options;
253 option_set(){}
254 option_set(option_set<T> const & other)
255 : options(other.options)
256 {}
257 option_set(option<T> const & opt)
258 {
259 options.insert(opt);
260 }
261
262 option_set(std::string const & name,
263 std::string const & desc,
264 bool arg,
265 void(T::*set)(std::string),
266 void(T::*reset)())
267 {
268 options.insert(option<T>(name, desc, arg, set, reset));
269 }
270 concrete_option_set instantiate(T * obj) const
271 {
272 std::set<concrete_option> out;
273 for (typename std::set<option<T> >::const_iterator i = options.begin();
274 i != options.end(); ++i)
275out.insert(i->instantiate(obj));
276 return out;
277 }
278 option_set<T> operator | (option_set<T> const & other) const
279 {
280 option_set<T> combined;
281 std::set_union(options.begin(), options.end(),
282 other.options.begin(), other.options.end(),
283 std::inserter(combined.options, combined.options.begin()));
284 return combined;
285 }
286 option_set<T> operator - (option_set<T> const & other) const
287 {
288 option_set<T> combined;
289 std::set_difference(options.begin(), options.end(),
290 other.options.begin(), other.options.end(),
291 std::inserter(combined.options,
292 combined.options.begin()));
293 return combined;
294 }
295 bool empty() const {return options.empty();}
296 };
297 template<typename T>
298 option_set<T>
299 operator | (option<T> const & a, option<T> const & b)
300 {
301 return option_set<T>(a) | b;
302 }
303
304}
305
306
307#endif
308
309// Local Variables:
310// mode: C++
311// fill-column: 76
312// c-file-style: "gnu"
313// indent-tabs-mode: nil
314// End:
315// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s:

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status