comparison C++/Parser.h @ 203:1ffe6d4937b7

Update parser for more convenience and types security #224
author David Demelier <markand@malikania.fr>
date Thu, 23 Jan 2014 14:56:50 +0100
parents 600754c27c88
children 9f22ce5f1b39 706f861c4c6d
comparison
equal deleted inserted replaced
202:99d0887395cc 203:1ffe6d4937b7
18 18
19 #ifndef _PARSER_H_ 19 #ifndef _PARSER_H_
20 #define _PARSER_H_ 20 #define _PARSER_H_
21 21
22 #include <cstdlib> 22 #include <cstdlib>
23 #include <exception>
24 #include <functional> 23 #include <functional>
25 #include <iostream> 24 #include <stdexcept>
26 #include <string> 25 #include <string>
26 #include <unordered_map>
27 #include <utility>
27 #include <vector> 28 #include <vector>
28
29 /**
30 * @class NotFoundException
31 * @brief Exception raised when a section or option is not found
32 *
33 * Thrown when a section or an option is not found.
34 */
35 class NotFoundException : public std::exception {
36 private:
37 std::string m_key;
38
39 public:
40 NotFoundException(const std::string &key)
41 : m_key(key)
42 {
43 }
44
45 const std::string & which() const
46 {
47 return m_key;
48 }
49
50 virtual const char *what() const throw()
51 {
52 return "Property not found";
53 }
54 };
55
56 /**
57 * @struct Option
58 * @brief A key-value pair
59 *
60 * An option referenced by a key and a value.
61 */
62 struct Option {
63 std::string m_key; /*! option name */
64 std::string m_value; /*! option value */
65 };
66
67 bool operator==(const Option &o1, const Option &o2);
68 29
69 /** 30 /**
70 * @class Section 31 * @class Section
71 * @brief The option container 32 * @brief The option container
72 * 33 *
73 * A list of section found in the file. If root 34 * A list of section found in the file. If root
74 * options are allowed (default behavior), the root 35 * options are allowed (default behavior), the root
75 * section is "". 36 * section is "".
76 */ 37 */
77 class Section { 38 class Section {
39 public:
40 using Map = std::unordered_map<std::string, std::string>;
41
42 friend class Parser;
43
78 private: 44 private:
45 std::string m_name; /*! name of section */
46 Map m_options; /*! list of options inside */
47 bool m_allowed; /*! is authorized to push */
48
79 const std::string findOption(const std::string &name) const; 49 const std::string findOption(const std::string &name) const;
80
81 public: 50 public:
82 std::string m_name; /*! name of section */ 51 template <typename T>
83 std::vector<Option> m_options; /*! list of options inside */ 52 struct Converter {
84 bool m_allowed; /*! is authorized to push */ 53 static const bool supported = false;
54 };
85 55
86 /** 56 /**
87 * Default constructor. 57 * Default constructor.
88 */ 58 */
89 Section(); 59 Section();
90 60
91 /** 61 /**
92 * Get the section name 62 * Named constructor.
93 * 63 *
94 * @return the section name 64 * @param name the section name
95 */ 65 */
96 const std::string &getName() const; 66 Section(const std::string &name);
97
98 /**
99 * Get all options from that section.
100 *
101 * @return the list of options
102 */
103 const std::vector<Option> &getOptions() const;
104 67
105 /** 68 /**
106 * Tells if that section has the specified option name. 69 * Tells if that section has the specified option name.
107 * 70 *
108 * @param name the option name 71 * @param name the option name
109 * @return true if has 72 * @return true if has
110 */ 73 */
111 bool hasOption(const std::string &name) const; 74 bool hasOption(const std::string &name) const;
112 75
113 /** 76 /**
77 * Get the section name
78 *
79 * @return the section name
80 */
81 const std::string &getName() const;
82
83 /**
84 * Return an iterator to the beginning.
85 *
86 * @return the iterator.
87 */
88 Map::iterator begin();
89
90 /**
91 * Return a const iterator to the beginning.
92 *
93 * @return the iterator.
94 */
95 Map::const_iterator cbegin() const;
96
97 /**
98 * Return an iterator to the end.
99 *
100 * @return the iterator.
101 */
102 Map::iterator end();
103
104 /**
105 * Return a const iterator to the end.
106 *
107 * @return the iterator.
108 */
109 Map::const_iterator cend() const;
110
111 /**
114 * Template all functions for retrieving options value. 112 * Template all functions for retrieving options value.
115 * 113 *
116 * @param name the option name 114 * @param name the option name
117 * @return the value if found 115 * @return the value if found
118 */ 116 */
119 template <typename T> 117 template <typename T>
120 T getValue(const std::string &name) const; 118 T getValue(const std::string &name) const
119 {
120 try {
121 return requireValue<T>(name);
122 } catch (...) {
123 // Catch any conversion error.
124 }
125
126 return T();
127 }
121 128
122 /** 129 /**
123 * Requires an option, this works like getOption except 130 * Requires an option, this works like getOption except
124 * that if an option is not found, an exception is 131 * that if an option is not found, an exception is
125 * thrown. 132 * thrown.
126 * 133 *
127 * @param name the name 134 * @param name the name
128 * @return the value 135 * @return the value
129 * @throw NotFoundException if not found 136 * @throw std::out_of_range if not found
137 * @throw std::invalid_argument on conversion failures
130 */ 138 */
131 template <typename T> 139 template <typename T>
132 T requireValue(const std::string &name) const 140 T requireValue(const std::string &name) const
133 { 141 {
134 if (!hasOption(name)) 142 static_assert(Converter<T>::supported, "invalid type requested");
135 throw NotFoundException(name); 143
136 144 return Converter<T>::convert(m_options.at(name));
137 return getValue<T>(name); 145 }
138 } 146 };
139 147
140 friend std::ostream &operator<<(std::ostream & stream, const Section &section) 148 template <>
141 { 149 struct Section::Converter<bool> {
142 stream << "[" << section.getName() << "]" << std::endl; 150 static const bool supported = true;
143 151
144 for (auto p : section.getOptions()) 152 static bool convert(const std::string &value)
145 stream << p.m_key << "=" << p.m_value << std::endl; 153 {
146 154 bool result(false);
147 return stream; 155
148 } 156 if (value == "yes" || value == "true"|| value == "1")
149 }; 157 result = true;
150 158 else if (value == "no" || value == "false" || value == "0")
151 bool operator==(const Section &s1, const Section &s2); 159 result = false;
160
161 return result;
162 }
163 };
164
165 template <>
166 struct Section::Converter<int> {
167 static const bool supported = true;
168
169 static int convert(const std::string &value)
170 {
171 return std::stoi(value);
172 }
173 };
174
175 template <>
176 struct Section::Converter<float> {
177 static const bool supported = true;
178
179 static float convert(const std::string &value)
180 {
181 return std::stof(value);
182 }
183 };
184
185 template <>
186 struct Section::Converter<double> {
187 static const bool supported = true;
188
189 static double convert(const std::string &value)
190 {
191 return std::stod(value);
192 }
193 };
194
195 template <>
196 struct Section::Converter<std::string> {
197 static const bool supported = true;
198
199 static std::string convert(const std::string &value)
200 {
201 return value;
202 }
203 };
152 204
153 /** 205 /**
154 * @class Parser 206 * @class Parser
155 * @brief Config file parser 207 * @brief Config file parser
156 * 208 *
165 DisableRootSection = 1, /*! disable options on root */ 217 DisableRootSection = 1, /*! disable options on root */
166 DisableRedefinition = 2, /*! disable multiple redefinition */ 218 DisableRedefinition = 2, /*! disable multiple redefinition */
167 DisableVerbosity = 4 /*! be verbose by method */ 219 DisableVerbosity = 4 /*! be verbose by method */
168 }; 220 };
169 221
170 using FindFunc = std::function<void (const Section &)>; 222 using FindFunc = std::function<void (const Section &)>;
223 using List = std::vector<Section>;
171 224
172 private: 225 private:
173 std::vector<Section> m_sections; /*! list of sections found */ 226 List m_sections; /*! list of sections found */
174 std::string m_error; /*! if an error occured */ 227 std::string m_path; /*! path file */
175 std::string m_path; /*! path file */ 228 int m_tuning; /*! options for parsing */
176 int m_tuning; /*! options for parsing */ 229 char m_commentChar; /*! the comment token default (#) */
177 char m_commentChar; /*! the comment token default (#) */
178 230
179 void addSection(const std::string &name); 231 void addSection(const std::string &name);
180 void addOption(const std::string &key, const std::string &value); 232 void addOption(const std::string &key, const std::string &value);
181 233
182 void readSection(int lineno, const std::string &line); 234 void readSection(int lineno, const std::string &line);
183 void readOption(int lineno, const std::string &line); 235 void readOption(int lineno, const std::string &line);
184 236
185 void readLine(int lineno, const std::string &line); 237 void readLine(int lineno, const std::string &line);
238
239 void open();
186 240
187 public: 241 public:
188 static const char DEFAULT_COMMENT_CHAR; 242 static const char DEFAULT_COMMENT_CHAR;
189 243
190 /** 244 /**
192 * options may be added. 246 * options may be added.
193 * 247 *
194 * @param path the file path 248 * @param path the file path
195 * @param tuning optional tuning flags 249 * @param tuning optional tuning flags
196 * @param commentToken an optional comment delimiter 250 * @param commentToken an optional comment delimiter
251 * @throw std::runtime_error on errors
197 * @see Tuning 252 * @see Tuning
198 */ 253 */
199 Parser(const std::string &path, int tuning = 0, char commentToken = Parser::DEFAULT_COMMENT_CHAR); 254 Parser(const std::string &path, int tuning = 0, char commentToken = Parser::DEFAULT_COMMENT_CHAR);
200 255
201 /** 256 /**
207 * Default destructor. 262 * Default destructor.
208 */ 263 */
209 virtual ~Parser(); 264 virtual ~Parser();
210 265
211 /** 266 /**
212 * Open the config file. 267 * Return an iterator to the beginning.
213 * 268 *
214 * @return true on success 269 * @return the iterator.
215 */ 270 */
216 bool open(); 271 List::iterator begin();
217 272
218 /** 273 /**
219 * Get the error message if any 274 * Return a const iterator to the beginning.
220 * 275 *
221 * @return the error message 276 * @return the iterator.
222 */ 277 */
223 const std::string &getError() const; 278 List::const_iterator cbegin() const;
224 279
225 /** 280 /**
226 * Get all sections found 281 * Return an iterator to the end.
227 * 282 *
228 * @return all sections 283 * @return the iterator.
229 */ 284 */
230 const std::vector<Section> &getSections() const; 285 List::iterator end();
286
287 /**
288 * Return a const iterator to the end.
289 *
290 * @return the iterator.
291 */
292 List::const_iterator cend() const;
231 293
232 /** 294 /**
233 * Find all sections matching the name. 295 * Find all sections matching the name.
234 * 296 *
235 * @param name the sections name 297 * @param name the sections name
248 /** 310 /**
249 * Get a specified section. 311 * Get a specified section.
250 * 312 *
251 * @param name the section name 313 * @param name the section name
252 * @return a section 314 * @return a section
253 * @throw NotFoundException if not found 315 * @throw std::out_of_range if not found
254 */ 316 */
255 const Section &getSection(const std::string &name) const; 317 const Section &getSection(const std::string &name) const;
256 318
257 /** 319 /**
258 * Logging function, used only if DisableVerbosity is not set. The 320 * Logging function, used only if DisableVerbosity is not set. The
263 * @param number the line number 325 * @param number the line number
264 * @param section the current section worked on 326 * @param section the current section worked on
265 * @param message the message 327 * @param message the message
266 */ 328 */
267 virtual void log(int number, const std::string &section, const std::string &message); 329 virtual void log(int number, const std::string &section, const std::string &message);
268
269 /**
270 * Dump all sections and options.
271 */
272 void dump();
273
274 /**
275 * Dump function used in the dump() method. This default method
276 * only print the section name like:
277 * Section foo
278 *
279 * @param section the current section
280 * @see dump
281 */
282 virtual void dumpSection(const Section &section);
283
284 /**
285 * Dump the option. The default method only print the option name
286 * and value.
287 *
288 * @param option the current option
289 * @see dump
290 */
291 virtual void dumpOption(const Option &option);
292
293 /**
294 * Write the configuration to the output stream.
295 *
296 * @param stream the output
297 * @param parser the configuration
298 * @return the stream
299 */
300 friend std::ostream &operator<<(std::ostream &stream, const Parser &parser)
301 {
302 for (auto s : parser.m_sections)
303 stream << s;
304
305 return stream;
306 }
307 }; 330 };
308 331
309 #endif // !_PARSER_H_ 332 #endif // !_PARSER_H_