Skip to content

Commit 728535e

Browse files
authored
Interface Breakout Refactoring (#48)
* Fixing all the tests * updates to config naming and tests * cleaning up my mess * temporary fixes for vectors * Addressing remaining comments in PR 48 * Addressing comments in PR 48
1 parent 2744ad7 commit 728535e

3 files changed

Lines changed: 271 additions & 156 deletions

File tree

include/Configuration.hpp

Lines changed: 99 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -19,107 +19,149 @@
1919
#ifndef CONFIGURATION_HPP_
2020
#define CONFIGURATION_HPP_
2121

22+
#include <algorithm>
23+
#include <iostream>
2224
#include <memory>
25+
#include <optional>
2326
#include <string>
2427
#include <variant>
2528
#include <vector>
2629

2730
/// @brief Namespace defining Data Containers
2831
namespace Data {
2932

33+
using ReturnType =
34+
std::variant<int, double, float, std::string, bool, char>;
35+
3036
/// @brief Declaration of wrapper class for property tree parser
3137
class PTree;
3238

39+
class IGettable {
40+
public:
41+
/// @brief Default template for getting parameters from the config
42+
/// @param str String key to search for
43+
/// @return The value searched for
44+
virtual ReturnType get(std::string, ReturnType) = 0;
45+
46+
/// @brief Template for the optional parameters
47+
/// @param str String key to search for
48+
/// @return The optional value searched for
49+
virtual std::shared_ptr<ReturnType> get_optional(std::string,
50+
ReturnType) = 0;
51+
virtual std::vector<ReturnType> getVector(std::string) = 0;
52+
53+
[[deprecated("This function is not intended to be permanent. getVector "
54+
"will recieve future focus.")]] virtual std::vector<int>
55+
getIntVector(std::string) = 0;
56+
[[deprecated("This function is not intended to be permanent. getVector "
57+
"will recieve future focus.")]] virtual std::vector<double>
58+
getDoubleVector(std::string) = 0;
59+
[[deprecated(
60+
"This function is not intended to be permanent. getVector will "
61+
"recieve future focus.")]] virtual std::vector<std::string>
62+
getStringVector(std::string) = 0;
63+
};
64+
65+
class IParseable {
66+
public:
67+
/// @brief Parse a single string to a vector
68+
/// @param string to parse
69+
/// @return vector containing parsed string
70+
virtual std::vector<ReturnType> parse(std::string) = 0;
71+
72+
/// @brief Parse a single string to a vector
73+
/// @param string to parse
74+
/// @param delimiter string is being parsed with
75+
/// @return vector containing parsed string
76+
virtual std::vector<ReturnType> parse(std::string, std::string) = 0;
77+
};
78+
3379
/// @brief Interface used for Configuration, provides guaranteed methods
34-
class IConfiguration {
80+
class IConfigable : public virtual IGettable, public virtual IParseable {
3581
public:
36-
virtual ~IConfiguration() = default;
37-
virtual std::vector<std::string>
38-
parseString2VectorOfStrings(std::string st) = 0;
39-
virtual std::vector<int> parseString2VectorOfInts(std::string st) = 0;
40-
virtual std::vector<std::string> getStringVector(std::string str) = 0;
41-
virtual std::vector<int> getIntVector(std::string str) = 0;
4282
virtual std::vector<std::string>
4383
getSectionCategories(std::string section) = 0;
4484
};
4585

4686
/// @brief Type definition for an easy to use pointer to a configuration
4787
/// interface
48-
using IConfigurationPtr = std::shared_ptr<Data::IConfiguration>;
88+
using IConfigablePtr = std::shared_ptr<Data::IConfigable>;
4989

5090
/// @brief Class describing a standard configuration file
51-
class Configuration : public IConfiguration {
91+
class Config : public IConfigable {
5292
private:
5393
std::unique_ptr<PTree> dmTree;
94+
ReturnType convert_type(std::string);
95+
std::string trim(const std::string &str);
5496

5597
public:
5698
/// @brief Default constructor with no file
57-
Configuration();
99+
Config();
58100

59101
/// @brief Primary Constructor used with a file
60102
/// @param configFile string path to the config file
61-
Configuration(std::string configFile);
103+
Config(std::string configFile);
62104

63105
/// @brief Default Destructor
64-
~Configuration();
106+
~Config();
65107

66-
/// @brief Default template for getting parameters from the config
67-
/// @param T Type to return
68-
/// @param str String key to search for
69-
/// @return The value searched for of type T
70-
template <typename T> T get(std::string str);
108+
ReturnType get(std::string str, ReturnType default_value) override;
71109

72-
/// @brief Template for the optional parameters
73-
/// @param T Type to return
74-
/// @param str String key to search for
75-
/// @return The optional value searched for of type T
76-
template <typename T> std::shared_ptr<T> optional(std::string str);
77-
78-
/// @brief Helper function to parse a string to a vector of strings
79-
/// @param st string to parse
80-
/// @return vector of parsed strings
81-
std::vector<std::string>
82-
parseString2VectorOfStrings(std::string st) override;
110+
std::vector<ReturnType> getVector(std::string str) override;
83111

84-
/// @brief Helper function to parse a string to a vector of ints
85-
/// @param st string to parse
86-
/// @return vector of parsed ints
87-
std::vector<int> parseString2VectorOfInts(std::string st) override;
112+
std::shared_ptr<ReturnType>
113+
get_optional(std::string str, ReturnType default_value) override;
88114

89-
/// @brief Wrapper function around `optional` and
90-
/// `parseString2VectorofStrings`.
91-
/// @param str string to parse
92-
/// @return vector of parsed strings
93-
std::vector<std::string> getStringVector(std::string str) override {
94-
std::shared_ptr<std::string> value =
95-
this->optional<std::string>(str);
96-
if (value) {
97-
return this->parseString2VectorOfStrings(*value);
98-
} else {
99-
return {};
100-
}
115+
std::vector<ReturnType> parse(std::string str) override {
116+
return this->parse(str, ",");
101117
}
102118

103-
/// @brief Wrapper function around `optional` and
104-
/// `parseString2VectorofInts`.
105-
/// @param str string to parse
106-
/// @return vector of parsed ints
107-
std::vector<int> getIntVector(std::string str) override {
108-
std::shared_ptr<std::string> value =
109-
this->optional<std::string>(str);
110-
if (value) {
111-
return this->parseString2VectorOfInts(*value);
112-
} else {
113-
return {};
114-
}
115-
}
119+
/// @brief Helper function to parse a string to a vector of strings
120+
/// @param st string to parse
121+
/// @return vector of parsed strings
122+
std::vector<ReturnType> parse(std::string str,
123+
std::string delimiter) override;
116124

117125
/// @brief Helper function to return all the categories belonging to the
118126
/// provided section
119127
/// @param section String describing the section to search
120128
/// @return A vector of the categories avaliable
121129
std::vector<std::string>
122130
getSectionCategories(std::string section) override;
131+
132+
std::vector<int> getIntVector(std::string str) override {
133+
std::string numbers = "";
134+
numbers = std::get<std::string>(this->get(str, numbers));
135+
std::vector<ReturnType> returned = this->parse(numbers);
136+
std::vector<int> casted_returned = {};
137+
std::for_each(returned.begin(), returned.end(), [&](ReturnType &n) {
138+
casted_returned.push_back(std::get<int>(n));
139+
});
140+
return casted_returned;
141+
}
142+
143+
std::vector<double> getDoubleVector(std::string str) override {
144+
std::string numbers = "";
145+
numbers = std::get<std::string>(this->get(str, numbers));
146+
std::vector<ReturnType> returned = this->parse(numbers);
147+
std::vector<double> casted_returned = {};
148+
std::for_each(returned.begin(), returned.end(), [&](ReturnType &n) {
149+
casted_returned.push_back(std::get<double>(n));
150+
});
151+
return casted_returned;
152+
}
153+
154+
std::vector<std::string> getStringVector(std::string str) override {
155+
std::string strings = "";
156+
strings = std::get<std::string>(this->get(str, strings));
157+
std::vector<ReturnType> returned = this->parse(strings);
158+
std::vector<std::string> casted_returned;
159+
std::for_each(
160+
returned.begin(), returned.end(), [&](Data::ReturnType &n) {
161+
casted_returned.push_back(std::get<std::string>(n));
162+
});
163+
return casted_returned;
164+
}
123165
};
124166
} // namespace Data
125167
#endif

src/Configuration.cpp

Lines changed: 88 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -4,99 +4,93 @@
44
#include <boost/property_tree/ptree.hpp>
55

66
#include <cassert>
7+
#include <limits>
8+
#include <type_traits>
9+
#include <typeinfo>
710

811
namespace Data {
912
class PTree {
1013
public:
1114
boost::property_tree::ptree ptree;
1215
};
1316

14-
Configuration::Configuration() { dmTree = std::make_unique<PTree>(); }
17+
Config::Config() { dmTree = std::make_unique<PTree>(); }
1518

16-
Configuration::Configuration(std::string configFile) {
19+
Config::Config(std::string configFile) {
1720
dmTree = std::make_unique<PTree>();
1821
std::ifstream f(configFile.c_str());
1922
assert((f.good(), "Valid Config File Provided"));
2023

2124
read_ini(configFile, this->dmTree->ptree);
2225
}
2326

24-
Configuration::~Configuration(){};
25-
26-
/// @brief Default template for getting parameters from the config
27-
/// @param T Type to return
28-
/// @param str String key to search for
29-
/// @return The value searched for of type T
30-
template <typename T> T Configuration::get(std::string str) {
31-
return this->dmTree->ptree.get<T>(str);
27+
Config::~Config(){};
28+
29+
ReturnType Config::get(std::string str, ReturnType default_value) {
30+
if (std::holds_alternative<int>(default_value)) {
31+
return this->dmTree->ptree.get<int>(str);
32+
} else if (std::holds_alternative<double>(default_value)) {
33+
return this->dmTree->ptree.get<double>(str);
34+
} else if (std::holds_alternative<float>(default_value)) {
35+
return this->dmTree->ptree.get<float>(str);
36+
} else if (std::holds_alternative<bool>(default_value)) {
37+
return this->dmTree->ptree.get<bool>(str);
38+
} else if (std::holds_alternative<char>(default_value)) {
39+
return this->dmTree->ptree.get<char>(str);
40+
} else {
41+
return this->dmTree->ptree.get<std::string>(str);
42+
}
3243
}
3344

34-
template int Configuration::get<int>(std::string str);
35-
template bool Configuration::get<bool>(std::string str);
36-
template float Configuration::get<float>(std::string str);
37-
template double Configuration::get<double>(std::string str);
38-
template char Configuration::get<char>(std::string str);
39-
template std::string Configuration::get<std::string>(std::string str);
40-
41-
/// @brief Template for the optional parameters
42-
/// @param T Type to return
43-
/// @param str String key to search for
44-
/// @return The optional value searched for of type T
45-
template <typename T>
46-
std::shared_ptr<T> Configuration::optional(std::string str) {
47-
boost::optional<T> result = this->dmTree->ptree.get_optional<T>(str);
48-
if (result) {
49-
return std::make_shared<T>(*result);
45+
std::vector<ReturnType> Config::getVector(std::string str) {
46+
47+
try {
48+
std::string result =
49+
std::get<std::string>(this->get(str, std::string("")));
50+
51+
return this->parse(result);
52+
} catch (const std::exception &e) {
53+
return {};
5054
}
51-
return nullptr;
5255
}
5356

54-
template std::shared_ptr<int> Configuration::optional<int>(std::string str);
55-
template std::shared_ptr<bool>
56-
Configuration::optional<bool>(std::string str);
57-
template std::shared_ptr<float>
58-
Configuration::optional<float>(std::string str);
59-
template std::shared_ptr<double>
60-
Configuration::optional<double>(std::string str);
61-
template std::shared_ptr<char>
62-
Configuration::optional<char>(std::string str);
63-
template std::shared_ptr<std::string>
64-
Configuration::optional<std::string>(std::string str);
65-
66-
std::vector<std::string>
67-
Configuration::parseString2VectorOfStrings(std::string st) {
68-
std::stringstream ss(st);
69-
std::vector<std::string> result = {};
70-
71-
while (ss.good()) {
72-
std::string substr;
73-
getline(ss, substr, ',');
74-
// remove leading whitespace
75-
int first = substr.find_first_not_of(' ');
76-
// break and return if the string is empty
77-
// TODO log warning when this happens
78-
if (std::string::npos == first) {
79-
break;
57+
std::shared_ptr<ReturnType> Config::get_optional(std::string str,
58+
ReturnType default_value) {
59+
try {
60+
ReturnType val = this->get(str, default_value);
61+
// This is the string error check
62+
if (std::holds_alternative<std::string>(val) &&
63+
std::get<std::string>(val).empty()) {
64+
return nullptr;
8065
}
81-
int last = substr.find_last_not_of(' ');
82-
result.push_back(substr.substr(first, (last - first + 1)));
66+
return std::make_shared<ReturnType>(val);
67+
} catch (const boost::property_tree::ptree_error &e) {
68+
return nullptr;
8369
}
84-
return result;
8570
}
8671

87-
std::vector<int> Configuration::parseString2VectorOfInts(std::string st) {
88-
std::vector<int> result = {};
89-
90-
std::istringstream iss(st);
72+
std::vector<ReturnType> Config::parse(std::string str,
73+
std::string delimiter) {
74+
std::vector<ReturnType> ret_vec;
75+
size_t pos = 0;
9176
std::string token;
92-
while (std::getline(iss, token, ',')) {
93-
result.push_back(std::stoi(token));
77+
while ((pos = str.find(delimiter)) != std::string::npos) {
78+
token = str.substr(0, pos);
79+
std::string trimmed_token = trim(token);
80+
ret_vec.push_back(this->convert_type(trimmed_token));
81+
str.erase(0, pos + delimiter.length());
82+
while (!str.empty() && str.at(0) == ' ') {
83+
str.erase(0, 1);
84+
}
85+
}
86+
if (!str.empty()) {
87+
ret_vec.push_back(this->convert_type(str));
9488
}
95-
return result;
89+
90+
return ret_vec;
9691
}
9792

98-
std::vector<std::string>
99-
Configuration::getSectionCategories(std::string section) {
93+
std::vector<std::string> Config::getSectionCategories(std::string section) {
10094
boost::property_tree::ptree subTree =
10195
this->dmTree->ptree.get_child(section);
10296
std::vector<std::string> keyList;
@@ -106,4 +100,33 @@ namespace Data {
106100
}
107101
return keyList;
108102
}
103+
104+
ReturnType Config::convert_type(std::string str) {
105+
char *endptr;
106+
107+
int i_res = std::strtol(str.c_str(), &endptr, 10);
108+
if (endptr != str.c_str() && *endptr == '\0') {
109+
return i_res;
110+
}
111+
112+
double d_res = std::strtod(str.c_str(), &endptr);
113+
if (endptr != str.c_str() && *endptr == '\0') {
114+
return d_res;
115+
}
116+
117+
float f_res = std::strtof(str.c_str(), &endptr);
118+
if (endptr != str.c_str() && *endptr == '\0') {
119+
return f_res;
120+
}
121+
return str;
122+
}
123+
124+
std::string Config::trim(const std::string &str) {
125+
size_t first = str.find_first_not_of(' ');
126+
if (std::string::npos == first) {
127+
return str;
128+
}
129+
size_t last = str.find_last_not_of(' ');
130+
return str.substr(first, (last - first + 1));
131+
}
109132
} // namespace Data

0 commit comments

Comments
 (0)