feat(config): added ability to get all keys and check if a key exists in the given config file
also added the ability to get a config value without specifying a default (this is only avalible to freind classes)
This commit is contained in:
@@ -46,6 +46,7 @@ bool Config::loadConfig(const std::string& configFile) {
|
|||||||
std::cerr << "Error: " << e.what() << std::endl;
|
std::cerr << "Error: " << e.what() << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
m_loaded = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,3 +61,45 @@ void Config::addToCache(const std::string &key, const YAML::Node &node) {
|
|||||||
void Config::registerUnknownKey(const std::string &key) {
|
void Config::registerUnknownKey(const std::string &key) {
|
||||||
unknownKeys.push_back(key);
|
unknownKeys.push_back(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Config::has(const std::string &key) {
|
||||||
|
if (!m_loaded) {
|
||||||
|
throw std::runtime_error("Error! Config file not loaded");
|
||||||
|
}
|
||||||
|
if (isKeyInCache(key)) { return true; }
|
||||||
|
|
||||||
|
YAML::Node node = YAML::Clone(yamlRoot);
|
||||||
|
std::istringstream keyStream(key);
|
||||||
|
std::string subKey;
|
||||||
|
while (std::getline(keyStream, subKey, ':')) {
|
||||||
|
if (!node[subKey]) {
|
||||||
|
registerUnknownKey(key);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
node = node[subKey]; // go deeper
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key exists and is of the requested type
|
||||||
|
addToCache(key, node);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recurse_keys(const YAML::Node& node, std::vector<std::string>& keyList, const std::string& path = "") {
|
||||||
|
if (node.IsMap()) {
|
||||||
|
for (const auto& it : node) {
|
||||||
|
std::string key = it.first.as<std::string>();
|
||||||
|
std::string new_path = path.empty() ? key : path + ":" + key;
|
||||||
|
recurse_keys(it.second, keyList, new_path);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
keyList.push_back(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> Config::keys() const {
|
||||||
|
std::vector<std::string> keyList;
|
||||||
|
YAML::Node node = YAML::Clone(yamlRoot);
|
||||||
|
recurse_keys(node, keyList);
|
||||||
|
return keyList;
|
||||||
|
}
|
||||||
@@ -23,14 +23,18 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
// Required for YAML parsing
|
||||||
#include "yaml-cpp/yaml.h"
|
#include "yaml-cpp/yaml.h"
|
||||||
|
|
||||||
|
// -- Forward Def of Resource manager to let it act as a friend of Config --
|
||||||
|
class ResourceManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class Config
|
* @class Config
|
||||||
* @brief Singleton class to manage configuration settings loaded from a YAML file.
|
* @brief Singleton class to manage configuration settings loaded from a YAML file.
|
||||||
@@ -94,6 +98,21 @@ private:
|
|||||||
*/
|
*/
|
||||||
void registerUnknownKey(const std::string &key);
|
void registerUnknownKey(const std::string &key);
|
||||||
|
|
||||||
|
bool m_loaded = false;
|
||||||
|
|
||||||
|
// Only friends can access get without a default value
|
||||||
|
template <typename T>
|
||||||
|
T get(const std::string &key) {
|
||||||
|
if (!m_loaded) {
|
||||||
|
throw std::runtime_error("Error! Config file not loaded");
|
||||||
|
}
|
||||||
|
if (has(key)) {
|
||||||
|
return getFromCache<T>(key, T());
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Error! Key not found in config file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Get the singleton instance of the Config class.
|
* @brief Get the singleton instance of the Config class.
|
||||||
@@ -136,6 +155,9 @@ public:
|
|||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T get(const std::string &key, T defaultValue) {
|
T get(const std::string &key, T defaultValue) {
|
||||||
|
if (!m_loaded) {
|
||||||
|
throw std::runtime_error("Error! Config file not loaded");
|
||||||
|
}
|
||||||
// --- Check if the key has already been checked for existence
|
// --- Check if the key has already been checked for existence
|
||||||
if (std::find(unknownKeys.begin(), unknownKeys.end(), key) != unknownKeys.end()) {
|
if (std::find(unknownKeys.begin(), unknownKeys.end(), key) != unknownKeys.end()) {
|
||||||
return defaultValue; // If the key has already been added to the unknown cache do not traverse the YAML tree or hit the cache
|
return defaultValue; // If the key has already been added to the unknown cache do not traverse the YAML tree or hit the cache
|
||||||
@@ -171,6 +193,19 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if the key exists in the given config file
|
||||||
|
* @param key Key to check;
|
||||||
|
* @return boolean true or false
|
||||||
|
*/
|
||||||
|
bool has(const std::string &key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get all keys defined in the configuration file.
|
||||||
|
* @return Vector of all keys in the configuration file.
|
||||||
|
*/
|
||||||
|
std::vector<std::string> keys() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Print the configuration file path and the YAML root node.
|
* @brief Print the configuration file path and the YAML root node.
|
||||||
* @param os Output stream.
|
* @param os Output stream.
|
||||||
@@ -178,6 +213,10 @@ public:
|
|||||||
* @return Output stream.
|
* @return Output stream.
|
||||||
*/
|
*/
|
||||||
friend std::ostream& operator<<(std::ostream& os, const Config& config) {
|
friend std::ostream& operator<<(std::ostream& os, const Config& config) {
|
||||||
|
if (!config.m_loaded) {
|
||||||
|
os << "Config file not loaded" << std::endl;
|
||||||
|
return os;
|
||||||
|
}
|
||||||
if (!config.debug) {
|
if (!config.debug) {
|
||||||
os << "Config file: " << config.configFilePath << std::endl;
|
os << "Config file: " << config.configFilePath << std::endl;
|
||||||
} else{
|
} else{
|
||||||
@@ -190,6 +229,8 @@ public:
|
|||||||
|
|
||||||
// Setup gTest class as a friend
|
// Setup gTest class as a friend
|
||||||
friend class configTestPrivateAccessor;
|
friend class configTestPrivateAccessor;
|
||||||
|
// -- Resource Manager is a friend of config so it can create a seperate instance
|
||||||
|
friend class ResourceManager;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
Reference in New Issue
Block a user