-
Notifications
You must be signed in to change notification settings - Fork 0
/
Config.cpp
104 lines (93 loc) · 4.88 KB
/
Config.cpp
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
#include "ConfigKeyRegister.cpp"
#include "MultipleException.hpp"
template<typename ConfigName>
safini::Config<ConfigName>::Config(const std::string_view filename):
m_IniReader(filename)
{
for(const auto& [key, typeHash, deserializeFunc, paramType] : _register::getRegisteredKeys<ConfigName>())
{
const std::size_t i = key.find('.');
const bool hasSection = i != key.npos;
//totally safe string operations
const std::string name(hasSection ? std::next(std::begin(key), i+1) : std::begin(key), std::end(key));
const std::string section(std::begin(key), hasSection ? std::next(std::begin(key), i) : std::begin(key));
const auto param = m_IniReader.get(name, section);
if(!param.has_value() && paramType == _register::Required)
throw std::runtime_error(std::string("No parameter \'")
.append(key)
.append("\' in config file \'")
.append(filename)
.append(1, '\''));
if(!param.has_value() && paramType == _register::Optional)
continue;
try
{
m_KeysMap.emplace(std::make_pair(key, typeHash), deserializeFunc(param.value()));
}
catch(const std::exception& exc)
{
if(paramType == _register::Required)
{
MultipleException multipleException(exc.what());
multipleException.addException(std::string("Unable to convert \'")
.append(key)
.append("\'=\'")
.append(param.value())
.append("\' to whatever type it belongs to")
.append(" from config file \'")
.append(filename)
.append(1, '\''));
throw multipleException;
}
}
}
}
template<typename ConfigName>
template<typename ReturnType, const safini::StringLiteral key, const auto deserializeFunc>
const ReturnType& safini::Config<ConfigName>::extract() const noexcept
{
//the code may break if you request volatile qualified thing
//probably breaks at AnyTypeStorage.hpp:22
//when you access volatile object through non volatile pointer, it's UB
//see https://en.cppreference.com/w/cpp/language/cv
//also see https://stackoverflow.com/questions/39583491/c-volatile-placement-new
static_assert(!std::is_volatile_v<ReturnType>, "Volatile qualified parameters in config are not allowed");
//registers the key to be a required key
//(void) supresses warning -Wunused-value
(void)_register::_registerKey<ConfigName,
key,
getHashFromType<const ReturnType>(),
deserializeFunc,
_register::Required>;
return m_KeysMap.at(std::make_pair(std::string_view(key), getHashFromType<const ReturnType>())).template get<const ReturnType>();
}
template<typename ConfigName>
template<typename ReturnType, const safini::StringLiteral key, const auto deserializeFunc>
const ReturnType& safini::Config<ConfigName>::extractOr(const ReturnType& fallbackValue) const noexcept
{
static_assert(!std::is_volatile_v<ReturnType>, "Volatile qualified parameters in config are not allowed");
(void)_register::_registerKey<ConfigName,
key,
getHashFromType<const ReturnType>(),
deserializeFunc,
_register::Optional>;
const auto param = m_KeysMap.find(std::make_pair(std::string_view(key), getHashFromType<const ReturnType>()));
if(param == m_KeysMap.cend())
return fallbackValue;
return param->second.template get<const ReturnType>();
}
template<typename ConfigName>
template<typename ReturnType, const safini::StringLiteral key, const auto deserializeFunc>
std::optional<std::reference_wrapper<const ReturnType>> safini::Config<ConfigName>::tryExtract() const noexcept
{
static_assert(!std::is_volatile_v<ReturnType>, "Volatile qualified parameters in config are not allowed");
(void)_register::_registerKey<ConfigName,
key,
getHashFromType<const ReturnType>(),
deserializeFunc,
_register::Optional>;
const auto param = m_KeysMap.find(std::make_pair(std::string_view(key), getHashFromType<const ReturnType>()));
if(param == m_KeysMap.cend())
return {};
return param->second.template get<const ReturnType>();
}