1#pragma once
2
3/**
4 * This file implements some functions that are dependent on Field type.
5 * Unlike SettingsCollection.h, we only have to include it once for each
6 * instantiation of SettingsCollection<>.
7 */
8
9#include <Common/SettingsChanges.h>
10
11namespace DB
12{
13namespace details
14{
15 struct SettingsCollectionUtils
16 {
17 static void serializeName(const StringRef & name, WriteBuffer & buf);
18 static String deserializeName(ReadBuffer & buf);
19 static void serializeFlag(bool flag, WriteBuffer & buf);
20 static bool deserializeFlag(ReadBuffer & buf);
21 static void skipValue(ReadBuffer & buf);
22 static void warningNameNotFound(const StringRef & name);
23 [[noreturn]] static void throwNameNotFound(const StringRef & name);
24 };
25}
26
27
28template <class Derived>
29size_t SettingsCollection<Derived>::MemberInfos::findIndex(const StringRef & name) const
30{
31 auto it = by_name_map.find(name);
32 if (it == by_name_map.end())
33 return static_cast<size_t>(-1); // npos
34 return it->second;
35}
36
37
38template <class Derived>
39size_t SettingsCollection<Derived>::MemberInfos::findIndexStrict(const StringRef & name) const
40{
41 auto it = by_name_map.find(name);
42 if (it == by_name_map.end())
43 details::SettingsCollectionUtils::throwNameNotFound(name);
44 return it->second;
45}
46
47
48template <class Derived>
49const typename SettingsCollection<Derived>::MemberInfo * SettingsCollection<Derived>::MemberInfos::find(const StringRef & name) const
50{
51 auto it = by_name_map.find(name);
52 if (it == by_name_map.end())
53 return nullptr;
54 else
55 return &infos[it->second];
56}
57
58
59template <class Derived>
60const typename SettingsCollection<Derived>::MemberInfo & SettingsCollection<Derived>::MemberInfos::findStrict(const StringRef & name) const
61{
62 return infos[findIndexStrict(name)];
63}
64
65
66template <class Derived>
67void SettingsCollection<Derived>::MemberInfos::add(MemberInfo && member)
68{
69 size_t index = infos.size();
70 infos.emplace_back(member);
71 by_name_map.emplace(infos.back().name, index);
72}
73
74
75template <class Derived>
76const typename SettingsCollection<Derived>::MemberInfos &
77SettingsCollection<Derived>::members()
78{
79 static const MemberInfos the_instance;
80 return the_instance;
81}
82
83
84template <class Derived>
85Field SettingsCollection<Derived>::const_reference::getValue() const
86{
87 return member->get_field(*collection);
88}
89
90
91template <class Derived>
92Field SettingsCollection<Derived>::valueToCorrespondingType(size_t index, const Field & value)
93{
94 return members()[index].value_to_corresponding_type(value);
95}
96
97
98template <class Derived>
99Field SettingsCollection<Derived>::valueToCorrespondingType(const StringRef & name, const Field & value)
100{
101 return members().findStrict(name).value_to_corresponding_type(value);
102}
103
104
105template <class Derived>
106typename SettingsCollection<Derived>::iterator SettingsCollection<Derived>::find(const StringRef & name)
107{
108 const auto * member = members().find(name);
109 if (member)
110 return iterator(castToDerived(), member);
111 return end();
112}
113
114
115template <class Derived>
116typename SettingsCollection<Derived>::const_iterator SettingsCollection<Derived>::find(const StringRef & name) const
117{
118 const auto * member = members().find(name);
119 if (member)
120 return const_iterator(castToDerived(), member);
121 return end();
122}
123
124
125template <class Derived>
126typename SettingsCollection<Derived>::iterator SettingsCollection<Derived>::findStrict(const StringRef & name)
127{
128 return iterator(castToDerived(), &members().findStrict(name));
129}
130
131
132template <class Derived>
133typename SettingsCollection<Derived>::const_iterator SettingsCollection<Derived>::findStrict(const StringRef & name) const
134{
135 return const_iterator(castToDerived(), &members().findStrict(name));
136}
137
138
139template <class Derived>
140Field SettingsCollection<Derived>::get(size_t index) const
141{
142 return (*this)[index].getValue();
143}
144
145
146template <class Derived>
147Field SettingsCollection<Derived>::get(const StringRef & name) const
148{
149 return (*this)[name].getValue();
150}
151
152
153template <class Derived>
154bool SettingsCollection<Derived>::tryGet(const StringRef & name, Field & value) const
155{
156 auto it = find(name);
157 if (it == end())
158 return false;
159 value = it->getValue();
160 return true;
161}
162
163
164template <class Derived>
165bool SettingsCollection<Derived>::tryGet(const StringRef & name, String & value) const
166{
167 auto it = find(name);
168 if (it == end())
169 return false;
170 value = it->getValueAsString();
171 return true;
172}
173
174
175template <class Derived>
176bool SettingsCollection<Derived>::operator ==(const Derived & rhs) const
177{
178 const auto & the_members = members();
179 for (size_t i = 0; i != the_members.size(); ++i)
180 {
181 const auto & member = the_members[i];
182 bool left_changed = member.is_changed(castToDerived());
183 bool right_changed = member.is_changed(rhs);
184 if (left_changed || right_changed)
185 {
186 if (left_changed != right_changed)
187 return false;
188 if (member.get_field(castToDerived()) != member.get_field(rhs))
189 return false;
190 }
191 }
192 return true;
193}
194
195
196template <class Derived>
197SettingsChanges SettingsCollection<Derived>::changes() const
198{
199 SettingsChanges found_changes;
200 const auto & the_members = members();
201 for (size_t i = 0; i != the_members.size(); ++i)
202 {
203 const auto & member = the_members[i];
204 if (member.is_changed(castToDerived()))
205 found_changes.push_back({member.name.toString(), member.get_field(castToDerived())});
206 }
207 return found_changes;
208}
209
210
211template <class Derived>
212void SettingsCollection<Derived>::applyChange(const SettingChange & change)
213{
214 set(change.name, change.value);
215}
216
217
218template <class Derived>
219void SettingsCollection<Derived>::applyChanges(const SettingsChanges & changes)
220{
221 for (const SettingChange & change : changes)
222 applyChange(change);
223}
224
225
226template <class Derived>
227void SettingsCollection<Derived>::copyChangesFrom(const Derived & src)
228{
229 const auto & the_members = members();
230 for (size_t i = 0; i != the_members.size(); ++i)
231 {
232 const auto & member = the_members[i];
233 if (member.is_changed(src))
234 member.set_field(castToDerived(), member.get_field(src));
235 }
236}
237
238
239template <class Derived>
240void SettingsCollection<Derived>::copyChangesTo(Derived & dest) const
241{
242 dest.copyChangesFrom(castToDerived());
243}
244
245
246template <class Derived>
247void SettingsCollection<Derived>::serialize(WriteBuffer & buf, SettingsBinaryFormat format) const
248{
249 const auto & the_members = members();
250 for (size_t i = 0; i != the_members.size(); ++i)
251 {
252 const auto & member = the_members[i];
253 if (member.is_changed(castToDerived()))
254 {
255 details::SettingsCollectionUtils::serializeName(member.name, buf);
256 if (format >= SettingsBinaryFormat::STRINGS)
257 details::SettingsCollectionUtils::serializeFlag(member.is_important, buf);
258 member.serialize(castToDerived(), buf, format);
259 }
260 }
261 details::SettingsCollectionUtils::serializeName(StringRef{} /* empty string is a marker of the end of settings */, buf);
262}
263
264
265template <class Derived>
266void SettingsCollection<Derived>::deserialize(ReadBuffer & buf, SettingsBinaryFormat format)
267{
268 const auto & the_members = members();
269 while (true)
270 {
271 String name = details::SettingsCollectionUtils::deserializeName(buf);
272 if (name.empty() /* empty string is a marker of the end of settings */)
273 break;
274 auto * member = the_members.find(name);
275 bool is_important = (format >= SettingsBinaryFormat::STRINGS) ? details::SettingsCollectionUtils::deserializeFlag(buf) : true;
276 if (member)
277 {
278 member->deserialize(castToDerived(), buf, format);
279 }
280 else if (is_important)
281 {
282 details::SettingsCollectionUtils::throwNameNotFound(name);
283 }
284 else
285 {
286 details::SettingsCollectionUtils::warningNameNotFound(name);
287 details::SettingsCollectionUtils::skipValue(buf);
288 }
289 }
290}
291
292
293//-V:IMPLEMENT_SETTINGS_COLLECTION:501
294#define IMPLEMENT_SETTINGS_COLLECTION(DERIVED_CLASS_NAME, LIST_OF_SETTINGS_MACRO) \
295 template<> \
296 SettingsCollection<DERIVED_CLASS_NAME>::MemberInfos::MemberInfos() \
297 { \
298 using Derived = DERIVED_CLASS_NAME; \
299 struct Functions \
300 { \
301 LIST_OF_SETTINGS_MACRO(IMPLEMENT_SETTINGS_COLLECTION_DEFINE_FUNCTIONS_HELPER_) \
302 }; \
303 constexpr int IMPORTANT = 1; \
304 UNUSED(IMPORTANT); \
305 LIST_OF_SETTINGS_MACRO(IMPLEMENT_SETTINGS_COLLECTION_ADD_MEMBER_INFO_HELPER_) \
306 } \
307 /** \
308 * Instantiation should happen when all method definitions from SettingsCollectionImpl.h \
309 * are accessible, so we instantiate explicitly. \
310 */ \
311 template class SettingsCollection<DERIVED_CLASS_NAME>;
312
313
314#define IMPLEMENT_SETTINGS_COLLECTION_DEFINE_FUNCTIONS_HELPER_(TYPE, NAME, DEFAULT, DESCRIPTION, FLAGS) \
315 static String NAME##_getString(const Derived & collection) { return collection.NAME.toString(); } \
316 static Field NAME##_getField(const Derived & collection) { return collection.NAME.toField(); } \
317 static void NAME##_setString(Derived & collection, const String & value) { collection.NAME.set(value); } \
318 static void NAME##_setField(Derived & collection, const Field & value) { collection.NAME.set(value); } \
319 static void NAME##_serialize(const Derived & collection, WriteBuffer & buf, SettingsBinaryFormat format) { collection.NAME.serialize(buf, format); } \
320 static void NAME##_deserialize(Derived & collection, ReadBuffer & buf, SettingsBinaryFormat format) { collection.NAME.deserialize(buf, format); } \
321 static String NAME##_valueToString(const Field & value) { TYPE temp{DEFAULT}; temp.set(value); return temp.toString(); } \
322 static Field NAME##_valueToCorrespondingType(const Field & value) { TYPE temp{DEFAULT}; temp.set(value); return temp.toField(); } \
323
324
325#define IMPLEMENT_SETTINGS_COLLECTION_ADD_MEMBER_INFO_HELPER_(TYPE, NAME, DEFAULT, DESCRIPTION, FLAGS) \
326 add({StringRef(#NAME, strlen(#NAME)), StringRef(DESCRIPTION, strlen(DESCRIPTION)), \
327 FLAGS & IMPORTANT, \
328 [](const Derived & d) { return d.NAME.changed; }, \
329 &Functions::NAME##_getString, &Functions::NAME##_getField, \
330 &Functions::NAME##_setString, &Functions::NAME##_setField, \
331 &Functions::NAME##_serialize, &Functions::NAME##_deserialize, \
332 &Functions::NAME##_valueToString, &Functions::NAME##_valueToCorrespondingType});
333}
334