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