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 &section)
+	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 &section, 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 &section);
-
-	/**
-	 * 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_