inicpp
C++ parser of INI files with schema validation.
option.h
1 #ifndef INICPP_OPTION_H
2 #define INICPP_OPTION_H
3 
4 #include <cctype>
5 #include <iostream>
6 #include <memory>
7 #include <vector>
8 
9 #include "dll.h"
10 #include "exception.h"
11 #include "option_schema.h"
12 #include "string_utils.h"
13 #include "types.h"
14 #include "types.h"
15 
16 
17 namespace inicpp
18 {
20  class option_schema;
21 
22 
28  {
29  public:
33  virtual ~option_holder()
34  {
35  }
36  };
37 
38 
43  template <typename ValueType> class option_value : public option_holder
44  {
45  public:
50  option_value(ValueType value) : value_(value)
51  {
52  }
56  virtual ~option_value()
57  {
58  }
59 
64  ValueType get()
65  {
66  return value_;
67  }
72  void set(ValueType value)
73  {
74  value_ = value;
75  }
76 
77  private:
79  ValueType value_;
80  };
81 
82 
87  namespace
88  {
95  template <typename ActualType, typename ReturnType> class convertor
96  {
97  public:
105  static ReturnType get_converted_value(const std::unique_ptr<option_holder> &value)
106  {
107  option_value<ActualType> *ptr = dynamic_cast<option_value<ActualType> *>(&*value);
108  if (ptr == nullptr) {
109  throw bad_cast_exception("Cannot cast to requested type");
110  }
111  try {
112  return static_cast<ReturnType>(ptr->get());
113  } catch (std::runtime_error &e) {
114  throw bad_cast_exception(e.what());
115  }
116  }
117  };
118 
122  template <typename ActualType> class convertor<ActualType, string_ini_t>
123  {
124  public:
125  static string_ini_t get_converted_value(const std::unique_ptr<option_holder> &value)
126  {
127  option_value<ActualType> *ptr = dynamic_cast<option_value<ActualType> *>(&*value);
128  if (ptr == nullptr) {
129  throw bad_cast_exception("Cannot cast to requested type");
130  }
131  return inistd::to_string(ptr->get());
132  }
133  };
134  } // anonymous namespace
135 
141  class INICPP_API option
142  {
143  private:
145  std::string name_;
147  option_type type_;
149  std::vector<std::unique_ptr<option_holder>> values_;
151  std::shared_ptr<option_schema> option_schema_;
152 
154  template <typename ValueType> void copy_option(const std::unique_ptr<option_holder> &opt)
155  {
156  option_value<ValueType> *ptr = dynamic_cast<option_value<ValueType> *>(&*opt);
157  auto new_option_value = std::make_unique<option_value<ValueType>>(ptr->get());
158  values_.push_back(std::move(new_option_value));
159  }
160 
162  template <typename ValueType>
163  bool compare_option(
164  const std::unique_ptr<option_holder> &local, const std::unique_ptr<option_holder> &remote) const
165  {
166  option_value<ValueType> *loc = dynamic_cast<option_value<ValueType> *>(&*local);
167  option_value<ValueType> *rem = dynamic_cast<option_value<ValueType> *>(&*remote);
168  return loc->get() == rem->get();
169  }
170 
171  template <typename ReturnType>
172  ReturnType convert_single_value(option_type source_type, const std::unique_ptr<option_holder> &value) const
173  {
174  switch (source_type) {
175  case option_type::boolean_e: return convertor<boolean_ini_t, ReturnType>::get_converted_value(value); break;
176  case option_type::enum_e: return convertor<enum_ini_t, ReturnType>::get_converted_value(value); break;
177  case option_type::float_e: return convertor<float_ini_t, ReturnType>::get_converted_value(value); break;
178  case option_type::signed_e: return convertor<signed_ini_t, ReturnType>::get_converted_value(value); break;
179  case option_type::string_e: {
180  option_value<string_ini_t> *ptr = dynamic_cast<option_value<string_ini_t> *>(&*value);
181  if (ptr == nullptr) {
182  throw bad_cast_exception("Cannot cast to requested type");
183  }
184 
185  // We have string, so try to parse it
186  try {
187  return string_utils::parse_string<ReturnType>(ptr->get(), get_name());
188  } catch (invalid_type_exception &e) {
189  throw bad_cast_exception(e.what());
190  }
191  } break;
192  case option_type::unsigned_e:
193  return convertor<unsigned_ini_t, ReturnType>::get_converted_value(value);
194  break;
195  case option_type::invalid_e:
196  default:
197  // never reached
198  throw invalid_type_exception("Invalid option type");
199  break;
200  }
201  }
202 
203  public:
207  option() = delete;
211  option(const option &source);
215  option &operator=(const option &source);
219  option(option &&source);
223  option &operator=(option &&source);
224 
230  option(const std::string &name, const std::string &value = "");
236  option(const std::string &name, const std::vector<std::string> &values);
237 
242  const std::string &get_name() const;
243 
248  option_type get_type() const;
253  bool is_list() const;
254 
261  template <typename ValueType> void set(ValueType value)
262  {
263  this->operator=(value);
264  }
270  option &operator=(boolean_ini_t arg);
276  option &operator=(signed_ini_t arg);
282  option &operator=(unsigned_ini_t arg);
288  option &operator=(float_ini_t arg);
294  option &operator=(const char *arg);
300  option &operator=(string_ini_t arg);
306  option &operator=(enum_ini_t arg);
307 
315  template <typename ReturnType> ReturnType get() const
316  {
317  if (values_.empty()) {
318  throw not_found_exception(0);
319  }
320 
321  // Get the value and try to convert it
322  return convert_single_value<ReturnType>(type_, values_[0]);
323  }
324 
333  template <typename ValueType> void set_list(const std::vector<ValueType> &list)
334  {
335  values_.clear();
336  type_ = get_option_enum_type<ValueType>();
337  for (const auto &item : list) {
338  add_to_list(item);
339  }
340  }
341 
350  template <typename ReturnType> std::vector<ReturnType> get_list() const
351  {
352  if (values_.empty()) {
353  throw not_found_exception(0);
354  }
355  std::vector<ReturnType> results;
356  for (const auto &value : values_) {
357  results.push_back(convert_single_value<ReturnType>(type_, value));
358  }
359 
360  return results;
361  }
362 
369  template <typename ValueType> void add_to_list(ValueType value)
370  {
371  if (get_option_enum_type<ValueType>() != type_) {
372  throw bad_cast_exception("Cannot cast to requested type");
373  }
374  auto new_option_value = std::make_unique<option_value<ValueType>>(value);
375  values_.push_back(std::move(new_option_value));
376  }
377 
386  template <typename ValueType> void add_to_list(ValueType value, size_t position)
387  {
388  if (get_option_enum_type<ValueType>() != type_) {
389  throw bad_cast_exception("Cannot cast to requested type");
390  }
391  if (position > values_.size()) {
392  throw not_found_exception(position);
393  }
394  auto new_option_value = std::make_unique<option_value<ValueType>>(value);
395  values_.insert(values_.begin() + position, std::move(new_option_value));
396  }
397 
403  template <typename ValueType> void remove_from_list(ValueType value)
404  {
405  if (get_option_enum_type<ValueType>() != type_) {
406  throw bad_cast_exception("Cannot cast to requested type");
407  }
408  for (auto it = values_.cbegin(); it != values_.cend(); ++it) {
409  option_value<ValueType> *ptr = dynamic_cast<option_value<ValueType> *>(&*(*it));
410  if (ptr->get() == value) {
411  values_.erase(it);
412  break;
413  }
414  }
415  }
416 
422  void remove_from_list_pos(size_t position);
423 
429  void validate(const option_schema &opt_schema);
430 
436  bool operator==(const option &other) const;
442  bool operator!=(const option &other) const;
443 
450  INICPP_API friend std::ostream &operator<<(std::ostream &os, const option &opt);
451  };
452 
453  INICPP_API std::ostream &operator<<(std::ostream &os, const option &opt);
454 }
455 
456 #endif
void add_to_list(ValueType value)
Definition: option.h:369
option_value(ValueType value)
Definition: option.h:50
ValueType get()
Definition: option.h:64
Definition: config.h:15
std::vector< ReturnType > get_list() const
Definition: option.h:350
void set_list(const std::vector< ValueType > &list)
Definition: option.h:333
void add_to_list(ValueType value, size_t position)
Definition: option.h:386
virtual ~option_holder()
Definition: option.h:33
void remove_from_list(ValueType value)
Definition: option.h:403
std::string to_string(const enum_ini_t &value)
virtual const char * what() const noexcept
Definition: exception.h:47
virtual ~option_value()
Definition: option.h:56