vSMC
vSMC: Scalable Monte Carlo
program_option.hpp
Go to the documentation of this file.
1 //============================================================================
2 // vSMC/include/vsmc/utility/program_option.hpp
3 //----------------------------------------------------------------------------
4 // vSMC: Scalable Monte Carlo
5 //----------------------------------------------------------------------------
6 // Copyright (c) 2013-2016, Yan Zhou
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are met:
11 //
12 // Redistributions of source code must retain the above copyright notice,
13 // this list of conditions and the following disclaimer.
14 //
15 // Redistributions in binary form must reproduce the above copyright notice,
16 // this list of conditions and the following disclaimer in the documentation
17 // and/or other materials provided with the distribution.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
20 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 // POSSIBILITY OF SUCH DAMAGE.
30 //============================================================================
31 
32 #ifndef VSMC_UTILITY_PROGRAM_OPTION_HPP
33 #define VSMC_UTILITY_PROGRAM_OPTION_HPP
34 
35 #include <vsmc/internal/common.hpp>
36 
37 #define VSMC_RUNTIME_ASSERT_UTILITY_PROGRAM_OPTION_NULLPTR(ptr, func) \
38  VSMC_RUNTIME_ASSERT((ptr != nullptr), \
39  "**ProgramOption::" #func \
40  "** ATTEMPT TO SET OPTION WITH A NULL POINTER")
41 
42 namespace vsmc
43 {
44 
45 namespace internal
46 {
47 
48 inline void program_option_warning(const std::string &name,
49  const std::string &msg, bool silent, std::ostream &os)
50 {
51  if (silent)
52  return;
53 
54  os << "vSMC Program Option Warning\n";
55  os << "Option: --" << name << '\n';
56  os << "Message : " << msg << std::endl;
57 }
58 
59 } // namespace vsmc::internal
60 
64 {
65  public:
66  ProgramOption() = default;
67  ProgramOption(const ProgramOption &) = default;
68  ProgramOption &operator=(const ProgramOption &) = default;
69  virtual ~ProgramOption() {}
70 
71  virtual bool is_bool() const = 0;
72  virtual bool is_vector() const = 0;
73  virtual bool set(
74  const std::string &, const std::string &, bool, std::ostream &) = 0;
75  virtual bool set_default() = 0;
76  virtual std::string description() const = 0;
77  virtual std::string default_str() const = 0;
78 
79  protected:
80  bool set_value(const std::string &name, const std::string &sval,
81  bool *dest, bool silent, std::ostream &os)
82  {
83  const char *const sptr = sval.c_str();
84  const std::size_t size = sval.size();
85 
86  bool is_numb = true;
87  bool is_zero = true;
88  for (std::size_t i = 0; i != size; ++i) {
89  char c = sptr[i];
90  is_numb = is_numb && c >= '0' && c <= '9';
91  is_zero = is_zero && (c == '0');
92  }
93  if (is_zero) {
94  *dest = false;
95  return true;
96  } else if (is_numb) {
97  *dest = true;
98  return true;
99  }
100 
101  bool is_true = false;
102  is_true = is_true || std::strcmp(sptr, "y") == 0;
103  is_true = is_true || std::strcmp(sptr, "Y") == 0;
104  is_true = is_true || std::strcmp(sptr, "yes") == 0;
105  is_true = is_true || std::strcmp(sptr, "Yes") == 0;
106  is_true = is_true || std::strcmp(sptr, "YES") == 0;
107  is_true = is_true || std::strcmp(sptr, "t") == 0;
108  is_true = is_true || std::strcmp(sptr, "T") == 0;
109  is_true = is_true || std::strcmp(sptr, "true") == 0;
110  is_true = is_true || std::strcmp(sptr, "True") == 0;
111  is_true = is_true || std::strcmp(sptr, "TRUE") == 0;
112  if (is_true) {
113  *dest = true;
114  return true;
115  }
116 
117  bool is_false = false;
118  is_false = is_false || std::strcmp(sptr, "n") == 0;
119  is_false = is_false || std::strcmp(sptr, "N") == 0;
120  is_false = is_false || std::strcmp(sptr, "no") == 0;
121  is_false = is_false || std::strcmp(sptr, "No") == 0;
122  is_false = is_false || std::strcmp(sptr, "NO") == 0;
123  is_false = is_false || std::strcmp(sptr, "f") == 0;
124  is_false = is_false || std::strcmp(sptr, "F") == 0;
125  is_false = is_false || std::strcmp(sptr, "false") == 0;
126  is_false = is_false || std::strcmp(sptr, "False") == 0;
127  is_false = is_false || std::strcmp(sptr, "FALSE") == 0;
128  if (is_false) {
129  *dest = false;
130  return true;
131  }
132 
134  name, "Failed to set value: " + sval, silent, os);
135  return false;
136  }
137 
138  bool set_value(const std::string &, const std::string &sval,
139  std::string *dest, bool, std::ostream &)
140  {
141  *dest = sval;
142 
143  return true;
144  }
145 
146  template <typename T>
147  bool set_value(const std::string &name, const std::string &sval, T *dest,
148  bool silent, std::ostream &os)
149  {
150  std::stringstream ss;
151  ss.str(sval);
152  T tval;
153  ss >> tval;
154  if (ss.fail()) {
156  name, "Failed to set value: " + sval, silent, os);
157  ss.clear();
158  return false;
159  }
160  *dest = std::move(tval);
161 
162  return true;
163  }
164 }; // class ProgramOption
165 
169 {
170  public:
171  ProgramOptionHelp() : help_(false) {}
172 
173  bool is_bool() const { return true; }
174 
175  bool is_vector() const { return false; }
176 
177  bool set(const std::string &name, const std::string &sval, bool silent,
178  std::ostream &os)
179  {
180  return set_value(name, sval, &help_, silent, os);
181  }
182 
183  bool set_default() { return false; }
184 
185  std::string description() const
186  {
187  return std::string("Print this help information");
188  }
189 
190  std::string default_str() const { return std::string("(false)"); }
191 
192  bool help() const { return help_; }
193 
194  private:
195  bool help_;
196 }; // ProgramOptionHelp
197 
200 template <typename T>
202 {
203  public:
204  ProgramOptionDefault(const std::string &desc)
205  : desc_(desc), default_(T()), has_default_(false)
206  {
207  }
208 
209  template <typename V>
210  ProgramOptionDefault(const std::string &desc, V val)
211  : desc_(desc), default_(static_cast<T>(val)), has_default_(true)
212  {
213  }
214 
215  bool is_bool() const { return std::is_same<T, bool>::value; }
216 
217  std::string description() const { return desc_; }
218 
219  std::string default_str() const
220  {
221  return has_default_ ? default_val2str(default_) : std::string();
222  }
223 
224  protected:
225  bool set_value_default(T *dest)
226  {
227  if (has_default_)
228  *dest = default_;
229 
230  return has_default_;
231  }
232 
233  private:
234  std::string desc_;
235  T default_;
236  bool has_default_;
237 
238  template <typename U>
239  std::string default_val2str(const U &val) const
240  {
241  std::stringstream ss;
242  ss << '(' << val << ')';
243 
244  return ss.str();
245  }
246 
247  std::string default_val2str(bool val) const
248  {
249  return val ? std::string("(true)") : std::string("(false)");
250  }
251 }; // ProgramOptionDefault
252 
255 template <typename T>
257 {
258  public:
259  ProgramOptionScalar(const std::string &desc, T *ptr)
260  : ProgramOptionDefault<T>(desc), ptr_(ptr)
261  {
262  }
263 
264  template <typename V>
265  ProgramOptionScalar(const std::string &desc, T *ptr, V val)
266  : ProgramOptionDefault<T>(desc, val), ptr_(ptr)
267  {
268  }
269 
270  bool is_vector() const { return false; }
271 
272  bool set(const std::string &name, const std::string &sval, bool silent,
273  std::ostream &os)
274  {
275  return this->set_value(name, sval, ptr_, silent, os);
276  }
277 
278  bool set_default() { return this->set_value_default(ptr_); }
279 
280  private:
281  T *const ptr_;
282 }; // class ProgramOptionScalar
283 
286 template <typename T>
288 {
289  public:
290  ProgramOptionVector(const std::string &desc, std::vector<T> *ptr)
291  : ProgramOptionDefault<T>(desc), ptr_(ptr)
292  {
293  }
294 
295  template <typename V>
296  ProgramOptionVector(const std::string &desc, std::vector<T> *ptr, V val)
297  : ProgramOptionDefault<T>(desc, val), ptr_(ptr)
298  {
299  }
300 
301  bool is_vector() const { return true; }
302 
303  bool set(const std::string &name, const std::string &sval, bool silent,
304  std::ostream &os)
305  {
306  T val;
307  bool success = this->set_value(name, sval, &val, silent, os);
308  if (success)
309  ptr_->push_back(val);
310 
311  return success;
312  }
313 
314  bool set_default()
315  {
316  T val;
317  bool success = this->set_value_default(&val);
318  if (success)
319  ptr_->push_back(val);
320 
321  return success;
322  }
323 
324  private:
325  std::vector<T> *const ptr_;
326 }; // class ProgramOptionVector
327 
331 {
332  public:
333  explicit ProgramOptionMap(bool silent = false)
334  : silent_(silent), help_ptr_(std::make_shared<ProgramOptionHelp>())
335  {
336  add_option("help", help_ptr_);
337  }
338 
345  template <typename T>
347  const std::string &name, const std::string &desc, T *ptr)
348  {
350 
351  return add_option(
352  name, std::make_shared<ProgramOptionScalar<T>>(desc, ptr));
353  }
354 
356  template <typename T, typename V>
358  const std::string &name, const std::string &desc, T *ptr, V val)
359  {
361 
362  return add_option(
363  name, std::make_shared<ProgramOptionScalar<T>>(desc, ptr, val));
364  }
365 
367  template <typename T>
369  const std::string &name, const std::string &desc, std::vector<T> *ptr)
370  {
372 
373  return add_option(
374  name, std::make_shared<ProgramOptionVector<T>>(desc, ptr));
375  }
376 
378  template <typename T, typename V>
379  ProgramOptionMap &add(const std::string &name, const std::string &desc,
380  std::vector<T> *ptr, V val)
381  {
383 
384  return add_option(
385  name, std::make_shared<ProgramOptionVector<T>>(desc, ptr, val));
386  }
387 
388  ProgramOptionMap &remove(const std::string &name)
389  {
390  auto iter = option_find(name);
391  if (iter != option_vec_.end())
392  option_vec_.erase(iter);
393 
394  return *this;
395  }
396 
407  void process(int argc, const char **argv, std::ostream &os = std::cout)
408  {
409  std::string arg;
410  Vector<std::string> arg_vector;
411  arg_vector.reserve(static_cast<std::size_t>(argc));
412  for (int i = 0; i != argc; ++i) {
413  arg = process_arg(argv[i]);
414  if (!arg.empty())
415  arg_vector.push_back(arg);
416  }
417  process_arg_vector(arg_vector, os);
418  }
419 
421  void process(int argc, char **argv, std::ostream &os = std::cout)
422  {
423  std::string arg;
424  Vector<std::string> arg_vector;
425  arg_vector.reserve(static_cast<std::size_t>(argc));
426  for (int i = 0; i != argc; ++i) {
427  arg = process_arg(argv[i]);
428  if (!arg.empty())
429  arg_vector.push_back(arg);
430  }
431  process_arg_vector(arg_vector, os);
432  }
433 
435  void print_help(std::ostream &os = std::cout) const
436  {
437  std::size_t len[2] = {0, 0};
438  Vector<std::string> str[3];
439  for (const auto &option : option_vec_) {
440  str[0].push_back("--" + std::get<0>(option));
441  str[1].push_back(std::get<1>(option)->description());
442  str[2].push_back(std::get<1>(option)->default_str());
443  len[0] = std::max(len[0], str[0].back().size());
444  len[1] = std::max(len[1], str[1].back().size());
445  }
446  len[0] += 4;
447  len[1] += 4;
448  for (std::size_t i = 0; i != str[0].size(); ++i) {
449  os << str[0][i] << std::string(len[0] - str[0][i].size(), ' ');
450  os << str[1][i] << std::string(len[1] - str[1][i].size(), ' ');
451  os << str[2][i] << std::endl;
452  }
453  }
454 
456  std::size_t count(const std::string &name) const
457  {
458  auto iter = option_find(name);
459  if (iter != option_vec_.end())
460  return std::get<2>(*iter);
461  return 0;
462  }
463 
465  bool help() { return help_ptr_->help(); }
466 
468  std::shared_ptr<ProgramOption> option(const std::string &name)
469  {
470  auto iter = option_find(name);
471  if (iter != option_vec_.end())
472  return std::get<1>(*iter);
473  return std::shared_ptr<ProgramOption>(
474  static_cast<ProgramOption *>(nullptr));
475  }
476 
478  std::shared_ptr<const ProgramOption> option(const std::string &name) const
479  {
480  auto iter = option_find(name);
481  if (iter != option_vec_.end())
482  return std::get<1>(*iter);
483  return std::shared_ptr<const ProgramOption>(
484  static_cast<const ProgramOption *>(nullptr));
485  }
486 
489  void silent(bool flag) { silent_ = flag; }
490 
491  private:
492  using option_vec_type = Vector<
493  std::tuple<std::string, std::shared_ptr<ProgramOption>, std::size_t>>;
494 
495  bool silent_;
496  std::shared_ptr<ProgramOptionHelp> help_ptr_;
497  option_vec_type option_vec_;
498 
499  option_vec_type::iterator option_find(const std::string &name)
500  {
501  auto iter = option_vec_.begin();
502  for (; iter != option_vec_.end(); ++iter)
503  if (std::get<0>(*iter) == name)
504  break;
505 
506  return iter;
507  }
508 
509  option_vec_type::const_iterator option_find(const std::string &name) const
510  {
511  auto iter = option_vec_.begin();
512  for (; iter != option_vec_.end(); ++iter)
513  if (std::get<0>(*iter) == name)
514  break;
515 
516  return iter;
517  }
518 
519  ProgramOptionMap &add_option(
520  const std::string &name, std::shared_ptr<ProgramOption> optr)
521  {
522  auto option = std::make_tuple(name, optr, 0);
523  auto iter = option_find(name);
524  if (iter != option_vec_.end())
525  *iter = option;
526  else
527  option_vec_.push_back(option);
528 
529  return *this;
530  }
531 
532  void process_arg_vector(
533  std::vector<std::string> &arg_vector, std::ostream &os)
534  {
536  Vector<std::string> svals;
537  auto aiter = arg_vector.begin();
538  while (aiter != arg_vector.end() && !is_option(*aiter))
539  ++aiter;
540  while (aiter != arg_vector.end()) {
541  std::string name(aiter->begin() + 2, aiter->end());
542  ++aiter;
543  svals.clear();
544  while (aiter != arg_vector.end() && !is_option(*aiter)) {
545  svals.push_back(*aiter);
546  ++aiter;
547  }
548  name_svals.push_back(std::make_pair(name, svals));
549  }
550 
551  const std::string sval_true("1");
552  for (auto &nsv : name_svals) {
553  auto iter = option_find(nsv.first);
554  if (iter == option_vec_.end()) {
556  nsv.first, "Unknown option", silent_, os);
557  continue;
558  }
559 
560  bool proc = false;
561  if (nsv.second.size() == 0 && std::get<1>(*iter)->is_bool()) {
562  proc = process_option(iter, sval_true, os);
563  } else if (nsv.second.size() == 0) {
565  nsv.first, "No value found", silent_, os);
566  } else if (std::get<1>(*iter)->is_vector()) {
567  for (const auto &sval : nsv.second)
568  proc = process_option(iter, sval, os);
569  } else {
570  proc = process_option(iter, nsv.second.back(), os) || proc;
571  }
572  if (proc)
573  ++std::get<2>(*iter);
574  }
575 
576  for (auto &option : option_vec_)
577  if (std::get<2>(option) == 0)
578  if (std::get<1>(option)->set_default())
579  std::get<2>(option) = 1;
580 
581  if (help())
582  print_help(os);
583  }
584 
585  std::string process_arg(const char *arg) const
586  {
587  std::size_t s = std::strlen(arg);
588  std::size_t e = s;
589  while (e != 0 && (arg[e - 1] == ' ' || arg[e - 1] == ','))
590  --e;
591 
592  return std::string(arg, arg + e);
593  }
594 
595  bool process_option(option_vec_type::iterator iter,
596  const std::string &sval, std::ostream &os)
597  {
598  if (sval.empty()) {
600  std::get<0>(*iter), "No value found", silent_, os);
601  return false;
602  }
603  return std::get<1>(*iter)->set(std::get<0>(*iter), sval, silent_, os);
604  }
605 
606  bool is_option(const std::string &str) const
607  {
608  if (str.size() < 3)
609  return false;
610 
611  if (str[0] != '-')
612  return false;
613 
614  if (str[1] != '-')
615  return false;
616 
617  return true;
618  }
619 }; // class ProgramOptionMap
620 
621 } // namespace vsmc
622 
623 #endif // VSMC_UTILITY_PROGRAM_OPTION_HPP
Definition: monitor.hpp:49
typename std::conditional< std::is_scalar< T >::value, AlignedVector< T >, std::vector< T >>::type Vector
AlignedVector for scalar type and std::vector for others.
std::string default_str() const
ProgramOptionMap & add(const std::string &name, const std::string &desc, T *ptr)
Add an option with a single value.
bool set_value(const std::string &, const std::string &sval, std::string *dest, bool, std::ostream &)
ProgramOptionDefault(const std::string &desc)
STL namespace.
#define VSMC_RUNTIME_ASSERT_UTILITY_PROGRAM_OPTION_NULLPTR(ptr, func)
std::string description() const
std::shared_ptr< ProgramOption > option(const std::string &name)
Get the underlying option object.
void silent(bool flag)
Set the silent flag, if true, no warning messages will be printed for unknown options etc...
void process(int argc, const char **argv, std::ostream &os=std::cout)
Process the options.
ProgramOptionScalar(const std::string &desc, T *ptr)
ProgramOptionScalar(const std::string &desc, T *ptr, V val)
bool set_value(const std::string &name, const std::string &sval, bool *dest, bool silent, std::ostream &os)
void program_option_warning(const std::string &name, const std::string &msg, bool silent, std::ostream &os)
std::shared_ptr< const ProgramOption > option(const std::string &name) const
Get the underlying option object.
ProgramOptionDefault(const std::string &desc, V val)
ProgramOptionVector(const std::string &desc, std::vector< T > *ptr)
bool help()
If the "help" option is processed and set to true.
Option with multiple values.
Option base class.
Option with a single value.
ProgramOptionMap & add(const std::string &name, const std::string &desc, std::vector< T > *ptr, V val)
Add an option with multiple value, with a default value.
std::string default_str() const
void print_help(std::ostream &os=std::cout) const
Print help information for each option.
ProgramOptionMap & add(const std::string &name, const std::string &desc, std::vector< T > *ptr)
Add an option with multiple value.
void process(int argc, char **argv, std::ostream &os=std::cout)
Process the options.
Option with a default value.
std::size_t count(const std::string &name) const
Count the number of successful processing of an option.
void add(std::size_t n, const float *a, const float *b, float *y)
Definition: vmath.hpp:109
ProgramOptionMap & add(const std::string &name, const std::string &desc, T *ptr, V val)
Add an option with a single value, with a default value.
ProgramOptionVector(const std::string &desc, std::vector< T > *ptr, V val)
bool set_value(const std::string &name, const std::string &sval, T *dest, bool silent, std::ostream &os)
ProgramOptionMap(bool silent=false)
std::string description() const