diff --git a/fairmq/options/FairMQProgOptions.cxx b/fairmq/options/FairMQProgOptions.cxx index 23965316..c810a664 100644 --- a/fairmq/options/FairMQProgOptions.cxx +++ b/fairmq/options/FairMQProgOptions.cxx @@ -14,25 +14,123 @@ #include "FairMQLogger.h" #include "FairMQProgOptions.h" -#include "FairProgOptionsHelper.h" #include "FairMQParser.h" #include "FairMQSuboptParser.h" #include "tools/Unique.h" +#include +#include #include // join/split +#include #include #include #include #include +#include using namespace std; using namespace fair::mq; +using boost::any_cast; namespace po = boost::program_options; +template +ostream& operator<<(ostream& os, const vector& v) +{ + for (unsigned int i = 0; i < v.size(); ++i) { + os << v[i]; + if (i != v.size() - 1) { + os << ", "; + } + } + return os; +} + +template +pair getString(const boost::any& v, const string& label) +{ + return { to_string(any_cast(v)), label }; +} + + +template +pair getStringPair(const boost::any& v, const string& label) +{ + stringstream ss; + ss << any_cast(v); + return { ss.str(), label }; +} + +unordered_map(*)(const boost::any&)> FairMQProgOptions::fValInfos = { + { type_index(typeid(string)), [](const boost::any& v) { return pair{ any_cast(v), "" }; } }, + { type_index(typeid(int)), [](const boost::any& v) { return getString(v, ""); } }, + { type_index(typeid(size_t)), [](const boost::any& v) { return getString(v, ""); } }, + { type_index(typeid(uint32_t)), [](const boost::any& v) { return getString(v, ""); } }, + { type_index(typeid(uint64_t)), [](const boost::any& v) { return getString(v, ""); } }, + { type_index(typeid(long)), [](const boost::any& v) { return getString(v, ""); } }, + { type_index(typeid(long long)), [](const boost::any& v) { return getString(v, ""); } }, + { type_index(typeid(unsigned)), [](const boost::any& v) { return getString(v, ""); } }, + { type_index(typeid(unsigned long)), [](const boost::any& v) { return getString(v, ""); } }, + { type_index(typeid(unsigned long long)), [](const boost::any& v) { return getString(v, ""); } }, + { type_index(typeid(float)), [](const boost::any& v) { return getString(v, ""); } }, + { type_index(typeid(double)), [](const boost::any& v) { return getString(v, ""); } }, + { type_index(typeid(long double)), [](const boost::any& v) { return getString(v, ""); } }, + { type_index(typeid(bool)), [](const boost::any& v) { stringstream ss; ss << boolalpha << any_cast(v); return pair{ ss.str(), "" }; } }, + { type_index(typeid(vector)), [](const boost::any& v) { stringstream ss; ss << boolalpha << any_cast>(v); return pair{ ss.str(), ">" }; } }, + { type_index(typeid(boost::filesystem::path)), [](const boost::any& v) { return getStringPair(v, ""); } }, + { type_index(typeid(vector)), [](const boost::any& v) { return getStringPair>(v, ">"); } }, + { type_index(typeid(vector)), [](const boost::any& v) { return getStringPair>(v, ">"); } }, + { type_index(typeid(vector)), [](const boost::any& v) { return getStringPair>(v, ">"); } }, + { type_index(typeid(vector)), [](const boost::any& v) { return getStringPair>(v, ">"); } }, + { type_index(typeid(vector)), [](const boost::any& v) { return getStringPair>(v, ">"); } }, + { type_index(typeid(vector)), [](const boost::any& v) { return getStringPair>(v, ">"); } }, + { type_index(typeid(vector)), [](const boost::any& v) { return getStringPair>(v, ">"); } }, + { type_index(typeid(vector)), [](const boost::any& v) { return getStringPair>(v, ">"); } }, + { type_index(typeid(vector)), [](const boost::any& v) { return getStringPair>(v, ">"); } }, + { type_index(typeid(vector)), [](const boost::any& v) { return getStringPair>(v, ">"); } }, + { type_index(typeid(vector)), [](const boost::any& v) { return getStringPair>(v, ">"); } }, + { type_index(typeid(vector)), [](const boost::any& v) { return getStringPair>(v, ">"); } }, + { type_index(typeid(vector)), [](const boost::any& v) { return getStringPair>(v, ">"); } }, + { type_index(typeid(vector)), [](const boost::any& v) { return getStringPair>(v, ">"); } }, +}; + +namespace fair +{ +namespace mq +{ + +ValInfo ConvertVarValToValInfo(const po::variable_value& v) +{ + string origin; + + if (v.defaulted()) { + origin = "[default]"; + } else if (v.empty()) { + origin = "[empty]"; + } else { + origin = "[provided]"; + } + + try { + pair info = FairMQProgOptions::fValInfos.at(v.value().type())(v.value()); + return {info.first, info.second, origin}; + } catch (out_of_range& oor) + { + return {string("[unidentified]"), string("[unidentified]"), origin}; + } +}; + +string ConvertVarValToString(const po::variable_value& v) +{ + return ConvertVarValToValInfo(v).value; +} + +} // namespace mq +} // namespace fair + FairMQProgOptions::FairMQProgOptions() : fVarMap() , fFairMQChannelMap() @@ -100,6 +198,8 @@ int FairMQProgOptions::ParseAll(const int argc, char const* const* argv, bool al { ParseCmdLine(argc, argv, allowUnregistered); + UpdateVarMap("blubblub", "yarhar"); + // if this option is provided, handle them and return stop value if (fVarMap.count("help")) { cout << fAllOptions << endl; @@ -382,7 +482,7 @@ int FairMQProgOptions::PrintOptions() // string, int, float, double, short, boost::filesystem::path // vector, vector, vector, vector, vector - map mapinfo; + map mapinfo; // get string length for formatting and convert varmap values into string int maxLenKey = 0; @@ -393,15 +493,14 @@ int FairMQProgOptions::PrintOptions() for (const auto& m : fVarMap) { maxLenKey = max(maxLenKey, static_cast(m.first.length())); - VarValInfo valinfo = ConvertVariableValue()((m.second)); + ValInfo valinfo = ConvertVarValToValInfo(m.second); mapinfo[m.first] = valinfo; maxLenValue = max(maxLenValue, static_cast(valinfo.value.length())); maxLenType = max(maxLenType, static_cast(valinfo.type.length())); - maxLenDefault = max(maxLenDefault, static_cast(valinfo.defaulted.length())); + maxLenDefault = max(maxLenDefault, static_cast(valinfo.origin.length())); } - // TODO : limit the value len field in a better way if (maxLenValue > 100) { maxLenValue = 100; } @@ -418,7 +517,7 @@ int FairMQProgOptions::PrintOptions() << setw(maxLenKey) << p.first << " = " << setw(maxLenValue) << p.second.value << " " << setw(maxLenType) << p.second.type - << setw(maxLenDefault) << p.second.defaulted + << setw(maxLenDefault) << p.second.origin << "\n"; } @@ -432,9 +531,9 @@ int FairMQProgOptions::PrintOptionsRaw() const vector>& options = fAllOptions.options(); for (const auto& o : options) { - VarValInfo value; + ValInfo value; if (fVarMap.count(o->canonical_display_name())) { - value = ConvertVariableValue()((fVarMap[o->canonical_display_name()])); + value = ConvertVarValToValInfo(fVarMap[o->canonical_display_name()]); } string description = o->description(); @@ -454,7 +553,7 @@ string FairMQProgOptions::GetStringValue(const string& key) string valueStr; try { if (fVarMap.count(key)) { - valueStr = ConvertVariableValue()(fVarMap.at(key)); + valueStr = ConvertVarValToString(fVarMap.at(key)); } } catch (exception& e) { LOG(error) << "Exception thrown for the key '" << key << "'"; diff --git a/fairmq/options/FairMQProgOptions.h b/fairmq/options/FairMQProgOptions.h index a0a1a868..aa977037 100644 --- a/fairmq/options/FairMQProgOptions.h +++ b/fairmq/options/FairMQProgOptions.h @@ -24,6 +24,8 @@ #include #include #include +#include +#include namespace fair { @@ -33,6 +35,13 @@ namespace mq struct PropertyChange : Event {}; struct PropertyChangeAsString : Event {}; +struct ValInfo +{ + std::string value; + std::string type; + std::string origin; +}; + } /* namespace mq */ } /* namespace fair */ @@ -45,6 +54,8 @@ class FairMQProgOptions 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 @@ -52,80 +63,36 @@ class FairMQProgOptions FairMQChannelMap GetFairMQMap() const; std::unordered_map GetChannelInfo() const; - - template - int SetValue(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)); - - 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); - } - std::vector GetPropertyKeys() const; - // get value corresponding to the key template - T GetValue(const std::string& key) const + T GetProperty(const std::string& key) const { std::lock_guard lock(fMtx); - T val = T(); - if (fVarMap.count(key)) { - val = fVarMap[key].as(); - } else { - LOG(warn) << "Config has no key: " << key << ". Returning default constructed object."; + return fVarMap[key].as(); } - return val; + 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) @@ -145,6 +112,64 @@ class FairMQProgOptions // 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 @@ -159,6 +184,8 @@ class FairMQProgOptions fFairMQChannelMap[channelName].push_back(channel); } + static std::unordered_map(*)(const boost::any&)> fValInfos; + private: struct ChannelKey { diff --git a/fairmq/options/FairProgOptions.h b/fairmq/options/FairProgOptions.h deleted file mode 100644 index b2e9ae5f..00000000 --- a/fairmq/options/FairProgOptions.h +++ /dev/null @@ -1 +0,0 @@ -#warning "This header file is deprecated. Use FairMQProgOptions class directly which now contains all FairProgOptions functionality. Note, that FairMQProgOptions is also available if you include FairMQDevice." diff --git a/fairmq/options/FairProgOptionsHelper.h b/fairmq/options/FairProgOptionsHelper.h deleted file mode 100644 index ab984fd5..00000000 --- a/fairmq/options/FairProgOptionsHelper.h +++ /dev/null @@ -1,187 +0,0 @@ -/******************************************************************************** - * 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" * - ********************************************************************************/ -/* - * File: FairProgOptionsHelper.h - * Author: winckler - * - * Created on March 11, 2015, 5:38 PM - */ - -#ifndef FAIRPROGOPTIONSHELPER_H -#define FAIRPROGOPTIONSHELPER_H - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace fair -{ -namespace mq -{ - -template -std::ostream& operator<<(std::ostream& os, const std::vector& v) -{ - for (const auto& i : v) { - os << i << " "; - } - return os; -} - -struct VarValInfo -{ - std::string value; - std::string type; - std::string defaulted; -}; - -template -std::string ConvertVariableValueToString(const boost::program_options::variable_value& varVal) -{ - std::ostringstream oss; - if (auto q = boost::any_cast(&varVal.value())) { - oss << *q; - } - return oss.str(); -} - -namespace options -{ - -// policy to convert boost variable value into string -struct ToString -{ - using returned_type = std::string; - - template - std::string Value(const boost::program_options::variable_value& varVal, const std::string&, const std::string&) - { - return ConvertVariableValueToString(varVal); - } - - returned_type DefaultValue(const std::string&) - { - return std::string("[unidentified]"); - } -}; - -// policy to convert variable value content into VarValInfo -struct ToVarValInfo -{ - using returned_type = VarValInfo; - - template - returned_type Value(const boost::program_options::variable_value& varVal, const std::string& type, const std::string& defaulted) - { - return VarValInfo{ConvertVariableValueToString(varVal), type, defaulted}; - } - - returned_type DefaultValue(const std::string& defaulted) - { - return VarValInfo{std::string("[unidentified]"), std::string("[unidentified]"), defaulted}; - } -}; - -} // namespace options - -// host class that take one of the two policy defined above -template -struct ConvertVariableValue : T -{ - auto operator()(const boost::program_options::variable_value& varVal) -> typename T::returned_type - { - std::string defaulted; - - if (varVal.defaulted()) { - defaulted = " [default]"; - } else { - defaulted = " [provided]"; - } - - if (typeid(std::string) == varVal.value().type()) - return T::template Value(varVal, std::string(""), defaulted); - - if (typeid(std::vector) == varVal.value().type()) - return T::template Value>(varVal, std::string(">"), defaulted); - - if (typeid(int) == varVal.value().type()) - return T::template Value(varVal, std::string(""), defaulted); - - if (typeid(std::vector) == varVal.value().type()) - return T::template Value>(varVal, std::string(">"), defaulted); - - if (typeid(float) == varVal.value().type()) - return T::template Value(varVal, std::string(""), defaulted); - - if (typeid(std::vector) == varVal.value().type()) - return T::template Value>(varVal, std::string(">"), defaulted); - - if (typeid(double) == varVal.value().type()) - return T::template Value(varVal, std::string(""), defaulted); - - if (typeid(std::vector) == varVal.value().type()) - return T::template Value>(varVal, std::string(">"), defaulted); - - if (typeid(short) == varVal.value().type()) - return T::template Value(varVal, std::string(""), defaulted); - - if (typeid(std::vector) == varVal.value().type()) - return T::template Value>(varVal, std::string(">"), defaulted); - - if (typeid(long) == varVal.value().type()) - return T::template Value(varVal, std::string(""), defaulted); - - if (typeid(std::vector) == varVal.value().type()) - return T::template Value>(varVal, std::string(">"), defaulted); - - if (typeid(std::size_t) == varVal.value().type()) - return T::template Value(varVal, std::string(""), defaulted); - - if (typeid(std::vector) == varVal.value().type()) - return T::template Value>(varVal, std::string(">"), defaulted); - - if (typeid(std::uint32_t) == varVal.value().type()) - return T::template Value(varVal, std::string(""), defaulted); - - if (typeid(std::vector) == varVal.value().type()) - return T::template Value>(varVal, std::string(">"), defaulted); - - if (typeid(std::uint64_t) == varVal.value().type()) - return T::template Value(varVal, std::string(""), defaulted); - - if (typeid(std::vector) == varVal.value().type()) - return T::template Value>(varVal, std::string(">"), defaulted); - - if (typeid(bool) == varVal.value().type()) - return T::template Value(varVal, std::string(""), defaulted); - - if (typeid(std::vector) == varVal.value().type()) - return T::template Value>(varVal, std::string(">"), defaulted); - - if (typeid(boost::filesystem::path) == varVal.value().type()) - return T::template Value(varVal, std::string(""), defaulted); - - if (typeid(std::vector) == varVal.value().type()) - return T::template Value>(varVal, std::string(">"), defaulted); - - // if we get here, the type is not supported return unknown info - return T::DefaultValue(defaulted); - } -}; - -} // namespace mq -} // namespace fair - -#endif /* FAIRPROGOPTIONSHELPER_H */