Last active
June 2, 2020 10:50
-
-
Save AlexandreGerault/1410736797d59181c0ff62b2eba90b21 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <core/configuration.hpp> | |
configuration::configuration() : m_file("default.config") { | |
} | |
configuration::configuration(std::string path) : m_file(std::move(path)) {} | |
/** | |
* Check whether the options map contains a key or not | |
* | |
* @param key | |
* @return true if the map has the option | |
*/ | |
bool configuration::has(const std::string &key) const { | |
return m_fields.contains(key); | |
} | |
/** | |
* Update the value of an existing option identified by its key. | |
* If the key does not exist then the function does nothing | |
* | |
* @param key | |
* @param value | |
*/ | |
void configuration::set(const std::string &key, const std::string &value) { | |
auto iterator = m_fields.find(key); | |
if (iterator != m_fields.end()) { | |
iterator->second = value; | |
} | |
} | |
/** | |
* Add a new option entry if the entry does not still exist | |
* Else it throw an exception | |
* | |
* @param key | |
* @param value | |
*/ | |
void configuration::add(const std::string &key, const std::string &value) { | |
m_fields.insert({key, value}); | |
} | |
/** | |
* Remove an option if it finds it. | |
* Else it does nothing. | |
* | |
* @param key | |
*/ | |
void configuration::remove(const std::string &key) { m_fields.erase(key); } | |
/** | |
* Reset the map and fill it with the content of a configuration file | |
* The syntax of the configuration file must be like this | |
* KEY=VALUE | |
* with 1 pair per line | |
* | |
* @param path | |
* @return | |
*/ | |
bool configuration::load() { | |
m_fields.clear(); | |
std::ifstream loadingFile(m_file); | |
if (loadingFile.is_open()) { | |
std::string line; | |
std::string delimiter{"="}; | |
while (std::getline(loadingFile, line)) { | |
if (auto pos = line.find(delimiter); pos != std::string::npos) { | |
std::string key{line.substr(0, pos)}; | |
std::string value{line.substr(pos + 1, line.length())}; | |
m_fields.insert({key, value}); | |
} | |
} | |
return true; | |
} | |
return false; | |
} | |
/** | |
* Saves the current fields to a configuration file. | |
* If the file already exists it is previously cleared. | |
* It stores each option on a new line matching the below syntax: | |
* KEY=VALUE | |
* | |
* @param path | |
* @return whether the configuration was successfully saved | |
*/ | |
bool configuration::save() const { | |
std::ofstream savingFile(m_file); | |
savingFile.clear(); | |
for (auto const &[key, value] : m_fields) { | |
savingFile << key << "=" << value << std::endl; | |
} | |
savingFile.close(); | |
return !savingFile.fail(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef CONFIGURATION_HPP | |
#define CONFIGURATION_HPP | |
#include <fstream> | |
#include <sstream> | |
#include <stdexcept> | |
#include <string> | |
#include <unordered_map> | |
template <typename T> struct expected { | |
static char const *name() { return "SHOULD NOT BE USED"; } | |
}; | |
template <> struct expected<std::string> { | |
static char const *name() { return "a string"; } | |
}; | |
template <> struct expected<int> { | |
static char const *name() { return "an int"; } | |
}; | |
template <> struct expected<double> { | |
static char const *name() { return "a double"; } | |
}; | |
template <typename T> struct decoder { | |
static T decode(std::string const &text, std::string const &name) { | |
std::istringstream iss(text); | |
if (T value; (iss >> value).eof()) { | |
return value; | |
} | |
throw std::runtime_error("Cannot extract parameter " + name + " as " + | |
expected<T>::name() + " from \"" + text + "\""); | |
} | |
}; | |
template <> struct decoder<std::string> { | |
static std::string const &decode(std::string const &text, | |
std::string const &name) { | |
return text; | |
} | |
}; | |
class configuration { | |
public: | |
configuration(); | |
explicit configuration(std::string path); | |
bool has(const std::string &key) const; | |
void set(const std::string &key, const std::string &value); | |
void add(const std::string &key, const std::string &value); | |
void remove(const std::string &key); | |
bool load(); | |
bool save() const; | |
/** | |
* Get a value from the map and convert to T it if possible. | |
* If it cannot convert it returns the string. | |
* If it doesn't find the option it does nothing. | |
* | |
* @tparam T | |
* @param key | |
* @return a converted value | |
*/ | |
template <typename T> | |
T get(const std::string &key, T defaultValue = T{}) const { | |
auto iterator = m_fields.find(key); | |
if (iterator == m_fields.end()) { | |
return defaultValue; | |
} | |
return decoder<T>::decode(iterator->second, key); | |
}; | |
private: | |
std::unordered_map<std::string, std::string> m_fields; | |
std::string m_file; | |
}; | |
#endif // CONFIGURATION_HPP |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment