Mercurial > code
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 §ion) | 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 §ion, const std::string &message); | 329 virtual void log(int number, const std::string §ion, 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 §ion); | |
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_ |