/******************************************************************************** * Copyright (C) 2014 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 namespace fair { namespace mq { struct PropertyChange : Event {}; struct PropertyChangeAsString : Event {}; } /* namespace mq */ } /* namespace fair */ class FairMQProgOptions { private: using FairMQChannelMap = std::unordered_map>; public: FairMQProgOptions(); virtual ~FairMQProgOptions(); 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; template int SetValue(const std::string& key, T val) { std::unique_lock lock(fConfigMutex); // update variable map UpdateVarMap::type>(key, val); // update FairMQChannel map if the key is a channel key if (std::is_same::value || std::is_same::value) { 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)); return 0; } template void Subscribe(const std::string& subscriber, std::function func) { std::unique_lock lock(fConfigMutex); 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::unique_lock lock(fConfigMutex); fEvents.Unsubscribe(subscriber); } void SubscribeAsString(const std::string& subscriber, std::function func) { std::unique_lock lock(fConfigMutex); fEvents.Subscribe(subscriber, func); } void UnsubscribeAsString(const std::string& subscriber) { std::unique_lock lock(fConfigMutex); fEvents.Unsubscribe(subscriber); } std::vector GetPropertyKeys() const; // get value corresponding to the key template T GetValue(const std::string& key) const { std::unique_lock lock(fConfigMutex); T val = T(); if (fVarMap.count(key)) { val = fVarMap[key].as(); } else { LOG(warn) << "Config has no key: " << key << ". Returning default constructed object."; } return val; } // Given a key, convert the variable value to string std::string GetStringValue(const std::string& key); int Count(const std::string& key) const; template T ConvertTo(const std::string& strValue) { if (std::is_arithmetic::value) { std::istringstream iss(strValue); T val; iss >> val; return val; } else { LOG(error) << "the provided string " << strValue << " cannot be converted to the requested type. The target type must be arithmetic type."; } } // add options_description int AddToCmdLineOptions(const boost::program_options::options_description optDesc, bool visible = true); boost::program_options::options_description& GetCmdLineOptions(); const boost::program_options::variables_map& GetVarMap() const { return fVarMap; } int PrintOptions(); int PrintOptionsRaw(); 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 fConfigMutex; 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); template void EmitUpdate(const std::string& key, T val) { // compile time check whether T is const char* or char*, and in that case a compile time error is thrown. static_assert(!std::is_same::value || !std::is_same::value, "In template member FairMQProgOptions::EmitUpdate(key,val) the types const char* or char* for the calback signatures are not supported."); fEvents.Emit(key, val); fEvents.Emit(key, GetStringValue(key)); } int UpdateChannelMap(const FairMQChannelMap& map); 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); 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); } }; #endif /* FAIRMQPROGOPTIONS_H */