view C++/Ini.h @ 325:d52a69f9f029

Add Ini, brand new replacement for Parser
author David Demelier <markand@malikania.fr>
date Sat, 28 Feb 2015 18:53:27 +0100
parents
children 78e8f9a3b233
line wrap: on
line source

/*
 * 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_

#include <algorithm>
#include <deque>
#include <fstream>
#include <istream>
#include <stdexcept>
#include <string>

/**
 * @class IniOption
 * @brief Option definition
 */
class IniOption {
private:
	std::string m_key;
	std::string m_value;

public:
	inline IniOption(std::string key, std::string value)
		: m_key(std::move(key))
		, m_value(std::move(value))
	{
	}

	inline const std::string &key() const noexcept
	{
		return m_key;
	}

	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:
	IniSection() = default;

	inline IniSection(std::string key, std::deque<IniOption> options = {})
		: m_key(std::move(key))
		, m_options(std::move(options))
	{
	}

	inline const std::string &key() const noexcept
	{
		return m_key;
	}

	inline auto begin() noexcept
	{
		return m_options.begin();
	}

	inline auto begin() const noexcept
	{
		return m_options.begin();
	}

	inline auto cbegin() const noexcept
	{
		return m_options.cbegin();
	}

	inline auto end() noexcept
	{
		return m_options.end();
	}

	inline auto end() const noexcept
	{
		return m_options.end();
	}

	inline auto cend() const noexcept
	{
		return m_options.cend();
	}

	inline void push_back(IniOption option)
	{
		m_options.push_back(std::move(option));
	}

	inline void push_front(IniOption option)
	{
		m_options.push_front(std::move(option));
	}

	inline unsigned size() const noexcept
	{
		return m_options.size();
	}

	inline IniOption &operator[](int index) noexcept
	{
		return m_options[index];
	}

	inline const IniOption &operator[](int index) const noexcept
	{
		return m_options[index];
	}

	inline IniOption &operator[](const std::string &key)
	{
		return find<IniOption &>(key);
	}

	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:
	Ini() = default;

	Ini(std::istream &stream);

	inline Ini(std::istream &&stream)
		: Ini(stream)
	{
	}

	inline auto begin() noexcept
	{
		return m_sections.begin();
	}

	inline auto begin() const noexcept
	{
		return m_sections.begin();
	}

	inline auto cbegin() const noexcept
	{
		return m_sections.cbegin();
	}

	inline auto end() noexcept
	{
		return m_sections.end();
	}

	inline auto end() const noexcept
	{
		return m_sections.end();
	}

	inline auto cend() const noexcept
	{
		return m_sections.cend();
	}

	inline unsigned size() const noexcept
	{
		return m_sections.size();
	}

	inline void push_back(IniSection section)
	{
		m_sections.push_back(std::move(section));
	}

	inline void push_front(IniSection section)
	{
		m_sections.push_front(std::move(section));
	}

	inline IniSection &operator[](int index) noexcept
	{
		return m_sections[index];
	}

	inline const IniSection &operator[](int index) const noexcept
	{
		return m_sections[index];
	}

	inline IniSection &operator[](const std::string &key)
	{
		return find<IniSection &>(key);
	}

	inline const IniSection &operator[](const std::string &key) const
	{
		return find<IniSection &>(key);
	}
};

#endif // !_INI_H_