@@ -247,7 +247,12 @@ class INIReader
247247 int ParseError () const ;
248248
249249 // Return the list of sections found in ini file
250- const std::set<std::string>& Sections () const ;
250+ const std::set<std::string> Sections () const ;
251+
252+ // Return the list of keys in the given section
253+ const std::set<std::string> Keys (std::string section) const ;
254+
255+ const std::unordered_map<std::string, std::string> Get (std::string section) const ;
251256
252257 template <typename T = std::string>
253258 T Get (std::string section, std::string name) const ;
@@ -263,13 +268,13 @@ class INIReader
263268
264269protected:
265270 int _error;
266- std::map<std::string, std::string> _values;
267- std::set<std::string> _sections;
268- static std::string MakeKey (std::string section, std::string name);
271+ std::unordered_map<std::string, std::unordered_map<std::string, std::string>> _values;
269272 static int ValueHandler (void * user, const char * section, const char * name, const char * value);
270273
271274 template <typename T>
272275 T Converter (std::string s) const ;
276+
277+ const bool BoolConverter (std::string s) const ;
273278};
274279
275280#endif // __INIREADER_H__
@@ -310,57 +315,69 @@ inline int INIReader::ParseError() const
310315 return _error;
311316}
312317
313- inline const std::set<std::string>& INIReader::Sections () const
318+ inline const std::set<std::string> INIReader::Sections () const
314319{
315- return _sections;
320+ std::set<std::string> retval;
321+ for (auto const & element : _values) {
322+ retval.insert (element.first );
323+ }
324+ return retval;
316325}
317326
318- template <typename T = std::string>
327+ inline const std::set<std::string> INIReader::Keys (std::string section) const
328+ {
329+ auto const _section = Get (section);
330+ std::set<std::string> retval;
331+ for (auto const & element : _section) {
332+ retval.insert (element.first );
333+ }
334+ return retval;
335+ }
336+
337+ inline const std::unordered_map<std::string, std::string> INIReader::Get (std::string section) const {
338+ auto const _section = _values.find (section);
339+ if (_section == _values.end ()) {
340+ throw std::runtime_error (" section '" + section + " ' not found." );
341+ }
342+ return _section->second ;
343+ }
344+
345+ template <typename T>
319346inline T INIReader::Get (std::string section, std::string name) const {
320- std::string key = MakeKey (section, name);
321- if (!_values.count (key)) {
322- throw std::runtime_error (" key " + key + " not found." );
347+ auto const _section = Get (section);
348+ auto const _value = _section.find (name);
349+
350+ if (_value == _section.end ()) {
351+ throw std::runtime_error (" key '" + name + " ' not found in section '" + section + " '." );
323352 }
324-
353+
354+ std::string value = _value->second ;
355+
325356 if constexpr (std::is_same<T, std::string>()) {
326- return _values. at (key) ;
357+ return value ;
327358 } else if constexpr (std::is_same<T, bool >()) {
328- std::string s{_values.at (key)};
329- std::transform (s.begin (), s.end (), s.begin (), ::tolower);
330-
331- const std::unordered_map<std::string, bool > s2b{
332- {" 1" , true }, {" true" , true }, {" yes" , true }, {" on" , true },
333- {" 0" , false }, {" false" , false }, {" no" , false }, {" off" , false },
334- };
335- return s2b.find (s)->second ;
359+ return BoolConverter (value);
336360 } else {
337- try {
338- return Converter<T>(_values.at (key));
339- } catch (std::exception& e) {
340- throw std::runtime_error (" cannot parse value in " + key + " to type<T>." );
341- }
342- }
361+ return Converter<T>(value);
362+ };
343363}
344364
345365template <typename T>
346366inline T INIReader::Get (std::string section, std::string name, T&& default_v) const {
347- std::string key = MakeKey (section, name);
348- if (!_values.count (key)) {
367+ try {
368+ return Get<T>(section, name);
369+ } catch (std::runtime_error &e) {
349370 return default_v;
350371 }
351- return Get<T>(section, name);
352372}
353373
354- template <typename T = std::string >
374+ template <typename T>
355375inline std::vector<T> INIReader::GetVector (std::string section, std::string name) const {
356- std::string key = MakeKey (section, name);
357- if (!_values.count (key)) {
358- throw std::runtime_error (" key " + key + " not found." );
359- }
376+ std::string value = Get (section, name);
360377
361- std::istringstream out{_values. at (key) };
378+ std::istringstream out{value };
362379 const std::vector<std::string> strs{
363- std::istream_iterator<std::string>{out},
380+ std::istream_iterator<std::string>{out},
364381 std::istream_iterator<std::string>()
365382 };
366383 try {
@@ -370,48 +387,51 @@ inline std::vector<T> INIReader::GetVector(std::string section, std::string name
370387 }
371388 return vs;
372389 } catch (std::exception& e) {
373- throw std::runtime_error (" cannot parse value in " + key + " to vector<T>." );
390+ throw std::runtime_error (" cannot parse value " + value + " to vector<T>." );
374391 }
375392}
376393
377394template <typename T>
378395inline std::vector<T> INIReader::GetVector (std::string section, std::string name, std::vector<T> default_v) const {
379- std::string key = MakeKey (section, name);
380- if (!_values.count (key)) {
396+ try {
397+ return GetVector<T>(section, name);
398+ } catch (std::runtime_error &e) {
381399 return default_v;
382- }
383- return GetVector<T>(section, name);
400+ };
384401}
385402
386-
387403template <typename T>
388404inline T INIReader::Converter (std::string s) const {
389- if constexpr (std::is_same<T, std::string>()) {
390- return s;
391- }
392-
393- T v{};
394- std::istringstream _{s};
395- _.exceptions (std::ios::failbit);
396-
397- _ >> v;
398- return v;
405+ try {
406+ T v{};
407+ std::istringstream _{s};
408+ _.exceptions (std::ios::failbit);
409+ _ >> v;
410+ return v;
411+ } catch (std::exception& e) {
412+ throw std::runtime_error (" cannot parse value '" + s + " ' to type<T>." );
413+ };
399414}
400415
401- inline std::string INIReader::MakeKey (const std::string section, const std::string name)
402- {
403- std::string key = section + " =" + name;
404- return key;
416+ inline const bool INIReader::BoolConverter (std::string s) const {
417+ std::transform (s.begin (), s.end (), s.begin (), ::tolower);
418+ const std::unordered_map<std::string, bool > s2b{
419+ {" 1" , true }, {" true" , true }, {" yes" , true }, {" on" , true },
420+ {" 0" , false }, {" false" , false }, {" no" , false }, {" off" , false },
421+ };
422+ auto const value = s2b.find (s);
423+ if (value == s2b.end ()) {
424+ throw std::runtime_error (" '" + s + " ' is not a valid boolean value." );
425+ }
426+ return value->second ;
405427}
406428
407429inline int INIReader::ValueHandler (void * user, const char * section, const char * name, const char * value)
408430{
409431 INIReader* reader = (INIReader*)user;
410- std::string key = MakeKey (section, name);
411- if (reader->_values [key].size () > 0 )
412- reader->_values [key] += " \n " ;
413- reader->_values [key] += value;
414- reader->_sections .insert (section);
432+ if (reader->_values [section][name].size () > 0 )
433+ reader->_values [section][name] += " \n " ;
434+ reader->_values [section][name] += value;
415435 return 1 ;
416436}
417437}
0 commit comments