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-2015, 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  "**ProgramOptionMap::" #func \
40  "** ATTEMPT TO SET OPTION WITH A NULL POINTER")
41 
42 namespace vsmc
43 {
44 
47 inline void program_option_warning(const std::string &oname,
48  const std::string &msg, bool silent, std::ostream &os)
49 {
50  if (silent)
51  return;
52 
53  os << "vSMC Program Option Warning\n";
54  os << "Option: " << oname << '\n';
55  os << "Message : " << msg << std::endl;
56 }
57 
61 {
62  public:
65  ProgramOption &operator=(const ProgramOption &) { return *this; }
66  virtual ~ProgramOption() {}
67 
68  virtual bool is_bool() const = 0;
69  virtual bool is_vector() const = 0;
70  virtual bool set(
71  const std::string &, const std::string &, bool, std::ostream &) = 0;
72  virtual bool set_default() = 0;
73  virtual std::string description() const = 0;
74  virtual std::string default_str() const = 0;
75  virtual ProgramOption *clone() const = 0;
76 
77  protected:
78  bool set_value(const std::string &oname, const std::string &sval,
79  bool *dest, bool silent, std::ostream &os)
80  {
81  const char *const sptr = sval.c_str();
82  const std::size_t size = sval.size();
83 
84  bool is_numb = true;
85  bool is_zero = true;
86  for (std::size_t i = 0; i != size; ++i) {
87  char c = sptr[i];
88  is_numb = is_numb && c >= '0' && c <= '9';
89  is_zero = is_zero && (c == '0');
90  }
91  if (is_zero) {
92  *dest = false;
93  return true;
94  } else if (is_numb) {
95  *dest = true;
96  return true;
97  }
98 
99  bool is_true = false;
100  is_true = is_true || std::strcmp(sptr, "y") == 0;
101  is_true = is_true || std::strcmp(sptr, "Y") == 0;
102  is_true = is_true || std::strcmp(sptr, "yes") == 0;
103  is_true = is_true || std::strcmp(sptr, "Yes") == 0;
104  is_true = is_true || std::strcmp(sptr, "YES") == 0;
105  is_true = is_true || std::strcmp(sptr, "t") == 0;
106  is_true = is_true || std::strcmp(sptr, "T") == 0;
107  is_true = is_true || std::strcmp(sptr, "true") == 0;
108  is_true = is_true || std::strcmp(sptr, "True") == 0;
109  is_true = is_true || std::strcmp(sptr, "TRUE") == 0;
110  if (is_true) {
111  *dest = true;
112  return true;
113  }
114 
115  bool is_false = false;
116  is_false = is_false || std::strcmp(sptr, "n") == 0;
117  is_false = is_false || std::strcmp(sptr, "N") == 0;
118  is_false = is_false || std::strcmp(sptr, "no") == 0;
119  is_false = is_false || std::strcmp(sptr, "No") == 0;
120  is_false = is_false || std::strcmp(sptr, "NO") == 0;
121  is_false = is_false || std::strcmp(sptr, "f") == 0;
122  is_false = is_false || std::strcmp(sptr, "F") == 0;
123  is_false = is_false || std::strcmp(sptr, "false") == 0;
124  is_false = is_false || std::strcmp(sptr, "False") == 0;
125  is_false = is_false || std::strcmp(sptr, "FALSE") == 0;
126  if (is_false) {
127  *dest = false;
128  return true;
129  }
130 
132  oname, "Failed to set value: " + sval, silent, os);
133  return false;
134  }
135 
136  template <typename T>
137  bool set_value(const std::string &oname, const std::string &sval, T *dest,
138  bool silent, std::ostream &os)
139  {
140  std::stringstream ss;
141  ss.str(sval);
142  T tval;
143  ss >> tval;
144  if (ss.fail()) {
146  oname, "Failed to set value: " + sval, silent, os);
147  ss.clear();
148  return false;
149  }
150  *dest = std::move(tval);
151 
152  return true;
153  }
154 }; // class ProgramOption
155 
159 {
160  public:
161  ProgramOptionHelp() : help_(false) {}
162 
163  bool is_bool() const { return true; }
164 
165  bool is_vector() const { return false; }
166 
167  bool set(const std::string &oname, const std::string &sval, bool silent,
168  std::ostream &os)
169  {
170  return set_value(oname, sval, &help_, silent, os);
171  }
172 
173  bool set_default() { return false; }
174 
175  std::string description() const
176  {
177  return std::string("Print this help information");
178  }
179 
180  std::string default_str() const { return std::string("(false)"); }
181 
182  ProgramOption *clone() const { return new ProgramOptionHelp; }
183 
184  bool help() const { return help_; }
185 
186  private:
187  bool help_;
188 }; // ProgramOptionHelp
189 
192 template <typename T>
194 {
195  public:
196  ProgramOptionDefault(const std::string &desc)
197  : desc_(desc), default_(T()), has_default_(false)
198  {
199  }
200 
201  template <typename V>
202  ProgramOptionDefault(const std::string &desc, V val)
203  : desc_(desc), default_(static_cast<T>(val)), has_default_(true)
204  {
205  }
206 
207  bool is_bool() const { return std::is_same<T, bool>::value; }
208 
209  std::string description() const { return desc_; }
210 
211  std::string default_str() const
212  {
213  return has_default_ ? default_val2str(default_) : std::string();
214  }
215 
216  protected:
217  bool set_value_default(T *dest)
218  {
219  if (has_default_)
220  *dest = default_;
221 
222  return has_default_;
223  }
224 
225  private:
226  std::string desc_;
227  T default_;
228  bool has_default_;
229 
230  template <typename U>
231  std::string default_val2str(const U &val) const
232  {
233  std::stringstream ss;
234  ss << '(' << val << ')';
235 
236  return ss.str();
237  }
238 
239  std::string default_val2str(bool val) const
240  {
241  return val ? std::string("(true)") : std::string("(false)");
242  }
243 }; // ProgramOptionDefault
244 
247 template <typename T>
249 {
250  public:
251  ProgramOptionScalar(const std::string &desc, T *ptr)
252  : ProgramOptionDefault<T>(desc), ptr_(ptr)
253  {
254  }
255 
256  template <typename V>
257  ProgramOptionScalar(const std::string &desc, T *ptr, V val)
258  : ProgramOptionDefault<T>(desc, val), ptr_(ptr)
259  {
260  }
261 
262  bool is_vector() const { return false; }
263 
264  bool set(const std::string &oname, const std::string &sval, bool silent,
265  std::ostream &os)
266  {
267  return this->set_value(oname, sval, ptr_, silent, os);
268  }
269 
270  bool set_default() { return this->set_value_default(ptr_); }
271 
272  ProgramOption *clone() const { return new ProgramOptionScalar<T>(*this); }
273 
274  private:
275  T *const ptr_;
276 }; // class ProgramOptionScalar
277 
280 template <typename T>
282 {
283  public:
284  ProgramOptionVector(const std::string &desc, std::vector<T> *ptr)
285  : ProgramOptionDefault<T>(desc), val_(T()), ptr_(ptr)
286  {
287  }
288 
289  template <typename V>
290  ProgramOptionVector(const std::string &desc, std::vector<T> *ptr, V val)
291  : ProgramOptionDefault<T>(desc, val), val_(T()), ptr_(ptr)
292  {
293  }
294 
295  bool is_vector() const { return true; }
296 
297  bool set(const std::string &oname, const std::string &sval, bool silent,
298  std::ostream &os)
299  {
300  bool success = this->set_value(oname, sval, &val_, silent, os);
301 
302  if (success)
303  ptr_->push_back(val_);
304 
305  return success;
306  }
307 
308  bool set_default()
309  {
310  bool success = this->set_value_default(&val_);
311 
312  if (success)
313  ptr_->push_back(val_);
314 
315  return success;
316  }
317 
318  ProgramOption *clone() const { return new ProgramOptionVector<T>(*this); }
319 
320  private:
321  T val_;
322  std::vector<T> *const ptr_;
323 }; // class ProgramOptionVector
324 
328 {
329  using option_map_type =
330  std::map<std::string, std::pair<ProgramOption *, std::size_t>>;
331  using option_list_type =
332  std::list<std::pair<std::string, const ProgramOption *>>;
333 
334  public:
335  explicit ProgramOptionMap(bool silent = false, bool auto_help = true)
336  : silent_(silent)
337  , auto_help_(auto_help)
338  , help_ptr_(new ProgramOptionHelp)
339  {
340  option_map_["--help"] = std::make_pair(help_ptr_, 0);
341  option_list_.push_back(std::make_pair("--help", help_ptr_));
342  }
343 
345  : silent_(other.silent_)
346  , auto_help_(other.auto_help_)
347  , option_map_(other.option_map_)
348  , option_list_(other.option_list_)
349  {
350  for (option_map_type::iterator iter = option_map_.begin();
351  iter != option_map_.end(); ++iter) {
352  if (iter->second.first)
353  iter->second.first = iter->second.first->clone();
354  }
355  }
356 
358  {
359  if (this != &other) {
360  silent_ = other.silent_;
361  auto_help_ = other.auto_help_;
362  for (option_map_type::iterator iter = option_map_.begin();
363  iter != option_map_.end(); ++iter) {
364  if (iter->second.first)
365  delete iter->second.first;
366  }
367 
368  option_map_ = other.option_map_;
369  option_list_ = other.option_list_;
370 
371  for (option_map_type::iterator iter = option_map_.begin();
372  iter != option_map_.end(); ++iter) {
373  if (iter->second.first)
374  iter->second.first = iter->second.first->clone();
375  }
376  }
377 
378  return *this;
379  }
380 
382  : silent_(other.silent_)
383  , auto_help_(other.auto_help_)
384  , help_ptr_(other.help_ptr_)
385  , option_map_(std::move(other.option_map_))
386  , option_list_(std::move(other.option_list_))
387  {
388  other.help_ptr_ = nullptr;
389  other.option_map_.clear();
390  other.option_list_.clear();
391  }
392 
394  {
395  if (this != &other) {
396  silent_ = other.silent_;
397  help_ptr_ = other.help_ptr_;
398  option_map_ = std::move(other.option_map_);
399  option_list_ = std::move(other.option_list_);
400  other.help_ptr_ = nullptr;
401  other.option_map_.clear();
402  other.option_list_.clear();
403  }
404 
405  return *this;
406  }
407 
409  {
410  for (option_map_type::iterator iter = option_map_.begin();
411  iter != option_map_.end(); ++iter) {
412  if (iter->second.first != nullptr)
413  delete iter->second.first;
414  }
415  }
416 
423  template <typename T>
425  const std::string &name, const std::string &desc, T *ptr)
426  {
428  const std::string oname("--" + name);
429  ProgramOption *optr = new ProgramOptionScalar<T>(desc, ptr);
430  add_option(oname, optr);
431 
432  return *this;
433  }
434 
436  template <typename T, typename V>
438  const std::string &name, const std::string &desc, T *ptr, V val)
439  {
441  const std::string oname("--" + name);
442  ProgramOption *optr = new ProgramOptionScalar<T>(desc, ptr, val);
443  add_option(oname, optr);
444 
445  return *this;
446  }
447 
449  template <typename T>
451  const std::string &name, const std::string &desc, std::vector<T> *ptr)
452  {
454  const std::string oname("--" + name);
455  ProgramOption *optr = new ProgramOptionVector<T>(desc, ptr);
456  add_option(oname, optr);
457 
458  return *this;
459  }
460 
462  template <typename T, typename V>
463  ProgramOptionMap &add(const std::string &name, const std::string &desc,
464  std::vector<T> *ptr, V val)
465  {
467  const std::string oname("--" + name);
468  ProgramOption *optr = new ProgramOptionVector<T>(desc, ptr, val);
469  add_option(oname, optr);
470 
471  return *this;
472  }
473 
474  ProgramOptionMap &remove(const std::string &name)
475  {
476  const std::string oname("--" + name);
477  option_map_type::iterator iter = option_map_.find(oname);
478  if (iter != option_map_.end()) {
479  if (iter->second.first != nullptr)
480  delete iter->second.first;
481  option_map_.erase(iter);
482  option_list_type::iterator liter = option_list_find(oname);
483  option_list_.erase(liter);
484  }
485 
486  return *this;
487  }
488 
500  void process(int argc, const char **argv, std::ostream &os = std::cout)
501  {
502  std::string arg;
503  std::vector<std::string> arg_vector;
504  arg_vector.reserve(static_cast<std::size_t>(argc));
505  for (int i = 0; i != argc; ++i) {
506  arg = process_arg(argv[i]);
507  if (!arg.empty())
508  arg_vector.push_back(arg);
509  }
510  process_arg_vector(arg_vector, os);
511  }
512 
514  void process(int argc, char **argv, std::ostream &os = std::cout)
515  {
516  std::string arg;
517  std::vector<std::string> arg_vector;
518  arg_vector.reserve(static_cast<std::size_t>(argc));
519  for (int i = 0; i != argc; ++i) {
520  arg = process_arg(argv[i]);
521  if (!arg.empty())
522  arg_vector.push_back(arg);
523  }
524  process_arg_vector(arg_vector, os);
525  }
526 
528  void print_help(std::ostream &os = std::cout) const
529  {
530  std::size_t len[2] = {0, 0};
531  std::vector<std::string> vec[3];
532  for (option_list_type::const_iterator liter = option_list_.begin();
533  liter != option_list_.end(); ++liter) {
534  vec[0].push_back(liter->first);
535  vec[1].push_back(liter->second->description());
536  vec[2].push_back(liter->second->default_str());
537  if (len[0] < vec[0].back().size())
538  len[0] = vec[0].back().size();
539  if (len[1] < vec[1].back().size())
540  len[1] = vec[1].back().size();
541  }
542  len[0] += 4;
543  len[1] += 4;
544  for (std::size_t i = 0; i != vec[0].size(); ++i) {
545  os << vec[0][i] << std::string(len[0] - vec[0][i].size(), ' ');
546  os << vec[1][i] << std::string(len[1] - vec[1][i].size(), ' ');
547  os << vec[2][i] << std::endl;
548  }
549  }
550 
552  std::size_t count(const std::string &name) const
553  {
554  option_map_type::const_iterator iter = option_map_.find("--" + name);
555  if (iter != option_map_.end())
556  return iter->second.second;
557  else
558  return 0;
559  }
560 
562  const ProgramOption *option(const std::string &name) const
563  {
564  option_map_type::const_iterator iter = option_map_.find("--" + name);
565  if (iter != option_map_.end())
566  return iter->second.first;
567  else
568  return nullptr;
569  }
570 
572  ProgramOption *option(const std::string &name)
573  {
574  option_map_type::const_iterator iter = option_map_.find("--" + name);
575  if (iter != option_map_.end())
576  return iter->second.first;
577  else
578  return nullptr;
579  }
580 
583  void silent(bool flag) { silent_ = flag; }
584 
587  void auto_help(bool flag) { auto_help_ = flag; }
588 
589  private:
590  bool silent_;
591  bool auto_help_;
592  ProgramOptionHelp *help_ptr_;
593  option_map_type option_map_;
594  option_list_type option_list_;
595 
596  option_list_type::iterator option_list_find(const std::string &oname)
597  {
598  option_list_type::iterator liter = option_list_.begin();
599  for (; liter != option_list_.end(); ++liter) {
600  if (liter->first == oname)
601  break;
602  }
603 
604  return liter;
605  }
606 
607  void add_option(const std::string &oname, ProgramOption *optr)
608  {
609  std::pair<option_map_type::iterator, bool> insert =
610  option_map_.insert(std::make_pair(oname, std::make_pair(optr, 0)));
611  if (insert.second) {
612  option_list_.push_back(std::make_pair(oname, optr));
613  } else {
614  if (insert.first->second.first != nullptr)
615  delete insert.first->second.first;
616  insert.first->second.first = optr;
617  option_list_type::iterator liter = option_list_find(oname);
618  liter->second = optr;
619  }
620  }
621 
622  void process_arg_vector(
623  std::vector<std::string> &arg_vector, std::ostream &os)
624  {
625  std::string option_value;
626  const std::vector<std::string> option_value_vec;
627  std::vector<std::pair<std::string, std::vector<std::string>>>
628  option_vector;
629  std::vector<std::string>::iterator aiter = arg_vector.begin();
630  while (aiter != arg_vector.end() && !is_option(*aiter))
631  ++aiter;
632  while (aiter != arg_vector.end()) {
633  option_vector.push_back(std::make_pair(*aiter, option_value_vec));
634  std::vector<std::string> &value = option_vector.back().second;
635  ++aiter;
636  while (aiter != arg_vector.end() && !is_option(*aiter)) {
637  value.push_back(*aiter);
638  ++aiter;
639  }
640  }
641 
642  const std::string sval_true("1");
643  for (std::vector<std::pair<std::string,
644  std::vector<std::string>>>::iterator iter =
645  option_vector.begin();
646  iter != option_vector.end(); ++iter) {
647  option_map_type::iterator miter = option_map_.find(iter->first);
648  if (miter == option_map_.end()) {
650  iter->first, "Unknown option", silent_, os);
651  continue;
652  }
653 
654  bool proc = false;
655  const std::size_t vsize = iter->second.size();
656  if (vsize == 0 && miter->second.first->is_bool()) {
657  proc = process_option(miter, sval_true, os);
658  } else if (vsize == 0) {
660  miter->first, "Value not found", silent_, os);
661  } else if (!miter->second.first->is_vector()) {
662  option_value.clear();
663  for (std::size_t i = 0; i != vsize - 1; ++i)
664  option_value += iter->second[i] + ' ';
665  option_value += iter->second[vsize - 1];
666  proc = process_option(miter, option_value, os);
667  } else {
668  for (std::size_t i = 0; i != vsize; ++i)
669  proc = process_option(miter, iter->second[i], os) || proc;
670  }
671  if (proc)
672  ++miter->second.second;
673  }
674 
675  for (option_map_type::iterator iter = option_map_.begin();
676  iter != option_map_.end(); ++iter) {
677  if (iter->second.second == 0)
678  if (iter->second.first->set_default())
679  iter->second.second = 1;
680  }
681 
682  if (auto_help_ && help_ptr_->help())
683  print_help(os);
684  }
685 
686  std::string process_arg(const char *arg) const
687  {
688  std::size_t s = std::strlen(arg);
689  std::size_t e = s;
690  while (e != 0 && (arg[e - 1] == ' ' || arg[e - 1] == ','))
691  --e;
692 
693  return std::string(arg, arg + e);
694  }
695 
696  bool process_option(option_map_type::iterator iter,
697  const std::string &sval, std::ostream &os)
698  {
699  if (sval.empty()) {
700  program_option_warning(iter->first, "No value found", silent_, os);
701  return false;
702  }
703 
704  return iter->second.first->set(iter->first, sval, silent_, os);
705  }
706 
707  bool is_option(const std::string &str) const
708  {
709  if (str.size() < 3)
710  return false;
711 
712  if (str[0] != '-')
713  return false;
714 
715  if (str[1] != '-')
716  return false;
717 
718  return true;
719  }
720 }; // class ProgramOptionMap
721 
722 } // namespace vsmc
723 
724 #endif // VSMC_UTILITY_PROGRAM_OPTION_HPP
ProgramOption & operator=(const ProgramOption &)
Definition: monitor.hpp:49
virtual bool set_default()=0
ProgramOptionMap(bool silent=false, bool auto_help=true)
std::string default_str() const
virtual ProgramOption * clone() const =0
ProgramOption * option(const std::string &name)
Get the underlying option object.
ProgramOptionMap & add(const std::string &name, const std::string &desc, T *ptr)
Add an option with a single value.
A map of ProgramOption.
ProgramOptionMap & operator=(const ProgramOptionMap &other)
ProgramOptionDefault(const std::string &desc)
STL namespace.
ProgramOption * clone() const
#define VSMC_RUNTIME_ASSERT_UTILITY_PROGRAM_OPTION_NULLPTR(ptr, func)
std::string description() const
ProgramOption(const ProgramOption &)
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)
ProgramOptionMap & operator=(ProgramOptionMap &&other)
ProgramOptionDefault(const std::string &desc, V val)
ProgramOptionVector(const std::string &desc, std::vector< T > *ptr)
virtual bool is_bool() const =0
ProgramOption * clone() const
Option with multiple values.
void program_option_warning(const std::string &oname, const std::string &msg, bool silent, std::ostream &os)
Program option warning messages.
Program option base class.
ProgramOptionMap(const ProgramOptionMap &other)
bool set_value(const std::string &oname, const std::string &sval, bool *dest, bool silent, std::ostream &os)
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.
virtual bool is_vector() const =0
virtual std::string description() const =0
virtual std::string default_str() const =0
ProgramOption * clone() const
const ProgramOption * option(const std::string &name) const
Get the underlying option object.
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 &oname, const std::string &sval, T *dest, bool silent, std::ostream &os)
ProgramOptionMap(ProgramOptionMap &&other)
std::string description() const
void auto_help(bool flag)
Set the auto_help flag, if true, help information is printed automatically when the --help option is ...