Mercurial > code
diff 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 |
line wrap: on
line diff
--- a/C++/Parser.h Sat Jan 04 18:02:06 2014 +0100 +++ b/C++/Parser.h Thu Jan 23 14:56:50 2014 +0100 @@ -20,53 +20,14 @@ #define _PARSER_H_ #include <cstdlib> -#include <exception> #include <functional> -#include <iostream> +#include <stdexcept> #include <string> +#include <unordered_map> +#include <utility> #include <vector> /** - * @class NotFoundException - * @brief Exception raised when a section or option is not found - * - * Thrown when a section or an option is not found. - */ -class NotFoundException : public std::exception { -private: - std::string m_key; - -public: - NotFoundException(const std::string &key) - : m_key(key) - { - } - - const std::string & which() const - { - return m_key; - } - - virtual const char *what() const throw() - { - return "Property not found"; - } -}; - -/** - * @struct Option - * @brief A key-value pair - * - * An option referenced by a key and a value. - */ -struct Option { - std::string m_key; /*! option name */ - std::string m_value; /*! option value */ -}; - -bool operator==(const Option &o1, const Option &o2); - -/** * @class Section * @brief The option container * @@ -75,13 +36,22 @@ * section is "". */ class Section { -private: - const std::string findOption(const std::string &name) const; - public: - std::string m_name; /*! name of section */ - std::vector<Option> m_options; /*! list of options inside */ - bool m_allowed; /*! is authorized to push */ + using Map = std::unordered_map<std::string, std::string>; + + friend class Parser; + +private: + std::string m_name; /*! name of section */ + Map m_options; /*! list of options inside */ + bool m_allowed; /*! is authorized to push */ + + const std::string findOption(const std::string &name) const; +public: + template <typename T> + struct Converter { + static const bool supported = false; + }; /** * Default constructor. @@ -89,18 +59,11 @@ Section(); /** - * Get the section name + * Named constructor. * - * @return the section name + * @param name the section name */ - const std::string &getName() const; - - /** - * Get all options from that section. - * - * @return the list of options - */ - const std::vector<Option> &getOptions() const; + Section(const std::string &name); /** * Tells if that section has the specified option name. @@ -111,13 +74,57 @@ bool hasOption(const std::string &name) const; /** + * Get the section name + * + * @return the section name + */ + const std::string &getName() const; + + /** + * Return an iterator to the beginning. + * + * @return the iterator. + */ + Map::iterator begin(); + + /** + * Return a const iterator to the beginning. + * + * @return the iterator. + */ + Map::const_iterator cbegin() const; + + /** + * Return an iterator to the end. + * + * @return the iterator. + */ + Map::iterator end(); + + /** + * Return a const iterator to the end. + * + * @return the iterator. + */ + Map::const_iterator cend() const; + + /** * Template all functions for retrieving options value. * * @param name the option name * @return the value if found */ template <typename T> - T getValue(const std::string &name) const; + T getValue(const std::string &name) const + { + try { + return requireValue<T>(name); + } catch (...) { + // Catch any conversion error. + } + + return T(); + } /** * Requires an option, this works like getOption except @@ -126,29 +133,74 @@ * * @param name the name * @return the value - * @throw NotFoundException if not found + * @throw std::out_of_range if not found + * @throw std::invalid_argument on conversion failures */ template <typename T> T requireValue(const std::string &name) const { - if (!hasOption(name)) - throw NotFoundException(name); + static_assert(Converter<T>::supported, "invalid type requested"); - return getValue<T>(name); + return Converter<T>::convert(m_options.at(name)); } +}; + +template <> +struct Section::Converter<bool> { + static const bool supported = true; - friend std::ostream &operator<<(std::ostream & stream, const Section §ion) + static bool convert(const std::string &value) { - stream << "[" << section.getName() << "]" << std::endl; + bool result(false); - for (auto p : section.getOptions()) - stream << p.m_key << "=" << p.m_value << std::endl; + if (value == "yes" || value == "true"|| value == "1") + result = true; + else if (value == "no" || value == "false" || value == "0") + result = false; - return stream; + return result; } }; -bool operator==(const Section &s1, const Section &s2); +template <> +struct Section::Converter<int> { + static const bool supported = true; + + static int convert(const std::string &value) + { + return std::stoi(value); + } +}; + +template <> +struct Section::Converter<float> { + static const bool supported = true; + + static float convert(const std::string &value) + { + return std::stof(value); + } +}; + +template <> +struct Section::Converter<double> { + static const bool supported = true; + + static double convert(const std::string &value) + { + return std::stod(value); + } +}; + +template <> +struct Section::Converter<std::string> { + static const bool supported = true; + + static std::string convert(const std::string &value) + { + return value; + } +}; /** * @class Parser @@ -167,14 +219,14 @@ DisableVerbosity = 4 /*! be verbose by method */ }; - using FindFunc = std::function<void (const Section &)>; + using FindFunc = std::function<void (const Section &)>; + using List = std::vector<Section>; private: - std::vector<Section> m_sections; /*! list of sections found */ - std::string m_error; /*! if an error occured */ - std::string m_path; /*! path file */ - int m_tuning; /*! options for parsing */ - char m_commentChar; /*! the comment token default (#) */ + List m_sections; /*! list of sections found */ + std::string m_path; /*! path file */ + int m_tuning; /*! options for parsing */ + char m_commentChar; /*! the comment token default (#) */ void addSection(const std::string &name); void addOption(const std::string &key, const std::string &value); @@ -184,6 +236,8 @@ void readLine(int lineno, const std::string &line); + void open(); + public: static const char DEFAULT_COMMENT_CHAR; @@ -194,6 +248,7 @@ * @param path the file path * @param tuning optional tuning flags * @param commentToken an optional comment delimiter + * @throw std::runtime_error on errors * @see Tuning */ Parser(const std::string &path, int tuning = 0, char commentToken = Parser::DEFAULT_COMMENT_CHAR); @@ -209,25 +264,32 @@ virtual ~Parser(); /** - * Open the config file. + * Return an iterator to the beginning. * - * @return true on success + * @return the iterator. */ - bool open(); + List::iterator begin(); /** - * Get the error message if any + * Return a const iterator to the beginning. * - * @return the error message + * @return the iterator. */ - const std::string &getError() const; + List::const_iterator cbegin() const; /** - * Get all sections found + * Return an iterator to the end. * - * @return all sections + * @return the iterator. */ - const std::vector<Section> &getSections() const; + List::iterator end(); + + /** + * Return a const iterator to the end. + * + * @return the iterator. + */ + List::const_iterator cend() const; /** * Find all sections matching the name. @@ -250,7 +312,7 @@ * * @param name the section name * @return a section - * @throw NotFoundException if not found + * @throw std::out_of_range if not found */ const Section &getSection(const std::string &name) const; @@ -265,45 +327,6 @@ * @param message the message */ virtual void log(int number, const std::string §ion, const std::string &message); - - /** - * Dump all sections and options. - */ - void dump(); - - /** - * Dump function used in the dump() method. This default method - * only print the section name like: - * Section foo - * - * @param section the current section - * @see dump - */ - virtual void dumpSection(const Section §ion); - - /** - * Dump the option. The default method only print the option name - * and value. - * - * @param option the current option - * @see dump - */ - virtual void dumpOption(const Option &option); - - /** - * Write the configuration to the output stream. - * - * @param stream the output - * @param parser the configuration - * @return the stream - */ - friend std::ostream &operator<<(std::ostream &stream, const Parser &parser) - { - for (auto s : parser.m_sections) - stream << s; - - return stream; - } }; #endif // !_PARSER_H_