Source · fairmq/
ProgOptions.hpublic header
Defines class fair::mq::ProgOptions, struct fair::mq::PropertyNotFoundError.
Described in Configuration and properties, Threads in a device, 1-1: sampler and sink, qc: quality control on demand, Control a device from code, Command-line options, Logging.
1/********************************************************************************2 * Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *3 * *4 * This software is distributed under the terms of the *5 * GNU Lesser General Public Licence (LGPL) version 3, *6 * copied verbatim in the file "LICENSE" *7 ********************************************************************************/8 9#ifndef FAIR_MQ_PROGOPTIONS_H10#define FAIR_MQ_PROGOPTIONS_H11 12#include <boost/program_options.hpp>13#include <fairlogger/Logger.h>14#include <fairmq/Channel.h>15#include <fairmq/EventManager.h>16#include <fairmq/ProgOptionsFwd.h>17#include <fairmq/Properties.h>18#include <fairmq/tools/Strings.h>19#include <functional>20#include <map>21#include <mutex>22#include <stdexcept>23#include <string>24#include <unordered_map>25#include <vector>26 27namespace fair::mq28{29 30struct PropertyNotFoundError : std::runtime_error { using std::runtime_error::runtime_error; };31 32class ProgOptions33{34 public:35 ProgOptions();36 ProgOptions(const ProgOptions&) = delete;37 ProgOptions(ProgOptions&&) = delete;38 ProgOptions& operator=(const ProgOptions&) = delete;39 ProgOptions& operator=(ProgOptions&&) = delete;40 ~ProgOptions() = default;41 42 void ParseAll(const std::vector<std::string>& cmdArgs, bool allowUnregistered);43 void ParseAll(int argc, char const* const* argv, bool allowUnregistered = true);44 void Notify();45 46 void AddToCmdLineOptions(boost::program_options::options_description optDesc, bool visible = true);47 boost::program_options::options_description& GetCmdLineOptions();48 49 /// @brief Checks a property with the given key exist in the configuration50 /// @param key51 /// @return 1 if it exists, 0 otherwise52 int Count(const std::string& key) const;53 54 /// @brief Retrieve current channel information55 /// @return a map of <channel name, number of subchannels>56 std::unordered_map<std::string, int> GetChannelInfo() const;57 /// @brief Discover the list of property keys58 /// @return list of property keys59 std::vector<std::string> GetPropertyKeys() const;60 61 /// @brief Read config property, throw if no property with this key exists62 /// @param key63 /// @return config property64 template<typename T>65 T GetProperty(const std::string& key) const66 {67 std::lock_guard<std::mutex> lock(fMtx);68 if (fVarMap.count(key)) {69 return fVarMap[key].as<T>();70 } else {71 throw PropertyNotFoundError(fair::mq::tools::ToString("Config has no key: ", key));72 }73 }74 75 /// @brief Read config property, return provided value if no property with this key exists76 /// @param key77 /// @param ifNotFound value to return if key is not found78 /// @return config property79 template<typename T>80 T GetProperty(const std::string& key, const T& ifNotFound) const81 {82 std::lock_guard<std::mutex> lock(fMtx);83 if (fVarMap.count(key)) {84 return fVarMap[key].as<T>();85 }86 return ifNotFound;87 }88 89 /// @brief Read config property as string, throw if no property with this key exists90 /// @param key91 /// @return config property converted to string92 ///93 /// Supports conversion to string for a fixed set of types,94 /// for custom/unsupported types add them via `fair::mq::PropertyHelper::AddType<MyType>("optional label")`95 /// the provided type must then be convertible to string via operator<<96 std::string GetPropertyAsString(const std::string& key) const;97 /// @brief Read config property, return provided value if no property with this key exists98 /// @param key99 /// @param ifNotFound value to return if key is not found100 /// @return config property converted to string101 ///102 /// Supports conversion to string for a fixed set of types,103 /// for custom/unsupported types add them via `fair::mq::PropertyHelper::AddType<MyType>("optional label")`104 /// the provided type must then be convertible to string via operator<<105 std::string GetPropertyAsString(const std::string& key, const std::string& ifNotFound) const;106 107 /// @brief Read several config properties whose keys match the provided regular expression108 /// @param q regex string to match for109 /// @return container with properties (fair::mq::Properties as an alias for std::map<std::string, Property>, where property is boost::any)110 fair::mq::Properties GetProperties(const std::string& q) const;111 /// @brief Read several config properties whose keys start with the provided string112 /// @param q string to match for113 /// @return container with properties (fair::mq::Properties as an alias for std::map<std::string, Property>, where property is boost::any)114 ///115 /// Typically more performant than GetProperties with regex116 fair::mq::Properties GetPropertiesStartingWith(const std::string& q) const;117 /// @brief Read several config properties as string whose keys match the provided regular expression118 /// @param q regex string to match for119 /// @return container with properties (fair::mq::Properties as an alias for std::map<std::string, Property>, where property is boost::any)120 std::map<std::string, std::string> GetPropertiesAsString(const std::string& q) const;121 /// @brief Read several config properties as string whose keys start with the provided string122 /// @param q string to match for123 /// @return container with properties (fair::mq::Properties as an alias for std::map<std::string, Property>, where property is boost::any)124 ///125 /// Typically more performant than GetPropertiesAsString with regex126 std::map<std::string, std::string> GetPropertiesAsStringStartingWith(const std::string& q) const;127 128 /// @brief Set config property129 /// @param key130 /// @param val131 template<typename T>132 void SetProperty(const std::string& key, T val);133 134 /// @brief Updates an existing config property (or fails if it doesn't exist)135 /// @param key136 /// @param val137 template<typename T>138 bool UpdateProperty(const std::string& key, T val)139 {140 std::unique_lock<std::mutex> lock(fMtx);141 142 if (fVarMap.count(key)) {143 SetVarMapValue<typename std::decay<T>::type>(key, val);144 145 lock.unlock();146 147 fEvents.Emit<fair::mq::PropertyChange, typename std::decay<T>::type>(key, val);148 fEvents.Emit<fair::mq::PropertyChangeAsString, std::string>(key, GetPropertyAsString(key));149 return true;150 } else {151 LOG(debug) << "UpdateProperty failed, no property found with key '" << key << "'";152 return false;153 }154 }155 156 /// @brief Set multiple config properties157 /// @param props fair::mq::Properties as an alias for std::map<std::string, Property>, where property is boost::any158 void SetProperties(const fair::mq::Properties& input);159 /// @brief Updates multiple existing config properties (or fails of any of then do not exist, leaving property store unchanged)160 /// @param props (fair::mq::Properties as an alias for std::map<std::string, Property>, where property is boost::any)161 bool UpdateProperties(const fair::mq::Properties& input);162 /// @brief Deletes a property with the given key from the config store163 /// @param key164 void DeleteProperty(const std::string& key);165 166 /// @brief Takes the provided channel and creates properties based on it167 /// @param name channel name168 /// @param channel FairMQChannel reference169 void AddChannel(const std::string& name, const Channel& channel);170 171 /// @brief Subscribe to property updates of type T172 /// @param subscriber173 /// @param callback function174 ///175 /// Subscribe to property changes with a callback to monitor property changes in an event based fashion.176 template<typename T>177 void Subscribe(const std::string& subscriber, std::function<void(typename fair::mq::PropertyChange::KeyType, T)> func) const178 {179 std::lock_guard<std::mutex> lock(fMtx);180 static_assert(!std::is_same<T,const char*>::value || !std::is_same<T, char*>::value,181 "In template member ProgOptions::Subscribe<T>(key,Lambda) the types const char* or char* for the calback signatures are not supported.");182 fEvents.Subscribe<fair::mq::PropertyChange, T>(subscriber, func);183 }184 185 /// @brief Unsubscribe from property updates of type T186 /// @param subscriber187 template<typename T>188 void Unsubscribe(const std::string& subscriber) const189 {190 std::lock_guard<std::mutex> lock(fMtx);191 fEvents.Unsubscribe<fair::mq::PropertyChange, T>(subscriber);192 }193 194 /// @brief Subscribe to property updates, with values converted to string195 /// @param subscriber196 /// @param callback function197 ///198 /// Subscribe to property changes with a callback to monitor property changes in an event based fashion. Will convert the property to string.199 void SubscribeAsString(const std::string& subscriber, std::function<void(typename fair::mq::PropertyChange::KeyType, std::string)> func) const200 {201 std::lock_guard<std::mutex> lock(fMtx);202 fEvents.Subscribe<fair::mq::PropertyChangeAsString, std::string>(subscriber, func);203 }204 205 /// @brief Unsubscribe from property updates that convert to string206 /// @param subscriber207 void UnsubscribeAsString(const std::string& subscriber) const208 {209 std::lock_guard<std::mutex> lock(fMtx);210 fEvents.Unsubscribe<fair::mq::PropertyChangeAsString, std::string>(subscriber);211 }212 213 /// @brief prints full options description214 void PrintHelp() const;215 /// @brief prints properties stored in the property container216 void PrintOptions() const;217 /// @brief prints full options description in a compact machine-readable format218 void PrintOptionsRaw() const;219 220 /// @brief returns the property container221 const boost::program_options::variables_map& GetVarMap() const222 {223 std::lock_guard<std::mutex> lock(fMtx);224 return fVarMap;225 }226 227 /// @brief Read config property, return default-constructed object if key doesn't exist228 /// @param key229 /// @return config property230 template<typename T>231 T GetValue(const std::string& key) const /* TODO: deprecate this */232 {233 std::lock_guard<std::mutex> lock(fMtx);234 if (fVarMap.count(key)) {235 return fVarMap[key].as<T>();236 } else {237 LOG(warn) << "Config has no key: " << key << ". Returning default constructed object.";238 return T();239 }240 }241 template<typename T>242 int SetValue(const std::string& key, T val) /* TODO: deprecate this */ { SetProperty(key, val); return 0; }243 /// @brief Read config property as string, return default-constructed object if key doesn't exist244 /// @param key245 /// @return config property246 std::string GetStringValue(const std::string& key) const; /* TODO: deprecate this */247 248 private:249 void ParseDefaults();250 std::unordered_map<std::string, int> GetChannelInfoImpl() const;251 252 template<typename T>253 void SetVarMapValue(const std::string& key, const T& val)254 {255 std::map<std::string, boost::program_options::variable_value>& vm = fVarMap;256 vm[key].value() = boost::any(val);257 }258 259 boost::program_options::variables_map fVarMap; ///< options container260 boost::program_options::options_description fAllOptions; ///< all options descriptions261 std::vector<std::string> fUnregisteredOptions; ///< container with unregistered options262 263 mutable fair::mq::EventManager fEvents;264 mutable std::mutex fMtx;265};266 267} // namespace fair::mq268template <typename T>269void fair::mq::ProgOptions::SetProperty(const std::string& key, T val)270{271 std::unique_lock<std::mutex> lock(fMtx);272 273 SetVarMapValue<typename std::decay<T>::type>(key, val);274 275 lock.unlock();276 277 fEvents.Emit<fair::mq::PropertyChange, typename std::decay<T>::type>(key, val);278 fEvents.Emit<fair::mq::PropertyChangeAsString, std::string>(key, GetPropertyAsString(key));279}280 281extern template void fair::mq::ProgOptions::SetProperty<int>(const std::string& key, int val);282extern template void fair::mq::ProgOptions::SetProperty<std::string>(const std::string& key, std::string val);283 284#endif /* FAIR_MQ_PROGOPTIONS_H */