cpp-toolbox  0.0.1
A toolbox library for C++
Loading...
Searching...
No Matches
ini_struct.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <optional>
4#include <sstream>
5#include <string>
6#include <tuple>
7#include <type_traits>
8
11
12namespace toolbox::utils
13{
14namespace ini_detail
15{
16// Trait to detect std::optional
17template<typename T>
18struct is_optional : std::false_type
19{
20};
21
22template<typename U>
23struct is_optional<std::optional<U>> : std::true_type
24{
25};
26
27template<typename T>
28inline constexpr bool is_optional_v =
30
31template<typename T>
33{
34};
35
36template<typename U>
37struct optional_value_type<std::optional<U>>
38{
39 using type = U;
40};
41
42template<typename T>
44 std::remove_cv_t<std::remove_reference_t<T>>>::type;
45
46// Trait to detect if a type can be streamed from an istream
47template<typename T, typename = void>
48struct has_istream_operator : std::false_type
49{
50};
51
52template<typename T>
54 T,
55 std::void_t<decltype(std::declval<std::istream&>() >> std::declval<T&>())>>
56 : std::true_type
57{
58};
59
60template<typename T>
61inline constexpr bool has_istream_operator_v =
63
64// Parsing helpers ---------------------------------------------------------
65
66template<typename T>
67bool parse_non_optional(const std::string& input, T& output)
68{
69 std::stringstream ss(input);
70 if constexpr (std::is_same_v<T, bool>) {
71 std::string lower_input;
72 std::transform(input.begin(),
73 input.end(),
74 std::back_inserter(lower_input),
75 ::tolower);
76 if (lower_input == "true" || lower_input == "1") {
77 output = true;
78 return true;
79 } else if (lower_input == "false" || lower_input == "0") {
80 output = false;
81 return true;
82 } else {
83 return false;
84 }
85 } else if constexpr (std::is_integral_v<T>) {
86 if (input.size() > 2 && input[0] == '0'
87 && (input[1] == 'x' || input[1] == 'X'))
88 {
89 ss >> std::hex >> output;
90 } else {
91 ss >> output;
92 }
93 return ss.eof() && !ss.fail();
94 } else if constexpr (std::is_floating_point_v<T>) {
95 ss >> output;
96 return ss.eof() && !ss.fail();
97 } else if constexpr (std::is_same_v<T, std::string>) {
98 output = input;
99 return true;
100 } else {
101 if constexpr (has_istream_operator_v<T>) {
102 ss >> output;
103 return ss.eof() && !ss.fail();
104 } else {
105 LOG_WARN_S << "Unsupported type for INI parser: " << typeid(T).name();
106 return false;
107 }
108 }
109}
110
111template<typename T_Optional>
112bool parse_non_optional(const std::string& input, std::optional<T_Optional>& output)
113{
114 T_Optional value;
115 if (parse_non_optional(input, value)) {
116 output = value;
117 return true;
118 }
119 output = std::nullopt;
120 return false;
121}
122
123template<typename T>
124bool parse_value(const std::string& input, T& output)
125{
126 if constexpr (is_optional_v<T>) {
127 if (input.empty()) {
128 output = std::nullopt;
129 return true;
130 }
131 using value_type = optional_value_type_t<T>;
132 value_type parsed;
133 bool ok = parse_non_optional(input, parsed);
134 if (ok)
135 output = parsed;
136 else
137 output = std::nullopt;
138 return ok;
139 } else {
140 return parse_non_optional(input, output);
141 }
142}
143
144} // namespace ini_detail
145
146// Field descriptor -------------------------------------------------------
147
148template<typename Struct, typename Member>
150{
151 const char* section;
152 const char* key;
153 Member Struct::*member;
154};
155
156// Trait to associate a struct with field descriptors
157template<typename T>
159{
160 static constexpr auto fields = std::make_tuple();
161};
162
163// Load struct from ini_config_t -----------------------------------------
164
165template<typename Struct>
167 Struct& obj,
168 const std::string& base_section = "")
169{
170 bool success = true;
171 constexpr auto fields = ini_struct_traits<Struct>::fields;
172 std::apply(
173 [&](auto&&... field)
174 {
175 ([&]() {
176 using member_t = std::remove_reference_t<decltype(obj.*(field.member))>;
177 std::string section = base_section;
178 if (field.section && field.section[0] != '\0') {
179 if (!base_section.empty()) {
180 section += ".";
181 section += field.section;
182 } else {
183 section = field.section;
184 }
185 }
186
187 if (cfg.has(section, field.key)) {
188 member_t value{};
189 if (ini_detail::parse_value(cfg.get_string(section, field.key),
190 value))
191 {
192 obj.*(field.member) = value;
193 } else {
194 success = false;
195 }
196 }
197 }(), ...);
198 },
199 fields);
200 return success;
201}
202
203} // namespace toolbox::utils
204
205// Helper macros to declare reflection metadata -------------------------
206
207#define TOOLBOX_INI_FIELD(struct_type, member, section, key) \
208 toolbox::utils::ini_field_desc<struct_type, decltype(struct_type::member)>{ \
209 section, key, &struct_type::member }
210
211#define TOOLBOX_INI_STRUCT(struct_type, ...) \
212 template<> struct toolbox::utils::ini_struct_traits<struct_type> { \
213 static constexpr auto fields = std::make_tuple(__VA_ARGS__); \
214 };
215
Definition ini_config.hpp:11
bool has(const std::string &section, const std::string &key) const
std::string get_string(const std::string &section, const std::string &key, const std::string &default_value="") const
#define LOG_WARN_S
WARN级别流式日志的宏 / Macro for WARN level stream logging.
Definition thread_logger.hpp:1331
bool parse_value(const std::string &input, T &output)
Definition ini_struct.hpp:124
typename optional_value_type< std::remove_cv_t< std::remove_reference_t< T > > >::type optional_value_type_t
Definition ini_struct.hpp:44
constexpr bool is_optional_v
Definition ini_struct.hpp:28
constexpr bool has_istream_operator_v
Definition ini_struct.hpp:61
bool parse_non_optional(const std::string &input, T &output)
Definition ini_struct.hpp:67
< 用于 std::out_of_range/For std::out_of_range
Definition click.hpp:11
bool load_struct_from_ini(const ini_config_t &cfg, Struct &obj, const std::string &base_section="")
Definition ini_struct.hpp:166
Definition ini_struct.hpp:19
Definition ini_struct.hpp:150
const char * section
Definition ini_struct.hpp:151
const char * key
Definition ini_struct.hpp:152
Member Struct::* member
Definition ini_struct.hpp:153
Definition ini_struct.hpp:159
static constexpr auto fields
Definition ini_struct.hpp:160