Skip to content

Commit 6e762c7

Browse files
committed
Added Config class
1 parent 9c5a6cb commit 6e762c7

File tree

3 files changed

+227
-0
lines changed

3 files changed

+227
-0
lines changed

include/Config.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#ifndef CONFIG_H
2+
#define CONFIG_H
3+
4+
#include <map>
5+
#include <string>
6+
#include <utility>
7+
#include <fstream>
8+
9+
#include "Util.h"
10+
11+
class ConfigValue {
12+
private:
13+
std::string value;
14+
public:
15+
ConfigValue(const std::string& val);
16+
ConfigValue(const ConfigValue&) = default;
17+
ConfigValue(ConfigValue&&) = default;
18+
~ConfigValue() = default;
19+
ConfigValue& operator=(const ConfigValue&) = default;
20+
ConfigValue& operator=(ConfigValue&&) = default;
21+
22+
operator int() const;
23+
operator float() const;
24+
operator std::string() const;
25+
operator Coordinate() const;
26+
operator ScreenCoordinate() const;
27+
};
28+
29+
class Config {
30+
private:
31+
std::map<std::string, ConfigValue> values;
32+
33+
void init(std::istream& in);
34+
public:
35+
Config(std::istream& source);
36+
Config(std::fstream&& source);
37+
Config(const std::string& filename);
38+
Config(const Config&) = default;
39+
Config(Config&&) = default;
40+
~Config() = default;
41+
Config& operator=(const Config&) = default;
42+
Config& operator=(Config&&) = default;
43+
44+
const ConfigValue& operator[](const std::string& name) const;
45+
};
46+
47+
const Config& getConfigFile(const std::string& filename);
48+
const Config& getGraphicsConfig();
49+
50+
#endif

src/Config.cpp

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
#include "Config.h"
2+
3+
#include <sstream>
4+
#include <stdexcept>
5+
6+
#include "Util.h"
7+
8+
using std::string;
9+
using std::stringstream;
10+
using std::runtime_error;
11+
using std::istream;
12+
using std::fstream;
13+
14+
ConfigValue::ConfigValue(const string& value) : value(value) {
15+
16+
}
17+
18+
ConfigValue::operator int() const {
19+
return fromString<int>(value);
20+
}
21+
22+
ConfigValue::operator float() const {
23+
return fromString<float>(value);
24+
}
25+
26+
ConfigValue::operator string() const {
27+
return value;
28+
}
29+
30+
ConfigValue::operator Coordinate() const {
31+
stringstream stream(value);
32+
Coordinate ret;
33+
char c = stream.get();
34+
if(c != '(') {
35+
throw runtime_error("Attempt to read a coordinate out of a non-coordinate value");
36+
}
37+
stream >> ret.first;
38+
c = stream.get();
39+
if(c != ',') {
40+
throw runtime_error("Attempt to read a coordinate out of a non-coordinate value");
41+
}
42+
stream >> ret.second;
43+
return ret;
44+
}
45+
46+
ConfigValue::operator ScreenCoordinate() const {
47+
stringstream stream(value);
48+
ScreenCoordinate ret;
49+
char c = stream.get();
50+
if(c != '(') {
51+
throw runtime_error("Attempt to read a coordinate out of a non-coordinate value");
52+
}
53+
stream >> ret.first;
54+
c = stream.get();
55+
if(c != ',') {
56+
throw runtime_error("Attempt to read a coordinate out of a non-coordinate value");
57+
}
58+
stream >> ret.second;
59+
return ret;
60+
}
61+
62+
Config::Config(istream& source) {
63+
init(source);
64+
}
65+
66+
Config::Config(fstream&& source) {
67+
init(source);
68+
}
69+
70+
Config::Config(const string& filename) {
71+
fstream source(filename, fstream::in);
72+
init(source);
73+
}
74+
75+
void Config::init(istream& source) {
76+
string line;
77+
while(source) {
78+
std::getline(source, line);
79+
if(line[0] == '#' || line.find('=') == string::npos) {
80+
continue;
81+
}
82+
string name = line.substr(0, line.find('='));
83+
string value = line.substr(line.find('=') + 1);
84+
values.insert(std::make_pair(name, ConfigValue(value)));
85+
}
86+
}
87+
88+
const ConfigValue& Config::operator[](const string& name) const {
89+
auto it = values.find(name);
90+
if(it == values.end()) {
91+
throw runtime_error("No such key in the config");
92+
} else {
93+
return it->second;
94+
}
95+
}
96+
97+
const Config& getConfigFile(const std::string& filename) {
98+
static std::map<std::string, Config> configs;
99+
100+
auto it = configs.find(filename);
101+
if(it == configs.end()) {
102+
fstream file(filename);
103+
if(!file) {
104+
throw runtime_error("Cannot open file " + filename);
105+
}
106+
return configs.insert(std::make_pair(filename, Config(file))).first->second;
107+
} else {
108+
return it->second;
109+
}
110+
}
111+
112+
const Config& getGraphicsConfig() {
113+
return getConfigFile("resources/graphics.conf");
114+
}

tests/testConfig.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#include "UnitTest++.h"
2+
#include "Config.h"
3+
4+
using std::string;
5+
using std::stringstream;
6+
7+
TEST(readOneString) {
8+
stringstream file("variable=value");
9+
Config config(file);
10+
11+
CHECK((string)config["variable"] == "value");
12+
}
13+
14+
TEST(readTwoStrings) {
15+
stringstream file("var_a=val_a\nvar_b=val_b\n");
16+
Config config(file);
17+
18+
CHECK((string)config["var_a"] == "val_a");
19+
CHECK((string)config["var_b"] == "val_b");
20+
}
21+
22+
TEST(readIntAndString) {
23+
stringstream file("string=hello\nint=5\n");
24+
Config config(file);
25+
26+
CHECK((string)config["string"] == "hello");
27+
CHECK((int)config["int"] == 5);
28+
}
29+
30+
TEST(readFloat) {
31+
stringstream file("float=5.0\n");
32+
Config config(file);
33+
34+
CHECK((float)config["float"] == 5.0f);
35+
}
36+
37+
TEST(readCommentsEmptyLines) {
38+
stringstream file("#this is a string\nstring=hello\n#we just had a string\n\n\n\n\n");
39+
Config config(file);
40+
41+
CHECK((string)config["string"] == "hello");
42+
}
43+
44+
TEST(readInvalid) {
45+
stringstream file("variable=value");
46+
Config config(file);
47+
48+
CHECK_THROW((string)config["string"] == "hello", std::runtime_error);
49+
}
50+
51+
TEST(readCoordinate) {
52+
stringstream file("coord=(1,2)");
53+
Config config(file);
54+
55+
CHECK(Coordinate({1, 2}) == (Coordinate)config["coord"]);
56+
}
57+
58+
TEST(readScreenCoordinate) {
59+
stringstream file("coord=(1.5,2.5)");
60+
Config config(file);
61+
62+
CHECK(ScreenCoordinate({1.5, 2.5}) == (ScreenCoordinate)config["coord"]);
63+
}

0 commit comments

Comments
 (0)