#pragma once /** * This file implements some functions that are dependent on Field type. * Unlike SettingsCollection.h, we only have to include it once for each * instantiation of SettingsCollection<>. */ #include namespace DB { namespace details { struct SettingsCollectionUtils { static void serializeName(const StringRef & name, WriteBuffer & buf); static String deserializeName(ReadBuffer & buf); static void serializeFlag(bool flag, WriteBuffer & buf); static bool deserializeFlag(ReadBuffer & buf); static void skipValue(ReadBuffer & buf); static void warningNameNotFound(const StringRef & name); [[noreturn]] static void throwNameNotFound(const StringRef & name); }; } template size_t SettingsCollection::MemberInfos::findIndex(const StringRef & name) const { auto it = by_name_map.find(name); if (it == by_name_map.end()) return static_cast(-1); // npos return it->second; } template size_t SettingsCollection::MemberInfos::findIndexStrict(const StringRef & name) const { auto it = by_name_map.find(name); if (it == by_name_map.end()) details::SettingsCollectionUtils::throwNameNotFound(name); return it->second; } template const typename SettingsCollection::MemberInfo * SettingsCollection::MemberInfos::find(const StringRef & name) const { auto it = by_name_map.find(name); if (it == by_name_map.end()) return nullptr; else return &infos[it->second]; } template const typename SettingsCollection::MemberInfo & SettingsCollection::MemberInfos::findStrict(const StringRef & name) const { return infos[findIndexStrict(name)]; } template void SettingsCollection::MemberInfos::add(MemberInfo && member) { size_t index = infos.size(); infos.emplace_back(member); by_name_map.emplace(infos.back().name, index); } template const typename SettingsCollection::MemberInfos & SettingsCollection::members() { static const MemberInfos the_instance; return the_instance; } template Field SettingsCollection::const_reference::getValue() const { return member->get_field(*collection); } template Field SettingsCollection::valueToCorrespondingType(size_t index, const Field & value) { return members()[index].value_to_corresponding_type(value); } template Field SettingsCollection::valueToCorrespondingType(const StringRef & name, const Field & value) { return members().findStrict(name).value_to_corresponding_type(value); } template typename SettingsCollection::iterator SettingsCollection::find(const StringRef & name) { const auto * member = members().find(name); if (member) return iterator(castToDerived(), member); return end(); } template typename SettingsCollection::const_iterator SettingsCollection::find(const StringRef & name) const { const auto * member = members().find(name); if (member) return const_iterator(castToDerived(), member); return end(); } template typename SettingsCollection::iterator SettingsCollection::findStrict(const StringRef & name) { return iterator(castToDerived(), &members().findStrict(name)); } template typename SettingsCollection::const_iterator SettingsCollection::findStrict(const StringRef & name) const { return const_iterator(castToDerived(), &members().findStrict(name)); } template Field SettingsCollection::get(size_t index) const { return (*this)[index].getValue(); } template Field SettingsCollection::get(const StringRef & name) const { return (*this)[name].getValue(); } template bool SettingsCollection::tryGet(const StringRef & name, Field & value) const { auto it = find(name); if (it == end()) return false; value = it->getValue(); return true; } template bool SettingsCollection::tryGet(const StringRef & name, String & value) const { auto it = find(name); if (it == end()) return false; value = it->getValueAsString(); return true; } template bool SettingsCollection::operator ==(const Derived & rhs) const { const auto & the_members = members(); for (size_t i = 0; i != the_members.size(); ++i) { const auto & member = the_members[i]; bool left_changed = member.is_changed(castToDerived()); bool right_changed = member.is_changed(rhs); if (left_changed || right_changed) { if (left_changed != right_changed) return false; if (member.get_field(castToDerived()) != member.get_field(rhs)) return false; } } return true; } template SettingsChanges SettingsCollection::changes() const { SettingsChanges found_changes; const auto & the_members = members(); for (size_t i = 0; i != the_members.size(); ++i) { const auto & member = the_members[i]; if (member.is_changed(castToDerived())) found_changes.push_back({member.name.toString(), member.get_field(castToDerived())}); } return found_changes; } template void SettingsCollection::applyChange(const SettingChange & change) { set(change.name, change.value); } template void SettingsCollection::applyChanges(const SettingsChanges & changes) { for (const SettingChange & change : changes) applyChange(change); } template void SettingsCollection::copyChangesFrom(const Derived & src) { const auto & the_members = members(); for (size_t i = 0; i != the_members.size(); ++i) { const auto & member = the_members[i]; if (member.is_changed(src)) member.set_field(castToDerived(), member.get_field(src)); } } template void SettingsCollection::copyChangesTo(Derived & dest) const { dest.copyChangesFrom(castToDerived()); } template void SettingsCollection::serialize(WriteBuffer & buf, SettingsBinaryFormat format) const { const auto & the_members = members(); for (size_t i = 0; i != the_members.size(); ++i) { const auto & member = the_members[i]; if (member.is_changed(castToDerived())) { details::SettingsCollectionUtils::serializeName(member.name, buf); if (format >= SettingsBinaryFormat::STRINGS) details::SettingsCollectionUtils::serializeFlag(member.is_ignorable, buf); member.serialize(castToDerived(), buf, format); } } details::SettingsCollectionUtils::serializeName(StringRef{} /* empty string is a marker of the end of settings */, buf); } template void SettingsCollection::deserialize(ReadBuffer & buf, SettingsBinaryFormat format) { const auto & the_members = members(); while (true) { String name = details::SettingsCollectionUtils::deserializeName(buf); if (name.empty() /* empty string is a marker of the end of settings */) break; auto * member = the_members.find(name); bool is_ignorable = (format >= SettingsBinaryFormat::STRINGS) ? details::SettingsCollectionUtils::deserializeFlag(buf) : false; if (member) { member->deserialize(castToDerived(), buf, format); } else if (is_ignorable) { details::SettingsCollectionUtils::warningNameNotFound(name); details::SettingsCollectionUtils::skipValue(buf); } else details::SettingsCollectionUtils::throwNameNotFound(name); } } //-V:IMPLEMENT_SETTINGS_COLLECTION:501 #define IMPLEMENT_SETTINGS_COLLECTION(DERIVED_CLASS_NAME, LIST_OF_SETTINGS_MACRO) \ template<> \ SettingsCollection::MemberInfos::MemberInfos() \ { \ using Derived = DERIVED_CLASS_NAME; \ struct Functions \ { \ LIST_OF_SETTINGS_MACRO(IMPLEMENT_SETTINGS_COLLECTION_DEFINE_FUNCTIONS_HELPER_) \ }; \ constexpr int IGNORABLE = 1; \ UNUSED(IGNORABLE); \ LIST_OF_SETTINGS_MACRO(IMPLEMENT_SETTINGS_COLLECTION_ADD_MEMBER_INFO_HELPER_) \ } \ /** \ * Instantiation should happen when all method definitions from SettingsCollectionImpl.h \ * are accessible, so we instantiate explicitly. \ */ \ template class SettingsCollection; #define IMPLEMENT_SETTINGS_COLLECTION_DEFINE_FUNCTIONS_HELPER_(TYPE, NAME, DEFAULT, DESCRIPTION, FLAGS) \ static String NAME##_getString(const Derived & collection) { return collection.NAME.toString(); } \ static Field NAME##_getField(const Derived & collection) { return collection.NAME.toField(); } \ static void NAME##_setString(Derived & collection, const String & value) { collection.NAME.set(value); } \ static void NAME##_setField(Derived & collection, const Field & value) { collection.NAME.set(value); } \ static void NAME##_serialize(const Derived & collection, WriteBuffer & buf, SettingsBinaryFormat format) { collection.NAME.serialize(buf, format); } \ static void NAME##_deserialize(Derived & collection, ReadBuffer & buf, SettingsBinaryFormat format) { collection.NAME.deserialize(buf, format); } \ static String NAME##_valueToString(const Field & value) { TYPE temp{DEFAULT}; temp.set(value); return temp.toString(); } \ static Field NAME##_valueToCorrespondingType(const Field & value) { TYPE temp{DEFAULT}; temp.set(value); return temp.toField(); } \ #define IMPLEMENT_SETTINGS_COLLECTION_ADD_MEMBER_INFO_HELPER_(TYPE, NAME, DEFAULT, DESCRIPTION, FLAGS) \ add({StringRef(#NAME, strlen(#NAME)), StringRef(DESCRIPTION, strlen(DESCRIPTION)), \ FLAGS & IGNORABLE, \ [](const Derived & d) { return d.NAME.changed; }, \ &Functions::NAME##_getString, &Functions::NAME##_getField, \ &Functions::NAME##_setString, &Functions::NAME##_setField, \ &Functions::NAME##_serialize, &Functions::NAME##_deserialize, \ &Functions::NAME##_valueToString, &Functions::NAME##_valueToCorrespondingType}); }