Code forensics  0.1
Generate historical information about code changes
cli_options.hpp
Go to the documentation of this file.
1 #ifndef CLI_OPTIONS_HPP
2 #define CLI_OPTIONS_HPP
3 
4 #include <common.hpp>
5 #include "program_state.hpp"
6 #include <boost/program_options.hpp>
7 #include <boost/describe.hpp>
8 #include <boost/describe/enum_to_string.hpp>
9 #include <boost/describe/enum_from_string.hpp>
10 #include <boost/describe/operators.hpp>
11 #include <boost/function.hpp>
12 #include <boost/bind.hpp>
13 #include <boost/lambda/lambda.hpp>
14 #include <boost/unordered_map.hpp>
15 #include <fstream>
16 
19  std::size_t operator()(std::type_info const& t) const {
20  return t.hash_code();
21  }
22 };
23 
25 struct equal_ref {
26  template <typename T>
27  bool operator()(
28  boost::reference_wrapper<T> a,
29  boost::reference_wrapper<T> b) const {
30  return a.get() == b.get();
31  }
32 };
33 
34 
36 struct any_visitor {
37  boost::unordered_map<
38  boost::reference_wrapper<std::type_info const>,
39  boost::function<void(boost::any&)>,
41  equal_ref>
42  fs;
43 
45  template <typename T>
46  static T any_cast_f(boost::any& any) {
47  return boost::any_cast<T>(any);
48  }
49 
51  template <typename T>
52  void insert_visitor(boost::function<void(T)> f) {
53  try {
54  fs.insert(std::make_pair(
55  boost::ref(typeid(T)),
56  boost::bind(
57  f, boost::bind(any_cast_f<T>, boost::lambda::_1))));
58  } catch (boost::bad_any_cast& e) {
59  std::cout << e.what() << std::endl;
60  }
61  }
62 
66  inline bool operator()(boost::any& x) const {
67  auto it = fs.find(boost::ref(x.type()));
68  if (it != fs.end()) {
69  it->second(x);
70  return true;
71  } else {
72  return false;
73  }
74  }
75 };
76 
77 namespace po = boost::program_options;
78 
80 template <IsDescribedEnum E>
81 class EnumOption {
82  public:
83  EnumOption(E in) : value(in) {}
84 
85  inline E get() const noexcept { return value; }
86 
87  private:
88  E value;
89 
90  BOOST_DESCRIBE_CLASS(EnumOption, (), (value), (), ());
91 };
92 
97 class bad_lexical_cast : public boost::bad_lexical_cast {
98  Str msg;
99 
100  public:
102  CR<std::type_info> S,
103  CR<std::type_info> T,
104  CR<Str> _msg)
105  : boost::bad_lexical_cast(S, T), msg(_msg) {}
106  inline const char* what() const noexcept override {
107  // TODO use cxxabi and write out proper type conversion error
108  // message information - not only user-provided failure text
109  return strdup((msg).c_str());
110  }
111 
112  template <typename S, typename T>
113  static bad_lexical_cast init(CR<Str> msg) {
114  return bad_lexical_cast(typeid(S), typeid(T), msg);
115  }
116 };
117 
122 class validation_error : public po::validation_error {
123  Str msg;
124 
125  public:
127  inline validation_error(Str _msg)
128  : po::validation_error(po::validation_error::invalid_option)
129  , msg(_msg) {}
132  inline const char* what() const noexcept override {
133  return strdup(
134  (Str{po::validation_error::what()} + ": " + msg).c_str());
135  }
136 };
137 
138 namespace boost {
140 template <IsDescribedEnum E>
141 E lexical_cast(CR<Str> in) {
142  E result;
143  if (bd::enum_from_string<E>(in.c_str(), result)) {
144  return result;
145  } else {
146  throw ::bad_lexical_cast::init<Str, E>(
147  std::string("Invalid enumerator name '") + in +
148  "' for enum type '" + typeid(E).name() + "'");
149  }
150 }
151 
153 template <IsDescribedEnum E>
154 Str lexical_cast(E in) {
155  return Str{bd::enum_to_string<E>(in)};
156 }
157 } // namespace boost
158 
160 template <typename E>
161 void validate(boost::any& v, CR<Vec<Str>> xs, EnumOption<E>* opt, long) {}
162 
164 class BoolOption {
165  // https://stackoverflow.com/questions/51723237/boostprogram-options-bool-switch-used-multiple-times
166  // bool options is taken from this SO question - it is not /exactly/
167  // what I aimed for, but this solution allows specifying =true or
168  // =false on the command line explicitly, which I aimed for
169  public:
170  inline BoolOption(bool initialState = false) : state(initialState) {}
171  inline bool getState() const { return state; }
173  inline void switchState() { state = !state; }
176  operator bool() const { return state; }
177 
178  private:
179  bool state;
180 };
181 
182 
184 template <IsDescribedEnum E>
185 void validate(boost::any& v, CR<Vec<Str>> xs, EnumOption<E>*, long) {
186  try {
187  v = EnumOption<E>(boost::lexical_cast<E>(xs[0]));
188  } catch (CR<boost::bad_lexical_cast> err) {
189  throw validation_error(err.what());
190  }
191 }
192 
193 po::variables_map parse_cmdline(int argc, const char** argv);
194 
195 
197  CR<any_visitor> visitor,
198  std::ostream& out,
199  const po::variables_map vm);
200 
201 #endif // CLI_OPTIONS_HPP
bad_lexical_cast::what
const char * what() const noexcept override
Definition: cli_options.hpp:106
equal_ref
Compare reference wrappers for equality.
Definition: cli_options.hpp:25
EnumOption
enum
Definition: cli_options.hpp:81
any_visitor::fs
boost::unordered_map< boost::reference_wrapper< std::type_info const >, boost::function< void(boost::any &)>, type_info_hash, equal_ref > fs
Definition: cli_options.hpp:42
EnumOption::EnumOption
EnumOption(E in)
Definition: cli_options.hpp:83
BoolOption::state
bool state
Definition: cli_options.hpp:179
boost
Definition: cli_options.cpp:7
parse_cmdline
po::variables_map parse_cmdline(int argc, const char **argv)
Definition: cli_options.cpp:116
equal_ref::operator()
bool operator()(boost::reference_wrapper< T > a, boost::reference_wrapper< T > b) const
Definition: cli_options.hpp:27
validation_error::msg
Str msg
Stored user message.
Definition: cli_options.hpp:123
EnumOption::BOOST_DESCRIBE_CLASS
BOOST_DESCRIBE_CLASS(EnumOption,(),(value),(),())
BoolOption::BoolOption
BoolOption(bool initialState=false)
Definition: cli_options.hpp:170
print_variables_map
void print_variables_map(CR< any_visitor > visitor, std::ostream &out, const po::variables_map vm)
Definition: cli_options.cpp:32
validation_error::validation_error
validation_error(Str _msg)
create validation error with 'invalid option' state
Definition: cli_options.hpp:127
bad_lexical_cast::init
static bad_lexical_cast init(CR< Str > msg)
Definition: cli_options.hpp:113
validate
void validate(boost::any &v, CR< Vec< Str >> xs, EnumOption< E > *opt, long)
unparse input enum option into the stored value
Definition: cli_options.hpp:161
any_visitor::operator()
bool operator()(boost::any &x) const
try to call any of the stored oeprators with provided
Definition: cli_options.hpp:66
validation_error::what
const char * what() const noexcept override
get error message description, returning baseline one concatenated with the user-provdede elaboration
Definition: cli_options.hpp:132
bad_lexical_cast::bad_lexical_cast
bad_lexical_cast(CR< std::type_info > S, CR< std::type_info > T, CR< Str > _msg)
Definition: cli_options.hpp:101
any_visitor::insert_visitor
void insert_visitor(boost::function< void(T)> f)
add visitor for the specified mapping
Definition: cli_options.hpp:52
any_visitor::any_cast_f
static T any_cast_f(boost::any &any)
Convert 'any' value to specified type.
Definition: cli_options.hpp:46
any_visitor
boost::any visitor helper
Definition: cli_options.hpp:36
EnumOption::value
E value
Definition: cli_options.hpp:88
type_info_hash::operator()
std::size_t operator()(std::type_info const &t) const
Definition: cli_options.hpp:19
boost::lexical_cast
E lexical_cast(CR< Str > in)
lexical cast overload for 'described' enums
Definition: cli_options.hpp:141
BoolOption
specify boolean true/false flags on the boost command line
Definition: cli_options.hpp:164
program_state.hpp
Main code analysis state and configuration classes.
EnumOption::get
E get() const noexcept
Definition: cli_options.hpp:85
BoolOption::getState
bool getState() const
Definition: cli_options.hpp:171
BoolOption::switchState
void switchState()
toggle stored state
Definition: cli_options.hpp:173
bad_lexical_cast::msg
Str msg
Definition: cli_options.hpp:98
type_info_hash
Has typeinfo information for type-implementation mapping.
Definition: cli_options.hpp:18