diff --git a/fairmq/PluginServices.h b/fairmq/PluginServices.h index 68d1ef33..1f0b33c4 100644 --- a/fairmq/PluginServices.h +++ b/fairmq/PluginServices.h @@ -178,7 +178,6 @@ class PluginServices auto UnsubscribeFromDeviceStateChange(const std::string& subscriber) -> void { fDevice.UnsubscribeFromStateChange(subscriber); } // Config API - struct PropertyNotFoundError : std::runtime_error { using std::runtime_error::runtime_error; }; auto PropertyExists(const std::string& key) const -> bool { return fConfig.Count(key) > 0; } @@ -200,20 +199,11 @@ class PluginServices void DeleteProperty(const std::string& key) { fConfig.DeleteProperty(key); } - /// @brief Read config property + /// @brief Read config property, throw if no property with this key exists /// @param key /// @return config property - /// - /// TODO Currently, if a non-existing key is requested and a default constructed object is returned. - /// This behaviour will be changed in the future to throw an exception in that case to provide a proper sentinel. template - auto GetProperty(const std::string& key) const -> T - { - if (PropertyExists(key)) { - return fConfig.GetProperty(key); - } - throw PropertyNotFoundError(fair::mq::tools::ToString("Config has no key: ", key)); - } + auto GetProperty(const std::string& key) const -> T { return fConfig.GetProperty(key); } template T GetProperty(const std::string& key, const T& ifNotFound) const @@ -221,18 +211,14 @@ class PluginServices return fConfig.GetProperty(key, ifNotFound); } - /// @brief Read config property as string + /// @brief Read config property as string, throw if no property with this key exists /// @param key /// @return config property converted to string /// - /// If a type is not supported, the user can provide support by overloading the ostream operator for this type - auto GetPropertyAsString(const std::string& key) const -> std::string - { - if (PropertyExists(key)) { - return fConfig.GetPropertyAsString(key); - } - throw PropertyNotFoundError(fair::mq::tools::ToString("Config has no key: ", key)); - } + /// Supports conversion to string for a fixed set of types, + /// for custom/unsupported types add them via `fair::mq::PropertyHelper::AddType("optional label")` + /// the provided type must then be convertible to string via operator<< + auto GetPropertyAsString(const std::string& key) const -> std::string { return fConfig.GetPropertyAsString(key); } auto GetPropertyAsString(const std::string& key, const std::string& ifNotFound) const -> std::string { diff --git a/fairmq/ProgOptions.cxx b/fairmq/ProgOptions.cxx index be8daabc..15ec4ce0 100644 --- a/fairmq/ProgOptions.cxx +++ b/fairmq/ProgOptions.cxx @@ -197,6 +197,17 @@ string ProgOptions::GetPropertyAsString(const string& key) const { lock_guard lock(fMtx); + if (fVarMap.count(key)) { + return ConvertVarValToString(fVarMap.at(key)); + } else { + throw PropertyNotFoundError(fair::mq::tools::ToString("Config has no key: ", key)); + } +} + +string ProgOptions::GetStringValue(const string& key) const +{ + lock_guard lock(fMtx); + if (fVarMap.count(key)) { return ConvertVarValToString(fVarMap.at(key)); } else { diff --git a/fairmq/ProgOptions.h b/fairmq/ProgOptions.h index 0a59b310..8987480f 100644 --- a/fairmq/ProgOptions.h +++ b/fairmq/ProgOptions.h @@ -24,12 +24,15 @@ #include #include #include +#include namespace fair { namespace mq { +struct PropertyNotFoundError : std::runtime_error { using std::runtime_error::runtime_error; }; + class ProgOptions { public: @@ -48,6 +51,9 @@ class ProgOptions std::unordered_map GetChannelInfo() const; std::vector GetPropertyKeys() const; + /// @brief Read config property, throw if no property with this key exists + /// @param key + /// @return config property template T GetProperty(const std::string& key) const { @@ -55,8 +61,7 @@ class ProgOptions if (fVarMap.count(key)) { return fVarMap[key].as(); } else { - LOG(warn) << "Config has no key: " << key << ". Returning default constructed object."; - return T(); + throw PropertyNotFoundError(fair::mq::tools::ToString("Config has no key: ", key)); } } @@ -70,6 +75,13 @@ class ProgOptions return ifNotFound; } + /// @brief Read config property as string, throw if no property with this key exists + /// @param key + /// @return config property converted to string + /// + /// Supports conversion to string for a fixed set of types, + /// for custom/unsupported types add them via `fair::mq::PropertyHelper::AddType("optional label")` + /// the provided type must then be convertible to string via operator<< std::string GetPropertyAsString(const std::string& key) const; std::string GetPropertyAsString(const std::string& key, const std::string& ifNotFound) const; @@ -150,11 +162,26 @@ class ProgOptions const boost::program_options::variables_map& GetVarMap() const { return fVarMap; } + /// @brief Read config property, return default-constructed object if key doesn't exist + /// @param key + /// @return config property template - T GetValue(const std::string& key) const /* TODO: deprecate this */ { return GetProperty(key); } + T GetValue(const std::string& key) const /* TODO: deprecate this */ + { + std::lock_guard lock(fMtx); + if (fVarMap.count(key)) { + return fVarMap[key].as(); + } else { + LOG(warn) << "Config has no key: " << key << ". Returning default constructed object."; + return T(); + } + } template int SetValue(const std::string& key, T val) /* TODO: deprecate this */ { SetProperty(key, val); return 0; } - std::string GetStringValue(const std::string& key) const /* TODO: deprecate this */ { return GetPropertyAsString(key); } + /// @brief Read config property as string, return default-constructed object if key doesn't exist + /// @param key + /// @return config property + std::string GetStringValue(const std::string& key) const; /* TODO: deprecate this */ private: void ParseDefaults(); diff --git a/test/plugin_services/_config.cxx b/test/plugin_services/_config.cxx index b8b0ff95..c1e47b19 100644 --- a/test/plugin_services/_config.cxx +++ b/test/plugin_services/_config.cxx @@ -148,7 +148,7 @@ TEST_F(PluginServices, Accessors) // property should no longer exist after deletion ASSERT_EQ(mServices.PropertyExists("custom3"), false); // accessing this property should throw an exception - ASSERT_THROW(mServices.GetProperty("custom3"), fair::mq::PluginServices::PropertyNotFoundError); + ASSERT_THROW(mServices.GetProperty("custom3"), fair::mq::PropertyNotFoundError); mServices.SetProperty("customType", MyClass("message")); // without adding custom type information, proper string value will not be returned