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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
|
#ifndef KAZOESETTINGS_H
#define KAZOESETTINGS_H
#include <functional>
#include <memory>
#include <variant>
#include <string>
#include <algorithm>
/** @brief Key type for settings, composed of category and name */
using SettingKey = std::pair<std::string, std::string>;
/** @brief Value type that can hold string, int, double or boolean */
using SettingValue = std::variant<std::string, int, double, bool>;
namespace KaZoe {
class SettingsPrivate;
/**
* @brief Main class for managing KaZoe settings
*
* This class provides a thread-safe interface for storing and retrieving
* configuration settings with support for different value types.
*/
class Settings
{
public:
/** @brief Constructs a new Settings instance */
explicit Settings();
/** @brief Virtual destructor */
virtual ~Settings();
/**
* @brief Retrieves a setting value
* @param key The setting key
* @param category The setting category (optional)
* @param def Default value if setting not found (optional)
* @return The setting value or default if not found
*/
SettingValue get(const std::string &key, const std::string &category = "", SettingValue def = SettingValue()) const;
/**
* @brief Sets a setting value
* @param key The setting key
* @param value The value to set
* @param category The setting category (optional)
* @return true if successful, false otherwise
*/
bool set(const std::string &key, SettingValue value, const std::string &category = "");
/**
* @brief Gets the current instance identifier
* @return The instance ID string, by default, this is the excecutable filename
*/
std::string id() const;
/**
* @brief Sets the instance identifier
* @param newid The new ID to set
*/
void setId(const std::string &newid);
/**
* @brief Sets a callback for setting changes notification
* @param callback Function to call when settings change
*/
void setNotifier(const std::function<void(const std::string&, const std::string&, SettingValue)>& callback);
/**
* @brief Gets the number of settings
* @return The total count of settings
*/
std::size_t size() const;
/**
* @brief Iterates over all settings in a thread-safe manner
* @param callback Function called for each key-value pair
*/
void forEach(const std::function<void(const SettingKey&, const SettingValue&)>& callback) const;
private:
std::unique_ptr<SettingsPrivate> m_ptr; ///< Private implementation pointer
};
/**
* @brief Functor to convert SettingValue variants to string
*
* Provides string conversion for all supported setting value types
*/
struct settingValueFunctor {
std::string operator()(const std::string &x) const { return x; }
std::string operator()(int x) const { return std::to_string(x); }
std::string operator()(double x) const { return std::to_string(x); }
std::string operator()(bool x) const { return x ? "true" : "false"; }
};
/**
* @brief Convert a SettingValue into a string for display
* @param value Input SettingValue to convert
* @return std::string containing the converted value
*/
static inline std::string valueToStr(const SettingValue &value)
{
return std::visit(settingValueFunctor(), value);
}
/**
* @brief Check if a string represents a valid numeric value
* @param str String to check
* @return true if string is numeric, false otherwise
*/
static inline bool is_numeric(const std::string& str) {
return !str.empty() &&
str.find_first_not_of("0123456789.-") == std::string::npos &&
(std::count(str.begin(), str.end(), '.') <= 1) &&
(std::count(str.begin(), str.end(), '-') <= 1) &&
(str[0] == '-' || std::isdigit(str[0]));
}
/**
* @brief Convert a string to appropriate SettingValue type
* @param value Input string to convert
* @return SettingValue containing the converted value
*
* Conversion rules:
* - Quoted strings -> string without quotes
* - Numeric values -> int or double
* - "true"/"on" -> boolean true
* - "false"/"off" -> boolean false
* - Other -> string
*/
static inline SettingValue makeValue(const std::string &value)
{
if(value.starts_with('"') || value.starts_with('\''))
{
return value.substr(1, value.length() - 2);
}
if(is_numeric(value))
{
// double
if(value.find('.') != value.npos)
{
return std::stod(value);
}
else
{
return std::stoi(value);
}
}
// To Lower case
std::string lvalue = value;
std::transform(lvalue.begin(), lvalue.end(), lvalue.begin(),
[](unsigned char c){ return std::tolower(c); });
// bool true
if(lvalue == "true" || lvalue == "on")
{
return true;
}
// bool false
if(lvalue == "false" || lvalue == "off")
{
return false;
}
// else, string without quote
return value;
}
};
#endif // KAZOESETTINGS_H
|