Repository navigation
Expand file tree
/
Copy pathconfig.cpp
More file actions
108 lines (97 loc) · 3.16 KB
/
Copy pathconfig.cpp
File metadata and controls
108 lines (97 loc) · 3.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include "engine/framework/io/config.h"
#include "engine/framework/io/filesystem.h"
#include "engine/framework/io/json.h"
#include "engine/framework/io/text.h"
#include "engine/framework/io/yaml.h"
#include <algorithm>
#include <cmath>
#include <sstream>
#include <stdexcept>
namespace engine::io {
namespace {
std::string strip_quotes(std::string value) {
value = trim_ascii_whitespace(std::move(value));
if (value.size() >= 2 && ((value.front() == '"' && value.back() == '"') || (value.front() == '\'' && value.back() == '\''))) {
return value.substr(1, value.size() - 2);
}
return value;
}
ConfigMap parse_lines(const std::string & text, char separator) {
ConfigMap config;
std::istringstream stream(text);
std::string line;
while (std::getline(stream, line)) {
line = trim_ascii_whitespace(std::move(line));
if (line.empty() || line[0] == '#') {
continue;
}
const auto pos = line.find(separator);
if (pos == std::string::npos) {
continue;
}
auto key = trim_ascii_whitespace(line.substr(0, pos));
auto value = strip_quotes(line.substr(pos + 1));
if (!key.empty()) {
config[std::move(key)] = std::move(value);
}
}
return config;
}
} // namespace
ConfigMap parse_flat_json_object(const std::string & text) {
const auto root = json::parse(text);
const auto & object = root.as_object();
ConfigMap config;
config.reserve(object.size());
for (const auto & [key, value] : object) {
if (value.is_string()) {
config[key] = value.as_string();
continue;
}
if (value.is_bool()) {
config[key] = value.as_bool() ? "true" : "false";
continue;
}
if (value.is_null()) {
config[key] = "null";
continue;
}
if (value.is_number()) {
const double number = value.as_number();
if (std::isfinite(number) && std::floor(number) == number) {
config[key] = std::to_string(static_cast<long long>(number));
} else {
std::ostringstream stream;
stream << number;
config[key] = stream.str();
}
continue;
}
throw std::runtime_error("flat json config values must be scalar");
}
return config;
}
ConfigMap parse_key_value_text(const std::string & text, char separator) {
return parse_lines(text, separator);
}
ConfigMap load_config_map(const std::filesystem::path & path) {
const auto text = read_text_file(path);
const auto ext = path.extension().string();
if (ext == ".json") {
return parse_flat_json_object(text);
}
if (ext == ".yaml" || ext == ".yml") {
return yaml::parse_scalar_mapping(text);
}
return parse_key_value_text(text);
}
std::vector<std::string> discover_config_keys(const ConfigMap & config) {
std::vector<std::string> keys;
keys.reserve(config.size());
for (const auto & [key, _] : config) {
keys.push_back(key);
}
std::sort(keys.begin(), keys.end());
return keys;
}
} // namespace engine::io