diff --git a/core/include/gnuradio-4.0/Settings.hpp b/core/include/gnuradio-4.0/Settings.hpp index cdf57b4cd..95c869b4a 100644 --- a/core/include/gnuradio-4.0/Settings.hpp +++ b/core/include/gnuradio-4.0/Settings.hpp @@ -281,46 +281,44 @@ class BasicSettings : public SettingsBase { } if constexpr (refl::is_reflectable()) { - meta::tuple_for_each( - [this](auto &&default_tag) { - auto iterate_over_member = [&](auto member) { - using RawType = std::remove_cvref_t; - using Type = unwrap_if_wrapped_t; - if constexpr (traits::port::is_not_any_port_or_collection && !std::is_const_v && is_writable(member) && settings::isSupportedType()) { - if (default_tag == get_display_name(member)) { - _auto_forward.emplace(get_display_name(member)); - } - _auto_update.emplace(get_display_name(member)); - } - }; - if constexpr (detail::HasBaseType) { - refl::util::for_each(refl::reflect::base_t>().members, iterate_over_member); - } - refl::util::for_each(refl::reflect().members, iterate_over_member); - }, - gr::tag::DEFAULT_TAGS); + // register block-global description + constexpr bool hasMetaInfo = requires(TBlock t) { + { + unwrap_if_wrapped_t {} + } -> std::same_as; + }; + + if constexpr (hasMetaInfo && requires(TBlock t) { t.description; }) { + static_assert(std::is_same_v>, std::string_view>); + _block->meta_information.value["description"] = std::string(_block->description); + } // handle meta-information for UI and other non-processing-related purposes - auto iterate_over_member = [&](Member member) { - using RawType = std::remove_cvref_t; - // disable clang format because v16 cannot handle in-line requires clauses with return types nicely yet - // clang-format off - if constexpr (requires(TBlock t) { t.meta_information; }) { - static_assert(std::is_same_vmeta_information)>, property_map>); - if constexpr (requires(TBlock t) { t.description; }) { - static_assert(std::is_same_v>, std::string_view>); - _block->meta_information.value["description"] = std::string(_block->description); - } + auto iterate_over_member = [this](Member member) { + using RawType = std::remove_cvref_t; + using Type = unwrap_if_wrapped_t; + const auto memberName = std::string(get_display_name(member)); + + if constexpr (hasMetaInfo && AnnotatedType) { + _block->meta_information.value[memberName + "::description"] = std::string(RawType::description()); + _block->meta_information.value[memberName + "::documentation"] = std::string(RawType::documentation()); + _block->meta_information.value[memberName + "::unit"] = std::string(RawType::unit()); + _block->meta_information.value[memberName + "::visible"] = RawType::visible(); + } - if constexpr (AnnotatedType) { - _block->meta_information.value[fmt::format("{}::description", get_display_name(member))] = std::string(RawType::description()); - _block->meta_information.value[fmt::format("{}::documentation", get_display_name(member))] = std::string(RawType::documentation()); - _block->meta_information.value[fmt::format("{}::unit", get_display_name(member))] = std::string(RawType::unit()); - _block->meta_information.value[fmt::format("{}::visible", get_display_name(member))] = RawType::visible(); - } + // detect whether field has one of the DEFAULT_TAGS signature + if constexpr (traits::port::is_not_any_port_or_collection && !std::is_const_v && is_writable(member) && settings::isSupportedType()) { + meta::tuple_for_each( + [&memberName, this](auto &&default_tag) { + if (default_tag == memberName) { + _auto_forward.emplace(memberName); + } + _auto_update.emplace(memberName); + }, + gr::tag::DEFAULT_TAGS); } - // clang-format on }; + if constexpr (detail::HasBaseType) { refl::util::for_each(refl::reflect::base_t>().members, iterate_over_member); } @@ -377,7 +375,8 @@ class BasicSettings : public SettingsBase { auto iterate_over_member = [&, this](auto member) { using Type = unwrap_if_wrapped_t>; if constexpr (traits::port::is_not_any_port_or_collection && !std::is_const_v && is_writable(member) && settings::isSupportedType()) { - if (std::string(get_display_name(member)) == key && std::holds_alternative(value)) { + const auto fieldName = std::string_view(get_display_name(member)); + if (fieldName == key && std::holds_alternative(value)) { if (_auto_update.contains(key)) { _auto_update.erase(key); } @@ -385,15 +384,13 @@ class BasicSettings : public SettingsBase { SettingsBase::_changed.store(true); is_set = true; } - if (std::string(get_display_name(member)) == key && !std::holds_alternative(value)) { - const std::size_t required_index = meta::to_typelist::index_of(); - std::visit( - [&key, &value, &required_index](auto &&arg) { - using ActualType = std::decay_t; - throw std::invalid_argument(fmt::format("value for key {} has a wrong type ({}: {}) vs. expected ({}: {})", // - key, value.index(), gr::meta::type_name(), required_index, gr::meta::type_name())); - }, - value); + if (fieldName == key && !std::holds_alternative(value)) { + throw std::invalid_argument([&key, &value] { // lazy evaluation + const std::size_t actual_index = value.index(); + const std::size_t required_index = meta::to_typelist::index_of(); // This too, as per your implementation. + return fmt::format("value for key '{}' has a wrong type. Index of actual type: {} ({}), Index of expected type: {} ({})", key, actual_index, "", + required_index, gr::meta::type_name()); + }()); } } };