MRPT  2.0.5
config/CConfigFileBase.h
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | https://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2020, Individual contributors, see AUTHORS file |
6  | See: https://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See: https://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 #pragma once
10 
11 #include <mrpt/core/bits_math.h> // .0_deg
12 #include <mrpt/core/exceptions.h>
13 #include <mrpt/system/string_utils.h> // tokenize
14 #include <string>
15 #include <type_traits>
16 #include <vector>
17 
18 namespace mrpt
19 {
20 // Frd decl:
21 namespace typemeta
22 {
23 template <typename ENUMTYPE>
24 struct TEnumType;
25 }
26 namespace config
27 {
28 // Frwd. decl:
29 class CConfigFilePrefixer;
30 
31 /** Default padding sizes for macros MRPT_SAVE_CONFIG_VAR_COMMENT(), etc. */
34 
35 /** This class allows loading and storing values and vectors of different types
36  * from a configuration text, which can be implemented as a ".ini" file, a
37  * memory-stored string, etc...
38  * This is a virtual class, use only as a pointer to an implementation of one
39  * of the derived classes.
40  *
41  * See: \ref config_file_format
42  * \ingroup mrpt_config_grp
43  */
45 {
46  friend class CConfigFilePrefixer;
47 
48  protected:
49  /** A virtual method to write a generic string.
50  */
51  virtual void writeString(
52  const std::string& section, const std::string& name,
53  const std::string& str) = 0;
54 
55  /** Write a generic string with optional padding and a comment field ("//
56  * ...") at the end of the line. */
57  void writeString(
58  const std::string& section, const std::string& name,
59  const std::string& str, const int name_padding_width,
60  const int value_padding_width, const std::string& comment);
61 
62  /** A virtual method to read a generic string.
63  * \exception std::exception If the key name is not found and
64  * "failIfNotFound" is true. Otherwise the "defaultValue" is returned. */
65  virtual std::string readString(
66  const std::string& section, const std::string& name,
67  const std::string& defaultStr, bool failIfNotFound = false) const = 0;
68 
69  public:
70  /** dtor */
71  virtual ~CConfigFileBase();
72 
73  /** Returns a list with all the section names. */
74  virtual void getAllSections(std::vector<std::string>& sections) const = 0;
75 
76  /** Returs a list with all the keys into a section */
77  virtual void getAllKeys(
78  const std::string& section, std::vector<std::string>& keys) const = 0;
79 
80  /** Checks if a given section exists (name is case insensitive)
81  * \sa keyExists() */
82  bool sectionExists(const std::string& section_name) const;
83 
84  /** Checks if a given key exists inside a section (case insensitive)
85  * \sa sectionExists() */
86  bool keyExists(const std::string& section, const std::string& key) const;
87 
88  /** Changes the contents of the virtual "config file" from a text block
89  * containing a YAML configuration text. Refer to unit test
90  * yaml2config_unittest.cpp for examples of use.
91  * \sa getContentAsYAML()
92  */
93  void setContentFromYAML(const std::string& yaml_block);
94 
95  /** Returns a text block representing the contents of the config file in
96  * YAML format.
97  * \sa setContentFromYAML()
98  */
99  std::string getContentAsYAML() const;
100 
101  /** Empties the "config file" */
102  virtual void clear() = 0;
103 
104  template <
105  typename enum_t,
106  typename = std::enable_if_t<std::is_enum<enum_t>::value>>
107  void write(
108  const std::string& section, const std::string& name, enum_t value,
109  const int name_padding_width = -1, const int value_padding_width = -1,
110  const std::string& comment = std::string())
111  {
112  this->write(
113  section, name, mrpt::typemeta::TEnumType<enum_t>::value2name(value),
114  name_padding_width, value_padding_width, comment);
115  }
116  /** @name Save a configuration parameter. Optionally pads with spaces up to
117  * the desired width in number of characters (-1: no fill), and add a final
118  * comment field at the end of the line (a "// " prefix is automatically
119  * inserted).
120  * @{ */
121  template <
122  typename data_t,
123  typename = std::enable_if_t<!std::is_enum<data_t>::value>>
124  void write(
125  const std::string& section, const std::string& name,
126  const data_t& value, const int name_padding_width = -1,
127  const int value_padding_width = -1,
128  const std::string& comment = std::string())
129  {
130  writeString(
131  section, name, mrpt::to_string(value), name_padding_width,
132  value_padding_width, comment);
133  }
134  template <typename data_t>
135  void write(
136  const std::string& section, const std::string& name,
137  const std::vector<data_t>& value, const int name_padding_width = -1,
138  const int value_padding_width = -1,
139  const std::string& comment = std::string())
140  {
141  std::string s;
142  for (typename std::vector<data_t>::const_iterator it = value.begin();
143  it != value.end(); ++it)
144  {
145  s += mrpt::to_string(*it);
146  s += " ";
147  }
148  writeString(
149  section, name, s, name_padding_width, value_padding_width, comment);
150  }
151  void write(
152  const std::string& section, const std::string& name, double value,
153  const int name_padding_width = -1, const int value_padding_width = -1,
154  const std::string& comment = std::string());
155  void write(
156  const std::string& section, const std::string& name, float value,
157  const int name_padding_width = -1, const int value_padding_width = -1,
158  const std::string& comment = std::string());
159 
160  /** @} */
161 
162  /** @name Read a configuration parameter, launching exception if key name is
163  * not found and `failIfNotFound`=true
164  * @{ */
165  double read_double(
166  const std::string& section, const std::string& name,
167  double defaultValue, bool failIfNotFound = false) const;
168  float read_float(
169  const std::string& section, const std::string& name, float defaultValue,
170  bool failIfNotFound = false) const;
171  bool read_bool(
172  const std::string& section, const std::string& name, bool defaultValue,
173  bool failIfNotFound = false) const;
174  int read_int(
175  const std::string& section, const std::string& name, int defaultValue,
176  bool failIfNotFound = false) const;
177  uint64_t read_uint64_t(
178  const std::string& section, const std::string& name,
179  uint64_t defaultValue, bool failIfNotFound = false) const;
180  std::string read_string(
181  const std::string& section, const std::string& name,
182  const std::string& defaultValue, bool failIfNotFound = false) const;
183  /** Reads a configuration parameter of type "string", and keeps only the
184  * first word (this can be used to eliminate possible comments at the end of
185  * the line) */
186  std::string read_string_first_word(
187  const std::string& section, const std::string& name,
188  const std::string& defaultValue, bool failIfNotFound = false) const;
189  /** Reads a configuration parameter of type vector, stored in the file as a
190  * string: "[v1 v2 v3 ... ]", where spaces could also be commas. \exception
191  * std::exception If the key name is not found and "failIfNotFound" is true.
192  * Otherwise the "defaultValue" is returned. */
193  template <class VECTOR_TYPE>
195  const std::string& section, const std::string& name,
196  const VECTOR_TYPE& defaultValue, VECTOR_TYPE& outValues,
197  bool failIfNotFound = false) const
198  {
199  std::string aux(readString(section, name, "", failIfNotFound));
200  // Parse the text into a vector:
201  std::vector<std::string> tokens;
202  mrpt::system::tokenize(aux, "[], \t", tokens);
203 
204  if (tokens.size() == 0)
205  {
206  outValues = defaultValue;
207  }
208  else
209  {
210  // Parse to numeric type:
211  const size_t N = tokens.size();
212  outValues.resize(N);
213  for (size_t i = 0; i < N; i++)
214  {
215  double val = std::stod(tokens[i]);
216  outValues[i] =
217  static_cast<typename VECTOR_TYPE::value_type>(val);
218  }
219  }
220  }
221 
222  /** Reads a configuration parameter as a matrix written in a matlab-like
223  * format - for example: "[2 3 4 ; 7 8 9]".
224  * This template method can be instantiated for matrices of the types: int,
225  * long, unsinged int, unsigned long, float, double, long double
226  * \exception std::exception If the key name is not found and
227  * "failIfNotFound" is true. Otherwise the "defaultValue" is returned.
228  */
229  template <class MATRIX_TYPE>
231  const std::string& section, const std::string& name,
232  MATRIX_TYPE& outMatrix,
233  const MATRIX_TYPE& defaultMatrix = MATRIX_TYPE(),
234  bool failIfNotFound = false) const
235  {
236  std::string aux = readString(section, name, "", failIfNotFound);
237  if (aux.empty())
238  outMatrix = defaultMatrix;
239  else
240  {
241  // Parse the text into a vector:
242  if (!outMatrix.fromMatlabStringFormat(aux))
243  THROW_EXCEPTION_FMT("Error parsing matrix: '%s'", aux.c_str());
244  }
245  }
246 
247  /** Reads an "enum" value, where the value in the config file can be either
248  * a numerical value or the symbolic name, for example:
249  * In the code:
250  * \code
251  * enum my_type_t { type_foo=0, type_bar };
252  * \endcode
253  * In the config file:
254  * \code
255  * [section]
256  * type = type_bar // Use the symbolic name, or
257  * type = 1 // use the numerical value (both lines will be
258  * equivalent)
259  * \endcode
260  * Which can be loaded with:
261  * \code
262  * cfgfile.read_enum<my_type_t>("section","type", type_foo );
263  * \endcode
264  *
265  * \note For an enum type to work with this template it is required that
266  * it defines a specialization of mrpt::typemeta::TEnumType
267  */
268  template <typename ENUMTYPE>
269  ENUMTYPE read_enum(
270  const std::string& section, const std::string& name,
271  const ENUMTYPE& defaultValue, bool failIfNotFound = false) const
272  {
273  MRPT_START
274  const std::string sVal =
275  read_string_first_word(section, name, "", failIfNotFound);
276  if (sVal.empty()) return defaultValue;
277  // Text or numeric value?
278  if (::isdigit(sVal[0]))
279  { // Seems a number:
280  return static_cast<ENUMTYPE>(::atoi(&sVal[0]));
281  }
282  else
283  { // Name look-up:
284  try
285  {
287  }
288  catch (std::exception&)
289  {
291  "Invalid value '%s' for enum type while reading key='%s'.",
292  sVal.c_str(), name.c_str());
293  }
294  }
295  MRPT_END
296  }
297  /** @} */
298 }; // End of class def.
299 
300 /** An useful macro for loading variables stored in a INI-like file under a key
301  * with the same name that the variable, and assigning the variable the current
302  * value if not found in the config file.
303  * The variableType must be the suffix of "read_XXX" functions, i.e. int,
304  * bool,...
305  */
306 #define MRPT_LOAD_CONFIG_VAR( \
307  variableName, variableType, configFileObject, sectionNameStr) \
308  { \
309  variableName = configFileObject.read_##variableType( \
310  sectionNameStr, #variableName, variableName); \
311  }
312 
313 /** Shortcut for MRPT_LOAD_CONFIG_VAR() for config file object named `c` and
314  * section string named `s` */
315 #define MRPT_LOAD_CONFIG_VAR_CS(variableName, variableType) \
316  MRPT_LOAD_CONFIG_VAR(variableName, variableType, c, s)
317 
318 /** Loads a double variable, stored as radians but entered in the INI-file as
319  * degrees */
320 #define MRPT_LOAD_CONFIG_VAR_DEGREES( \
321  variableName, configFileObject, sectionNameStr) \
322  { \
323  variableName = mrpt::DEG2RAD(configFileObject.read_double( \
324  sectionNameStr, #variableName, mrpt::RAD2DEG(variableName))); \
325  }
326 #define MRPT_LOAD_CONFIG_VAR_DEGREESf( \
327  variableName, configFileObject, sectionNameStr) \
328  { \
329  variableName = mrpt::DEG2RAD(configFileObject.read_float( \
330  sectionNameStr, #variableName, mrpt::RAD2DEG(variableName))); \
331  }
332 
333 /** Loads a double, required, variable, stored as radians but entered in the
334  * INI-file as degrees */
335 #define MRPT_LOAD_CONFIG_VAR_DEGREES_NO_DEFAULT( \
336  variableName, configFileObject, sectionNameStr) \
337  { \
338  variableName = mrpt::DEG2RAD(configFileObject.read_double( \
339  sectionNameStr, #variableName, mrpt::RAD2DEG(variableName), \
340  true)); \
341  }
342 
343 #define MRPT_LOAD_CONFIG_VAR_CAST( \
344  variableName, variableType, variableTypeCast, configFileObject, \
345  sectionNameStr) \
346  { \
347  variableName = static_cast<variableTypeCast>( \
348  configFileObject.read_##variableType( \
349  sectionNameStr, #variableName, variableName)); \
350  }
351 
352 #define MRPT_LOAD_HERE_CONFIG_VAR( \
353  variableName, variableType, targetVariable, configFileObject, \
354  sectionNameStr) \
355  targetVariable = configFileObject.read_##variableType( \
356  sectionNameStr, #variableName, targetVariable, false);
357 
358 #define MRPT_LOAD_HERE_CONFIG_VAR_NO_DEFAULT( \
359  variableName, variableType, targetVariable, configFileObject, \
360  sectionNameStr) \
361  { \
362  try \
363  { \
364  targetVariable = configFileObject.read_##variableType( \
365  sectionNameStr, #variableName, targetVariable, true); \
366  } \
367  catch (std::exception&) \
368  { \
369  THROW_EXCEPTION(mrpt::format( \
370  "Value for '%s' not found in config file in section '%s'", \
371  static_cast<const char*>(#variableName), \
372  std::string(sectionNameStr).c_str())); \
373  } \
374  }
375 
376 #define MRPT_LOAD_HERE_CONFIG_VAR_DEGREES( \
377  variableName, variableType, targetVariable, configFileObject, \
378  sectionNameStr) \
379  targetVariable = mrpt::DEG2RAD(configFileObject.read_##variableType( \
380  sectionNameStr, #variableName, mrpt::RAD2DEG(targetVariable), false));
381 
382 #define MRPT_LOAD_HERE_CONFIG_VAR_DEGREES_NO_DEFAULT( \
383  variableName, variableType, targetVariable, configFileObject, \
384  sectionNameStr) \
385  { \
386  try \
387  { \
388  targetVariable = \
389  mrpt::DEG2RAD(configFileObject.read_##variableType( \
390  sectionNameStr, #variableName, targetVariable, true)); \
391  } \
392  catch (std::exception&) \
393  { \
394  THROW_EXCEPTION(mrpt::format( \
395  "Value for '%s' not found in config file in section '%s'", \
396  static_cast<const char*>(#variableName), \
397  std::string(sectionNameStr).c_str())); \
398  } \
399  }
400 
401 #define MRPT_LOAD_CONFIG_VAR_NO_DEFAULT( \
402  variableName, variableType, configFileObject, sectionNameStr) \
403  { \
404  try \
405  { \
406  variableName = configFileObject.read_##variableType( \
407  sectionNameStr, #variableName, variableName, true); \
408  } \
409  catch (std::exception&) \
410  { \
411  THROW_EXCEPTION(mrpt::format( \
412  "Value for '%s' not found in config file in section '%s'", \
413  static_cast<const char*>(#variableName), \
414  std::string(sectionNameStr).c_str())); \
415  } \
416  }
417 
418 /** Shortcut for MRPT_LOAD_CONFIG_VAR_NO_DEFAULT() for REQUIRED variables config
419  * file object named `c` and section string named `s` */
420 #define MRPT_LOAD_CONFIG_VAR_REQUIRED_CS(variableName, variableType) \
421  MRPT_LOAD_CONFIG_VAR_NO_DEFAULT(variableName, variableType, c, s)
422 
423 #define MRPT_LOAD_CONFIG_VAR_CAST_NO_DEFAULT( \
424  variableName, variableType, variableTypeCast, configFileObject, \
425  sectionNameStr) \
426  { \
427  try \
428  { \
429  variableName = static_cast<variableTypeCast>( \
430  configFileObject.read_##variableType( \
431  sectionNameStr, #variableName, variableName, true)); \
432  } \
433  catch (std::exception&) \
434  { \
435  THROW_EXCEPTION(mrpt::format( \
436  "Value for '%s' not found in config file in section '%s'", \
437  static_cast<const char*>(#variableName), \
438  std::string(sectionNameStr).c_str())); \
439  } \
440  }
441 
442 #define MRPT_LOAD_HERE_CONFIG_VAR_CAST( \
443  variableName, variableType, variableTypeCast, targetVariable, \
444  configFileObject, sectionNameStr) \
445  targetVariable = \
446  static_cast<variableTypeCast>(configFileObject.read_##variableType( \
447  sectionNameStr, #variableName, targetVariable));
448 
449 #define MRPT_LOAD_HERE_CONFIG_VAR_CAST_NO_DEFAULT( \
450  variableName, variableType, variableTypeCast, targetVariable, \
451  configFileObject, sectionNameStr) \
452  { \
453  try \
454  { \
455  targetVariable = static_cast<variableTypeCast>( \
456  configFileObject.read_##variableType( \
457  sectionNameStr, #variableName, targetVariable, true)); \
458  } \
459  catch (std::exception&) \
460  { \
461  THROW_EXCEPTION(mrpt::format( \
462  "Value for '%s' not found in config file in section '%s'", \
463  static_cast<const char*>(#variableName), \
464  std::string(sectionNameStr).c_str())); \
465  } \
466  }
467 
468 #define MRPT_SAVE_CONFIG_VAR(variableName, configFileObject, sectionNameStr) \
469  { \
470  configFileObject.write(sectionNameStr, #variableName, variableName); \
471  }
472 
473 #define MRPT_SAVE_CONFIG_VAR_DEGREES( \
474  variableName, configFileObject, sectionNameStr) \
475  { \
476  configFileObject.write( \
477  sectionNameStr, #variableName, mrpt::RAD2DEG(variableName)); \
478  }
479 
480 #define MRPT_SAVE_CONFIG_VAR_COMMENT(variableName, __comment) \
481  { \
482  c.write( \
483  s, #variableName, variableName, \
484  mrpt::config::MRPT_SAVE_NAME_PADDING(), \
485  mrpt::config::MRPT_SAVE_VALUE_PADDING(), __comment); \
486  }
487 #define MRPT_SAVE_CONFIG_VAR_DEGREES_COMMENT( \
488  __entryName, __variable, __comment) \
489  { \
490  c.write( \
491  s, __entryName, mrpt::RAD2DEG(__variable), \
492  mrpt::config::MRPT_SAVE_NAME_PADDING(), \
493  mrpt::config::MRPT_SAVE_VALUE_PADDING(), __comment); \
494  }
495 
496 } // namespace config
497 } // namespace mrpt
#define MRPT_START
Definition: exceptions.h:241
std::string to_string(T v)
Just like std::to_string(), but with an overloaded version for std::string arguments.
Definition: format.h:36
virtual void getAllKeys(const std::string &section, std::vector< std::string > &keys) const =0
Returs a list with all the keys into a section.
std::string read_string(const std::string &section, const std::string &name, const std::string &defaultValue, bool failIfNotFound=false) const
static ENUMTYPE name2value(const std::string &name)
Gives the numerical name for a given enum text name.
Definition: TEnumType.h:100
int MRPT_SAVE_NAME_PADDING()
Default padding sizes for macros MRPT_SAVE_CONFIG_VAR_COMMENT(), etc.
void read_matrix(const std::string &section, const std::string &name, MATRIX_TYPE &outMatrix, const MATRIX_TYPE &defaultMatrix=MATRIX_TYPE(), bool failIfNotFound=false) const
Reads a configuration parameter as a matrix written in a matlab-like format - for example: "[2 3 4 ; ...
void write(const std::string &section, const std::string &name, const data_t &value, const int name_padding_width=-1, const int value_padding_width=-1, const std::string &comment=std::string())
float read_float(const std::string &section, const std::string &name, float defaultValue, bool failIfNotFound=false) const
virtual void writeString(const std::string &section, const std::string &name, const std::string &str)=0
A virtual method to write a generic string.
void tokenize(const std::string &inString, const std::string &inDelimiters, OUT_CONTAINER &outTokens, bool skipBlankTokens=true) noexcept
Tokenizes a string according to a set of delimiting characters.
int read_int(const std::string &section, const std::string &name, int defaultValue, bool failIfNotFound=false) const
ENUMTYPE read_enum(const std::string &section, const std::string &name, const ENUMTYPE &defaultValue, bool failIfNotFound=false) const
Reads an "enum" value, where the value in the config file can be either a numerical value or the symb...
This class allows loading and storing values and vectors of different types from a configuration text...
void setContentFromYAML(const std::string &yaml_block)
Changes the contents of the virtual "config file" from a text block containing a YAML configuration t...
A helper class that can convert an enum value into its textual representation, and viceversa...
virtual void getAllSections(std::vector< std::string > &sections) const =0
Returns a list with all the section names.
int val
Definition: mrpt_jpeglib.h:957
uint64_t read_uint64_t(const std::string &section, const std::string &name, uint64_t defaultValue, bool failIfNotFound=false) const
int MRPT_SAVE_VALUE_PADDING()
std::string read_string_first_word(const std::string &section, const std::string &name, const std::string &defaultValue, bool failIfNotFound=false) const
Reads a configuration parameter of type "string", and keeps only the first word (this can be used to ...
bool sectionExists(const std::string &section_name) const
Checks if a given section exists (name is case insensitive)
A wrapper for other CConfigFileBase-based objects that prefixes a given token to every key and/or sec...
double read_double(const std::string &section, const std::string &name, double defaultValue, bool failIfNotFound=false) const
bool keyExists(const std::string &section, const std::string &key) const
Checks if a given key exists inside a section (case insensitive)
void write(const std::string &section, const std::string &name, enum_t value, const int name_padding_width=-1, const int value_padding_width=-1, const std::string &comment=std::string())
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
virtual void clear()=0
Empties the "config file".
bool read_bool(const std::string &section, const std::string &name, bool defaultValue, bool failIfNotFound=false) const
#define MRPT_END
Definition: exceptions.h:245
std::string getContentAsYAML() const
Returns a text block representing the contents of the config file in YAML format. ...
void write(const std::string &section, const std::string &name, const std::vector< data_t > &value, const int name_padding_width=-1, const int value_padding_width=-1, const std::string &comment=std::string())
#define THROW_EXCEPTION_FMT(_FORMAT_STRING,...)
Definition: exceptions.h:69
void read_vector(const std::string &section, const std::string &name, const VECTOR_TYPE &defaultValue, VECTOR_TYPE &outValues, bool failIfNotFound=false) const
Reads a configuration parameter of type vector, stored in the file as a string: "[v1 v2 v3 ...
virtual std::string readString(const std::string &section, const std::string &name, const std::string &defaultStr, bool failIfNotFound=false) const =0
A virtual method to read a generic string.



Page generated by Doxygen 1.8.14 for MRPT 2.0.5 Git: fc2d69e97 Fri Jul 10 18:20:57 2020 +0200 at vie jul 10 18:30:13 CEST 2020