/******************************************************************************** * Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * * * This software is distributed under the terms of the * * GNU Lesser General Public Licence (LGPL) version 3, * * copied verbatim in the file "LICENSE" * ********************************************************************************/ #ifndef FAIRMQPROGOPTIONS_H #define FAIRMQPROGOPTIONS_H #include #include "FairMQLogger.h" #include "FairMQChannel.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace fair { namespace mq { struct PropertyChange : Event {}; struct PropertyChangeAsString : Event {}; struct ValInfo { std::string value; std::string type; std::string origin; }; } /* namespace mq */ } /* namespace fair */ class FairMQProgOptions { private: using FairMQChannelMap = std::unordered_map>; public: FairMQProgOptions(); virtual ~FairMQProgOptions(); struct PropertyNotFoundException : std::runtime_error { using std::runtime_error::runtime_error; }; int ParseAll(const std::vector& cmdLineArgs, bool allowUnregistered); // parse command line. // default parser for the mq-configuration file (JSON) is called if command line key mq-config is called int ParseAll(const int argc, char const* const* argv, bool allowUnregistered = true); FairMQChannelMap GetFairMQMap() const; std::unordered_map GetChannelInfo() const; std::vector GetPropertyKeys() const; template T GetProperty(const std::string& key) const { std::lock_guard lock(fMtx); if (fVarMap.count(key)) { return fVarMap[key].as(); } throw PropertyNotFoundException(fair::mq::tools::ToString("Config has no key: ", key)); } template T GetProperty(const std::string& key, const T& ifNotFound) const { std::lock_guard lock(fMtx); if (fVarMap.count(key)) { return fVarMap[key].as(); } return ifNotFound; } template T GetValue(const std::string& key) const // TODO: deprecate this { return GetProperty(key); } std::map GetProperties(const std::string& q) { std::regex re(q); std::map result; for (const auto& m : fVarMap) { if (std::regex_search(m.first, re)) { result.emplace(m.first, m.second.value()); } } return result; } // Given a key, convert the variable value to string std::string GetStringValue(const std::string& key); template void SetProperty(const std::string& key, T val) { std::unique_lock lock(fMtx); // update variable map UpdateVarMap::type>(key, val); if (key == "channel-config") { ParseChannelsFromCmdLine(); } else if (fChannelKeyMap.count(key)) { UpdateChannelValue(fChannelKeyMap.at(key).channel, fChannelKeyMap.at(key).index, fChannelKeyMap.at(key).member, val); } lock.unlock(); //if (std::is_same::value || std::is_same::value)//if one wants to restrict type fEvents.Emit::type>(key, val); fEvents.Emit(key, GetStringValue(key)); } template int SetValue(const std::string& key, T val) // TODO: deprecate this { SetProperty(key, val); return 0; } template void Subscribe(const std::string& subscriber, std::function func) { std::lock_guard lock(fMtx); static_assert(!std::is_same::value || !std::is_same::value, "In template member FairMQProgOptions::Subscribe(key,Lambda) the types const char* or char* for the calback signatures are not supported."); fEvents.Subscribe(subscriber, func); } template void Unsubscribe(const std::string& subscriber) { std::lock_guard lock(fMtx); fEvents.Unsubscribe(subscriber); } void SubscribeAsString(const std::string& subscriber, std::function func) { std::lock_guard lock(fMtx); fEvents.Subscribe(subscriber, func); } void UnsubscribeAsString(const std::string& subscriber) { std::lock_guard lock(fMtx); fEvents.Unsubscribe(subscriber); } int Count(const std::string& key) const; // add options_description int AddToCmdLineOptions(const boost::program_options::options_description optDesc, bool visible = true); boost::program_options::options_description& GetCmdLineOptions(); int PrintOptions(); int PrintOptionsRaw(); void AddChannel(const std::string& channelName, const FairMQChannel& channel) { fFairMQChannelMap[channelName].push_back(channel); } static std::unordered_map(*)(const boost::any&)> fValInfos; private: struct ChannelKey { std::string channel; int index; std::string member; }; boost::program_options::variables_map fVarMap; ///< options container FairMQChannelMap fFairMQChannelMap; boost::program_options::options_description fAllOptions; ///< all options descriptions boost::program_options::options_description fGeneralOptions; ///< general options descriptions boost::program_options::options_description fMQOptions; ///< MQ options descriptions boost::program_options::options_description fParserOptions; ///< MQ Parser options descriptions mutable std::mutex fMtx; std::unordered_map fChannelInfo; ///< channel name - number of subchannels std::unordered_map fChannelKeyMap;// key=full path - val=key info std::vector fUnregisteredOptions; ///< container with unregistered options fair::mq::EventManager fEvents; void ParseCmdLine(const int argc, char const* const* argv, bool allowUnregistered = true); void ParseDefaults(); // read FairMQChannelMap and insert/update corresponding values in variable map // create key for variable map as follow : channelName.index.memberName void UpdateMQValues(); int Store(const FairMQChannelMap& channels); int UpdateChannelMap(const FairMQChannelMap& map); template int UpdateChannelValue(const std::string&, int, const std::string&, T) { LOG(error) << "update of FairMQChannel map failed, because value type not supported"; return 1; } int UpdateChannelValue(const std::string& channelName, int index, const std::string& member, const std::string& val); int UpdateChannelValue(const std::string& channelName, int index, const std::string& member, int val); int UpdateChannelValue(const std::string& channelName, int index, const std::string& member, bool val); void UpdateChannelInfo(); // helper to modify the value of variable map after calling boost::program_options::store template void UpdateVarMap(const std::string& key, const T& val) { std::map& vm = fVarMap; vm[key].value() = boost::any(val); } void ParseChannelsFromCmdLine(); }; #endif /* FAIRMQPROGOPTIONS_H */