diff C++/modules/Ini/Ini.h @ 334:0b576ee64d45

* Create brand new hierarchy * Rename DynLib to Dynlib * Remove some warnings
author David Demelier <markand@malikania.fr>
date Sun, 08 Mar 2015 14:26:33 +0100
parents C++/Ini.h@78e8f9a3b233
children d5ec1174b707
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/modules/Ini/Ini.h	Sun Mar 08 14:26:33 2015 +0100
@@ -0,0 +1,494 @@
+/*
+ * Ini.h -- .ini file parsing
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _INI_H_
+#define _INI_H_
+
+/**
+ * @file Ini.h
+ * @brief Configuration file parser
+ */
+
+#include <algorithm>
+#include <deque>
+#include <stdexcept>
+#include <string>
+
+/**
+ * @class IniError
+ * @brief Error in a file
+ */
+class IniError : public std::exception {
+private:
+	int m_line;
+	int m_position;
+	std::string m_error;
+
+public:
+	/**
+	 * Construct an error.
+	 *
+	 * @param line the line
+	 * @param position the position
+	 * @param error the error
+	 */
+	inline IniError(int line, int position, std::string error)
+		: m_line(line)
+		, m_position(position)
+		, m_error(std::move(error))
+	{
+	}
+
+	/**
+	 * Return the line number.
+	 *
+	 * @return the line
+	 */
+	inline int line() const noexcept
+	{
+		return m_line;
+	}
+
+	/**
+	 * Return the position in the current line.
+	 *
+	 * @return the position
+	 */
+	inline int position() const noexcept
+	{
+		return m_position;
+	}
+
+	/**
+	 * Get the error string.
+	 *
+	 * @return the string
+	 */
+	inline const char *what() const noexcept
+	{
+		return m_error.c_str();
+	}
+};
+
+/**
+ * @class IniOption
+ * @brief Option definition
+ */
+class IniOption {
+private:
+	std::string m_key;
+	std::string m_value;
+
+public:
+	/**
+	 * Construct an option.
+	 *
+	 * @param key the key
+	 * @param value the value
+	 */
+	inline IniOption(std::string key, std::string value)
+		: m_key(std::move(key))
+		, m_value(std::move(value))
+	{
+	}
+
+	/**
+	 * Get the option key.
+	 *
+	 * @return the key
+	 */
+	inline const std::string &key() const noexcept
+	{
+		return m_key;
+	}
+
+	/**
+	 * Get the option value.
+	 *
+	 * @return the value
+	 */
+	inline const std::string &value() const noexcept
+	{
+		return m_value;
+	}
+};
+
+/**
+ * @class IniSection
+ * @brief Section that contains one or more options
+ */
+class IniSection {
+private:
+	std::string m_key;
+	std::deque<IniOption> m_options;
+
+	template <typename T>
+	T find(const std::string &key) const
+	{
+		auto it = std::find_if(m_options.begin(), m_options.end(), [&] (const IniOption &o) {
+			return o.key() == key;
+		});
+
+		if (it == m_options.end())
+			throw std::out_of_range("option " + key + " not found");
+
+		return const_cast<T>(*it);
+	}
+
+public:
+	/**
+	 * Default constructor has no sections and no values.
+	 */
+	IniSection() = default;
+
+	/**
+	 * Construct a section with a set of options.
+	 *
+	 * @param key the section name
+	 * @param options the list of options
+	 */
+	inline IniSection(std::string key, std::deque<IniOption> options = {}) noexcept
+		: m_key(std::move(key))
+		, m_options(std::move(options))
+	{
+	}
+
+	/**
+	 * Get the section key.
+	 *
+	 * @return the key
+	 */
+	inline const std::string &key() const noexcept
+	{
+		return m_key;
+	}
+
+	/**
+	 * Get an iterator to the beginning.
+	 *
+	 * @return the iterator
+	 */
+	inline auto begin() noexcept
+	{
+		return m_options.begin();
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline auto begin() const noexcept
+	{
+		return m_options.begin();
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline auto cbegin() const noexcept
+	{
+		return m_options.cbegin();
+	}
+
+	/**
+	 * Get an iterator to the end.
+	 *
+	 * @return the iterator
+	 */
+	inline auto end() noexcept
+	{
+		return m_options.end();
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline auto end() const noexcept
+	{
+		return m_options.end();
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline auto cend() const noexcept
+	{
+		return m_options.cend();
+	}
+
+	/**
+	 * Append an option.
+	 *
+	 * @param option the option to add
+	 */
+	inline void push_back(IniOption option)
+	{
+		m_options.push_back(std::move(option));
+	}
+
+	/**
+	 * Push an option to the beginning.
+	 *
+	 * @param option the option to add
+	 */
+	inline void push_front(IniOption option)
+	{
+		m_options.push_front(std::move(option));
+	}
+
+	/**
+	 * Get the number of options in that section.
+	 *
+	 * @return the size
+	 */
+	inline unsigned size() const noexcept
+	{
+		return m_options.size();
+	}
+
+	/**
+	 * Access an option at the specified index.
+	 *
+	 * @param index the index
+	 * @return the option
+	 * @warning No bounds checking is performed
+	 */
+	inline IniOption &operator[](int index) noexcept
+	{
+		return m_options[index];
+	}
+
+	/**
+	 * Access an option at the specified index.
+	 *
+	 * @param index the index
+	 * @return the option
+	 * @warning No bounds checking is performed
+	 */
+	inline const IniOption &operator[](int index) const noexcept
+	{
+		return m_options[index];
+	}
+
+	/**
+	 * Access an option at the specified key.
+	 *
+	 * @param key the key
+	 * @return the option
+	 * @warning No bounds checking is performed
+	 */
+	inline IniOption &operator[](const std::string &key)
+	{
+		return find<IniOption &>(key);
+	}
+
+	/**
+	 * Access an option at the specified key.
+	 *
+	 * @param key the key
+	 * @return the option
+	 * @warning No bounds checking is performed
+	 */
+	inline const IniOption &operator[](const std::string &key) const
+	{
+		return find<const IniOption &>(key);
+	}
+};
+
+/**
+ * @class Ini
+ * @brief Ini config file loader
+ */
+class Ini {
+private:
+	std::deque<IniSection> m_sections;
+
+	template <typename T>
+	T find(const std::string &key) const
+	{
+		auto it = std::find_if(m_sections.begin(), m_sections.end(), [&] (const IniSection &s) {
+			return s.key() == key;
+		});
+
+		if (it == m_sections.end())
+			throw std::out_of_range("section " + key + " not found");
+
+		return const_cast<T>(*it);
+	}
+
+public:
+	/**
+	 * Default constructor with an empty configuration.
+	 */
+	Ini() = default;
+
+	/**
+	 * Open the path as the configuration file.
+	 *
+	 * @param path the path
+	 * @throw IniError on any error
+	 */
+	Ini(const std::string &path);
+
+	/**
+	 * Get an iterator to the beginning.
+	 *
+	 * @return the iterator
+	 */
+	inline auto begin() noexcept
+	{
+		return m_sections.begin();
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline auto begin() const noexcept
+	{
+		return m_sections.begin();
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline auto cbegin() const noexcept
+	{
+		return m_sections.cbegin();
+	}
+
+	/**
+	 * Get an iterator to the end.
+	 *
+	 * @return the iterator
+	 */
+	inline auto end() noexcept
+	{
+		return m_sections.end();
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline auto end() const noexcept
+	{
+		return m_sections.end();
+	}
+
+	/**
+	 * Overloaded function.
+	 *
+	 * @return the iterator
+	 */
+	inline auto cend() const noexcept
+	{
+		return m_sections.cend();
+	}
+
+	/**
+	 * Get the number of sections in the configuration.
+	 *
+	 * @return the size
+	 */
+	inline unsigned size() const noexcept
+	{
+		return m_sections.size();
+	}
+
+	/**
+	 * Append a section to the end.
+	 *
+	 * @param section the section to add
+	 */
+	inline void push_back(IniSection section)
+	{
+		m_sections.push_back(std::move(section));
+	}
+
+	/**
+	 * Add a section to the beginning.
+	 *
+	 * @param section the section to add
+	 */
+	inline void push_front(IniSection section)
+	{
+		m_sections.push_front(std::move(section));
+	}
+
+	/**
+	 * Access a section at the specified index.
+	 *
+	 * @param index the index
+	 * @return the section
+	 * @warning No bounds checking is performed
+	 */
+	inline IniSection &operator[](int index) noexcept
+	{
+		return m_sections[index];
+	}
+
+	/**
+	 * Access a section at the specified index.
+	 *
+	 * @param index the index
+	 * @return the section
+	 * @warning No bounds checking is performed
+	 */
+	inline const IniSection &operator[](int index) const noexcept
+	{
+		return m_sections[index];
+	}
+
+	/**
+	 * Access a section at the specified key.
+	 *
+	 * @param key the key
+	 * @return the section
+	 * @warning No bounds checking is performed
+	 */
+	inline IniSection &operator[](const std::string &key)
+	{
+		return find<IniSection &>(key);
+	}
+
+	/**
+	 * Access a section at the specified key.
+	 *
+	 * @param key the key
+	 * @return the section
+	 * @warning No bounds checking is performed
+	 */
+	inline const IniSection &operator[](const std::string &key) const
+	{
+		return find<IniSection &>(key);
+	}
+};
+
+#endif // !_INI_H_