From c830fa053727a0e64cc16445da6a9a18d6f09dba Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Sun, 3 Aug 2014 23:14:56 +1000 Subject: [PATCH] ConfigUtility now supports recursion; is a Singleton If you have "config.next" set, the config system will load that as another config file. Higher config files have a higher precedence over subfiles when conflicting keys are encountered. * Added singleton.hpp, containing Singleton * ConfigUtility now inherits from Singleton * Tweaked timer.*pp layouts --- common/debugging/timer.cpp | 20 ++++++++- common/debugging/timer.hpp | 12 +++--- common/utilities/config_utility.cpp | 44 +++++++++++++++----- common/utilities/config_utility.hpp | 24 ++++++----- common/utilities/singleton.hpp | 63 +++++++++++++++++++++++++++++ 5 files changed, 135 insertions(+), 28 deletions(-) create mode 100644 common/utilities/singleton.hpp diff --git a/common/debugging/timer.cpp b/common/debugging/timer.cpp index be3636a..29d107a 100644 --- a/common/debugging/timer.cpp +++ b/common/debugging/timer.cpp @@ -21,9 +21,25 @@ */ #include "timer.hpp" +Timer::Timer(): start(Timer::Clock::now()) { + // +} + +Timer::Timer(std::string s): name(s), start(Timer::Clock::now()) { + // +} + +void Timer::Start() { + start = Clock::now(); +} + +void Timer::Stop() { + timeSpan = Clock::now() - start; +} + std::ostream& operator<<(std::ostream& os, Timer& t) { os << t.GetName() << ": "; - os << std::chrono::duration_cast(t.GetTime()).count(); - os << "ns"; + os << std::chrono::duration_cast(t.GetTime()).count(); + os << "ms"; return os; } diff --git a/common/debugging/timer.hpp b/common/debugging/timer.hpp index 7f8f38b..dfafec9 100644 --- a/common/debugging/timer.hpp +++ b/common/debugging/timer.hpp @@ -30,15 +30,15 @@ class Timer { public: typedef std::chrono::high_resolution_clock Clock; - Timer() = default; - Timer(std::string s) : name(s), start(Clock::now()) {}; + Timer(); + Timer(std::string s); ~Timer() = default; - inline void Start() { start = Clock::now(); } - inline void Stop() { time = Clock::now() - start; } + inline void Start(); + inline void Stop(); //accessors and mutators - Clock::duration GetTime() { return time; } + Clock::duration GetTime() { return timeSpan; } std::string SetName(std::string s) { return name = s; } std::string GetName() { return name; } @@ -46,7 +46,7 @@ public: private: std::string name; Clock::time_point start; - Clock::duration time; + Clock::duration timeSpan; }; std::ostream& operator<<(std::ostream& os, Timer& t); diff --git a/common/utilities/config_utility.cpp b/common/utilities/config_utility.cpp index 4b1f797..e34a2db 100644 --- a/common/utilities/config_utility.cpp +++ b/common/utilities/config_utility.cpp @@ -26,11 +26,22 @@ #include void ConfigUtility::Load(std::string fname) { - //TODO: recursive rerouting? + //clear the stored configuration + configMap.clear(); + //pass to the recursive method + configMap = Read(fname); +} + +ConfigUtility::table_t ConfigUtility::Read(std::string fname) { + //read in and return this file's data + table_t retTable; std::ifstream is(fname); if (!is.is_open()) { - throw(std::runtime_error("Failed to open config file")); + std::string msg; + msg += "Failed to open a config file: "; + msg += fname; + throw(std::runtime_error(msg)); } std::string key, val; @@ -71,35 +82,48 @@ void ConfigUtility::Load(std::string fname) { } //save the pair - table[key] = val; + retTable[key] = val; } is.close(); + + //load in any subordinate config files + //TODO: Possibility of nesting config levels? + if (retTable.find("config.next") != retTable.end()) { + table_t subTable = Read(retTable["config.next"]); + retTable.insert(subTable.begin(), subTable.end()); + } + + return retTable; } +//------------------------- +//Convert to a type +//------------------------- + std::string& ConfigUtility::String(std::string s) { - return table[s]; + return configMap[s]; } int ConfigUtility::Integer(std::string s) { - std::map::iterator it = table.find(s); - if (it == table.end()) { + table_t::iterator it = configMap.find(s); + if (it == configMap.end()) { return 0; } return atoi(it->second.c_str()); } double ConfigUtility::Double(std::string s) { - std::map::iterator it = table.find(s); - if (it == table.end()) { + table_t::iterator it = configMap.find(s); + if (it == configMap.end()) { return 0.0; } return atof(it->second.c_str()); } bool ConfigUtility::Boolean(std::string s) { - std::map::iterator it = table.find(s); - if (it == table.end()) { + table_t::iterator it = configMap.find(s); + if (it == configMap.end()) { return false; } return it->second == "true"; diff --git a/common/utilities/config_utility.hpp b/common/utilities/config_utility.hpp index 3ea8448..8b85528 100644 --- a/common/utilities/config_utility.hpp +++ b/common/utilities/config_utility.hpp @@ -22,14 +22,13 @@ #ifndef CONFIGUTILITY_HPP_ #define CONFIGUTILITY_HPP_ +#include "singleton.hpp" + #include #include -class ConfigUtility { +class ConfigUtility : public Singleton { public: - ConfigUtility() = default; - ConfigUtility(std::string s) { Load(s); } - void Load(std::string fname); //convert to a type @@ -39,16 +38,21 @@ public: bool Boolean(std::string); //shorthand - inline std::string& operator[](std::string s) { return String(s); } + inline std::string& operator[](std::string s) { return configMap[s]; } inline int Int(std::string s) { return Integer(s); } inline bool Bool(std::string s) { return Boolean(s); } - //OO breaker - std::map* GetMap() { - return &table; - } private: - std::map table; + typedef std::map table_t; + + friend Singleton; + + ConfigUtility() = default; + ~ConfigUtility() = default; + + table_t Read(std::string fname); + + table_t configMap; }; #endif diff --git a/common/utilities/singleton.hpp b/common/utilities/singleton.hpp new file mode 100644 index 0000000..379003a --- /dev/null +++ b/common/utilities/singleton.hpp @@ -0,0 +1,63 @@ +/* Copyright: (c) Kayne Ruse 2014 + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. +*/ +#ifndef SINGLETON_HPP_ +#define SINGLETON_HPP_ + +#include + +template +class Singleton { +public: + static T& GetSingleton() { + if (!ptr) { + throw(std::logic_error("This singleton has not been created")); + } + return *ptr; + } + static void Create() { + if (ptr) { + throw(std::logic_error("This singleton has already been created")); + } + ptr = new T(); + } + static void Delete() { + if (!ptr) { + throw(std::logic_error("A non-existant singleton cannot be deleted")); + } + delete ptr; + ptr = nullptr; + } + +protected: + Singleton() = default; + Singleton(Singleton const&) = default; + Singleton(Singleton&&) = default; + ~Singleton() = default; + +private: + static T* ptr; +}; + +template +T* Singleton::ptr = nullptr; + +#endif \ No newline at end of file