diff --git a/fairmq/CMakeLists.txt b/fairmq/CMakeLists.txt index 0b80e6af..04b7d8ed 100644 --- a/fairmq/CMakeLists.txt +++ b/fairmq/CMakeLists.txt @@ -155,7 +155,7 @@ install(FILES ${FAIRMQHEADERS} DESTINATION include) set(DEPENDENCIES ${DEPENDENCIES} - boost_thread boost_timer boost_system boost_program_options boost_random boost_chrono boost_exception + boost_thread boost_timer boost_system boost_filesystem boost_program_options boost_random boost_chrono boost_exception ) set(LIBRARY_NAME FairMQ) diff --git a/fairmq/devices/GenericSampler.h b/fairmq/devices/GenericSampler.h index 89eeda76..7b04ab47 100644 --- a/fairmq/devices/GenericSampler.h +++ b/fairmq/devices/GenericSampler.h @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -25,6 +26,7 @@ #include "FairMQDevice.h" #include "FairMQLogger.h" +#include "FairMQTools.h" /* GENERIC SAMPLER (data source) MQ-DEVICE */ /********************************************************************* @@ -33,31 +35,55 @@ * Function to define in (parent) policy classes : * * -------- INPUT POLICY (SAMPLER POLICY) -------- - * SamplerPolicy::InitSampler() - * int64_t SamplerPolicy::GetNumberOfEvent() - * CONTAINER_TYPE SamplerPolicy::GetDataBranch(int64_t eventNr) - * SamplerPolicy::SetFileProperties(Args&... args) + * source_type::InitSampler() // must be there to compile + * int64_t source_type::GetNumberOfEvent() // must be there to compile + * source_type::SetIndex(int64_t eventIdx) // must be there to compile + * CONTAINER_TYPE source_type::GetOutData() // must be there to compile + * source_type::SetFileProperties(Args&... args) // must be there to compile + * source_type::ExecuteTasks() // must be there to compile + * + * void BindSendPart(std::function callback) // enabled if exists + * void BindGetSocketNumber(std::function callback) // enabled if exists + * void BindGetCurrentIndex(std::function callback) // enabled if exists * * -------- OUTPUT POLICY -------- - * OutputPolicy::SerializeMsg(CONTAINER_TYPE) - * OutputPolicy::SetMessage(FairMQMessage* msg) + * serialization_type::SerializeMsg(CONTAINER_TYPE) // must be there to compile + * serialization_type::SetMessage(FairMQMessage* msg) // must be there to compile * **********************************************************************/ -template -class GenericSampler : public FairMQDevice, public SamplerPolicy, public OutputPolicy +//template +//class base_GenericSampler : public FairMQDevice, public source_type, public serialization_type +template +class base_GenericSampler : public FairMQDevice, public T, public U { + typedef T source_type; + typedef U serialization_type; + typedef K key_type; + typedef L task_type; + typedef base_GenericSampler self_type; + public: enum { - InputFile = FairMQDevice::Last, - Branch, - ParFile, - EventRate + EventRate = FairMQDevice::Last, + OutChannelName }; - GenericSampler(); - virtual ~GenericSampler(); + base_GenericSampler(); + virtual ~base_GenericSampler(); + /* + struct trait : source_type::trait, serialization_type::trait + { + //static const SerializationTag serialization = serialization_type::trait::serialization; + //static const FileTag + static const DeviceTag device = kSampler; + typedef base_GenericSampler self_type; + typedef source_type source_type; + typedef serialization_type serialization_type; + }; + + */ virtual void SetTransport(FairMQTransportFactory* factory); void ResetEventCounter(); @@ -65,36 +91,103 @@ class GenericSampler : public FairMQDevice, public SamplerPolicy, public OutputP template void SetFileProperties(Args&... args) { - SamplerPolicy::SetFileProperties(args...); + source_type::SetFileProperties(args...); } - virtual void SetProperty(const int key, const std::string& value); - virtual std::string GetProperty(const int key, const std::string& default_ = ""); virtual void SetProperty(const int key, const int value); virtual int GetProperty(const int key, const int default_ = 0); - - /** - * Sends the currently available output of the Sampler Task as part of a multipart message - * and reinitializes the message to be filled with the next part. - * This method can be given as a callback to the SamplerTask. - * The final message part must be sent with normal Send method. - */ - // temporary disabled - //void SendPart(); - - void SetContinuous(bool flag); - + virtual void SetProperty(const int key, const std::string& value); + virtual std::string GetProperty(const int key, const std::string& default_ = ""); + + void SendPart(int socketIdx); + int GetSocketNumber() const; + int GetCurrentIndex() const; + void SetContinuous(bool flag); + + + /// /////////////////////////////////////////////////////////////////////////////////////// + /* + register the tasks you want to process and, which will be + called by ExecuteTasks() member function. The registration is done by filling + a std::map where key_type is int and task_type + is std::function by default (when using GenericSampler alias template). + The template parameter must take a pointer to this class or derived class as first argument, + and a reference to a std::map as second argument. + It is convenient to use a lambda expression in the place of the template argument. + For example if we want to register the simple function, + //< + void myfunction() {std::cout << "hello World" << std::endl;} + //> + ,and the MultiPartTask() template function member of this class , then + we can do in the main function as follow : + + sampler.RegisterTask( + [&](TSampler* s, std::map >& task_list) + { + task_list[0]=std::bind(myfunction); + task_list[1]=std::bind(&U::template MultiPartTask<5>, s); + }); + + To communicate with the Host derived class via callback, three methods from the host class are callable (only + after binding these methods in the GenericSampler::InitTask() ) + + */ + template + void RegisterTask(RegistrationManager manage) + { + manage(this,fTaskList); + LOG(DEBUG)<<"Current Number of registered tasks = "< fTaskList; // to handle Task list + + + // automatically enable or disable the call of policy function members for binding of host functions. + // this template functions use SFINAE to detect the existence of the policy function signature. + template = 0 > + void BindingSendPart(){} + template = 0 > + void BindingSendPart() + { + source_type::BindSendPart(std::bind(&base_GenericSampler::SendPart,this,std::placeholders::_1) ); + } + + template = 0 > + void BindingGetSocketNumber(){} + template = 0 > + void BindingGetSocketNumber() + { + source_type::BindGetSocketNumber(std::bind(&base_GenericSampler::GetSocketNumber,this) ); + } + + template = 0 > + void BindingGetCurrentIndex(){} + template = 0 > + void BindingGetCurrentIndex() + { + source_type::BindGetCurrentIndex(std::bind(&base_GenericSampler::GetCurrentIndex,this) ); + } }; #include "GenericSampler.tpl" diff --git a/fairmq/devices/GenericSampler.tpl b/fairmq/devices/GenericSampler.tpl index 42790c51..ba61f5c1 100644 --- a/fairmq/devices/GenericSampler.tpl +++ b/fairmq/devices/GenericSampler.tpl @@ -5,72 +5,82 @@ * Created on November 24, 2014, 3:59 PM */ -template -GenericSampler::GenericSampler() - : fNumEvents(0) +template +base_GenericSampler::base_GenericSampler() + : fOutChanName("data-out") + , fNumEvents(0) + , fCurrentIdx(0) , fEventRate(1) , fEventCounter(0) , fContinuous(false) - , fInputFile() - , fParFile() - , fBranch() { } -template -GenericSampler::~GenericSampler() +template +base_GenericSampler::~base_GenericSampler() { } -template -void GenericSampler::SetTransport(FairMQTransportFactory* factory) +template +void base_GenericSampler::SetTransport(FairMQTransportFactory* factory) { FairMQDevice::SetTransport(factory); - // OutputPolicy::SetTransport(factory); } -template -void GenericSampler::InitTask() +template +void base_GenericSampler::InitTask() { - SamplerPolicy::InitSampler(); - fNumEvents = SamplerPolicy::GetNumberOfEvent(); + BindingSendPart(); + BindingGetSocketNumber(); + BindingGetCurrentIndex(); + + source_type::InitSampler(); + fNumEvents = source_type::GetNumberOfEvent(); } -template -void GenericSampler::Run() + + + +template +void base_GenericSampler::Run() { // boost::thread resetEventCounter(boost::bind(&GenericSampler::ResetEventCounter, this)); int sentMsgs = 0; - + boost::timer::auto_cpu_timer timer; LOG(INFO) << "Number of events to process: " << fNumEvents; - + do { - for (int64_t eventNr = 0; eventNr < fNumEvents; ++eventNr) + for (fCurrentIdx = 0; fCurrentIdx < fNumEvents; fCurrentIdx++) { - //fSamplerTask->SetEventIndex(eventNr); - FairMQMessage* msg = fTransportFactory->CreateMessage(); - OutputPolicy::SetMessage(msg); - fChannels["data-out"].at(0).Send(OutputPolicy::SerializeMsg(SamplerPolicy::GetDataBranch(eventNr))); - ++sentMsgs; - - if (msg) + for(auto& p : fChannels[fOutChanName]) { - msg->CloseMessage(); - } + FairMQMessage* msg = fTransportFactory->CreateMessage(); + serialization_type::SetMessage(msg); + source_type::SetIndex(fCurrentIdx); + ExecuteTasks(); + p.Send(serialization_type::SerializeMsg(source_type::GetOutData())); + if (msg) + msg->CloseMessage(); + sentMsgs++; - // Optional event rate limiting - // --fEventCounter; - // while (fEventCounter == 0) { - // boost::this_thread::sleep(boost::posix_time::milliseconds(1)); - // } - - if (GetCurrentState() != RUNNING) - { - break; + if(fChannels[fOutChanName].size()>1) + fCurrentIdx++; + + // Optional event rate limiting + // --fEventCounter; + // while (fEventCounter == 0) { + // boost::this_thread::sleep(boost::posix_time::milliseconds(1)); + // } + + if (GetCurrentState() != RUNNING) + break; } + // if more than one socket, remove the last incrementation + if(fChannels[fOutChanName].size()>1) + fCurrentIdx--; } } while ( GetCurrentState() == RUNNING && fContinuous ); @@ -80,23 +90,43 @@ void GenericSampler::Run() LOG(INFO) << "Sent " << sentMsgs << " messages!"; } -/* -template -void GenericSampler::SendPart() -{ - fChannels["data-out"].at(0).Send(OutputPolicy::GetMessage(), "snd-more"); - OutputPolicy::CloseMessage(); -} -*/ -template -void GenericSampler::SetContinuous(bool flag) +template +void base_GenericSampler::SendPart(int socketIdx) +{ + fCurrentIdx++; + if(fCurrentIdxCreateMessage(); + serialization_type::SetMessage(msg); + source_type::SetIndex(fCurrentIdx); + fChannels[fOutChanName].at(socketIdx).Send(serialization_type::SerializeMsg(source_type::GetOutData()), "snd-more"); + if (msg) + msg->CloseMessage(); + } +} + + +template +int base_GenericSampler::GetSocketNumber() const +{ + return fChannels.at(fOutChanName).size(); +} + +template +int base_GenericSampler::GetCurrentIndex() const +{ + return fCurrentIdx; +} + +template +void base_GenericSampler::SetContinuous(bool flag) { fContinuous = flag; } -template -void GenericSampler::ResetEventCounter() +template +void base_GenericSampler::ResetEventCounter() { while (GetCurrentState() == RUNNING) { @@ -114,44 +144,8 @@ void GenericSampler::ResetEventCounter() LOG(DEBUG) << ">>>>>>> stopping resetEventCounter <<<<<<<"; } -template -void GenericSampler::SetProperty(const int key, const std::string& value) -{ - switch (key) - { - case InputFile: - fInputFile = value; - break; - case ParFile: - fParFile = value; - break; - case Branch: - fBranch = value; - break; - default: - FairMQDevice::SetProperty(key, value); - break; - } -} - -template -std::string GenericSampler::GetProperty(const int key, const std::string& default_/*= ""*/) -{ - switch (key) - { - case InputFile: - return fInputFile; - case ParFile: - return fParFile; - case Branch: - return fBranch; - default: - return FairMQDevice::GetProperty(key, default_); - } -} - -template -void GenericSampler::SetProperty(const int key, const int value) +template +void base_GenericSampler::SetProperty(const int key, const int value) { switch (key) { @@ -164,8 +158,8 @@ void GenericSampler::SetProperty(const int key, cons } } -template -int GenericSampler::GetProperty(const int key, const int default_/*= 0*/) +template +int base_GenericSampler::GetProperty(const int key, const int default_/*= 0*/) { switch (key) { @@ -175,3 +169,35 @@ int GenericSampler::GetProperty(const int key, const return FairMQDevice::GetProperty(key, default_); } } + +template +void base_GenericSampler::SetProperty(const int key, const std::string& value) +{ + switch (key) + { + case OutChannelName: + fOutChanName = value; + break; + default: + FairMQDevice::SetProperty(key, value); + break; + } +} + +template +std::string base_GenericSampler::GetProperty(const int key, const std::string& default_) +{ + switch (key) + { + case OutChannelName: + return fOutChanName; + default: + return FairMQDevice::GetProperty(key, default_); + } +} + + + +template +using GenericSampler = base_GenericSampler >; +typedef std::map > SamplerTasksMap; diff --git a/fairmq/options/FairMQParser.cxx b/fairmq/options/FairMQParser.cxx index 329d8a5f..c56fd24a 100644 --- a/fairmq/options/FairMQParser.cxx +++ b/fairmq/options/FairMQParser.cxx @@ -14,7 +14,7 @@ #include "FairMQParser.h" #include "FairMQLogger.h" - +#include // WARNING : pragma commands to hide boost (1.54.0) warning // TODO : remove these pragma commands when boost will fix this issue in future release #pragma clang diagnostic push @@ -188,4 +188,22 @@ FairMQMap JSON::UserParser(std::stringstream& input, const std::string& deviceId return ptreeToMQMap(pt, deviceId, rootNode,"json"); } + +//////////////////////////////////////////////////////////////////////////// +FairMQMap XML::UserParser(const std::string& filename, const std::string& deviceId, const std::string& rootNode) +{ + boost::property_tree::ptree pt; + boost::property_tree::read_xml(filename, pt); + return ptreeToMQMap(pt,deviceId,rootNode,"xml"); +} + +FairMQMap XML::UserParser(std::stringstream& input, const std::string& deviceId, const std::string& rootNode) +{ + boost::property_tree::ptree pt; + boost::property_tree::read_xml(input, pt); + return ptreeToMQMap(pt,deviceId,rootNode,"xml"); +} + + + } // end FairMQParser namespace \ No newline at end of file diff --git a/fairmq/options/FairMQParser.h b/fairmq/options/FairMQParser.h index 71cda2a5..66460507 100644 --- a/fairmq/options/FairMQParser.h +++ b/fairmq/options/FairMQParser.h @@ -32,6 +32,12 @@ struct JSON FairMQMap UserParser(std::stringstream& input, const std::string& deviceId, const std::string& rootNode = "fairMQOptions"); }; +struct XML +{ + FairMQMap UserParser(const std::string& filename, const std::string& deviceId, const std::string& root_node="fairMQOptions"); + FairMQMap UserParser(std::stringstream& input, const std::string& deviceId, const std::string& rootNode="fairMQOptions"); +}; + } // FairMQParser namespace #endif /* FAIRMQPARSER_H */ diff --git a/fairmq/options/FairMQProgOptions.cxx b/fairmq/options/FairMQProgOptions.cxx index 98b39ce4..e38d325d 100644 --- a/fairmq/options/FairMQProgOptions.cxx +++ b/fairmq/options/FairMQProgOptions.cxx @@ -19,10 +19,11 @@ FairMQProgOptions::FairMQProgOptions() : FairProgOptions() , fMQParserOptions("MQ-Device parser options") + , fMQOptionsInCmd("MQ-Device options") + , fMQOptionsInCfg("MQ-Device options") , fMQtree() , fFairMQmap() { - InitOptionDescription(); } FairMQProgOptions::~FairMQProgOptions() @@ -30,53 +31,62 @@ FairMQProgOptions::~FairMQProgOptions() } int FairMQProgOptions::ParseAll(const int argc, char** argv, bool AllowUnregistered) -{ - // before parsing, define cmdline and optionally cfgfile description, - // and also what is visible for the user - AddToCmdLineOptions(fGenericDesc); - AddToCmdLineOptions(fMQParserOptions); - - // if config file option enabled then id non required in cmdline but required in configfile - // else required in cmdline - if (fUseConfigFile) - { - fCmdline_options.add_options() - ("id", po::value< std::string >(), "Device ID"); - fConfig_file_options.add_options() - ("id", po::value< std::string >()->required(), "Device ID"); - } - else - { - fCmdline_options.add_options() - ("id", po::value< std::string >()->required(), "Device ID"); - } - - fVisible_options.add_options() - ("id", po::value< std::string >()->required(), "Device ID (required value)"); - - // parse command line +{ + // init description + InitOptionDescription(); + // parse command line options if (ParseCmdLine(argc,argv,fCmdline_options,fvarmap,AllowUnregistered)) { return 1; } - // if txt/INI configuration file enabled then parse it - if (fUseConfigFile && !fConfigFile.empty()) + // if txt/INI configuration file enabled then parse it as well + if (fUseConfigFile) { - AddToCfgFileOptions(fMQParserOptions,false); - - if (ParseCfgFile(fConfigFile, fConfig_file_options, fvarmap, AllowUnregistered)) + // check if file exist + if (fs::exists(fConfigFile)) { + if (ParseCfgFile(fConfigFile.string(), fConfig_file_options, fvarmap, AllowUnregistered)) + return 1; + } + else + { + LOG(ERROR)<<"config file '"<< fConfigFile <<"' not found"; return 1; } } - + // set log level before printing (default is 0 = DEBUG level) int verbose=GetValue("verbose"); SET_LOGGER_LEVEL(verbose); PrintOptions(); - + + // check if one of required MQ config option is there + auto parserOption_shptr = fMQParserOptions.options(); + bool option_exists=false; + std::vector MQParserKeys; + for(const auto& p : parserOption_shptr) + { + MQParserKeys.push_back( p->canonical_display_name() ); + if( fvarmap.count( p->canonical_display_name() ) ) + { + option_exists=true; + break; + } + } + + if(!option_exists) + { + LOG(ERROR)<<"Required option to configure the MQ device is not there."; + LOG(ERROR)<<"Please provide the value of one of the following key:"; + for(const auto& p : MQParserKeys) + { + LOG(ERROR)< >()->multitoken(), "XML input as command line string.") - ("config-xml-file", po::value< std::string >(), "XML input as file.") - ("config-json-string", po::value< std::vector >()->multitoken(), "JSON input as command line string.") - ("config-json-file", po::value< std::string >(), "JSON input as file.") + // Id required in command line if config txt file not enabled + if (fUseConfigFile) + { + fMQOptionsInCmd.add_options() + ("id", po::value< std::string >(), "Device ID (required argument)") + ("io-threads", po::value()->default_value(1), "io threads number"); - // ("ini.config.string", po::value< std::vector >()->multitoken(), "INI input as command line string.") - // ("ini.config.file", po::value< std::string >(), "INI input as file.") - ; + fMQOptionsInCfg.add_options() + ("id", po::value< std::string >()->required(), "Device ID (required argument)") + ("io-threads", po::value()->default_value(1), "io threads number"); + } + else + { + fMQOptionsInCmd.add_options() + ("id", po::value< std::string >()->required(), "Device ID (required argument)") + ("io-threads", po::value()->default_value(1), "io threads number"); + } + + fMQParserOptions.add_options() + ("config-xml-string", po::value< std::vector >()->multitoken(), "XML input as command line string.") + ("config-xml-file", po::value< std::string >(), "XML input as file.") + ("config-json-string", po::value< std::vector >()->multitoken(), "JSON input as command line string.") + ("config-json-file", po::value< std::string >(), "JSON input as file."); + + + AddToCmdLineOptions(fGenericDesc); + AddToCmdLineOptions(fMQOptionsInCmd); + AddToCmdLineOptions(fMQParserOptions); + + if (fUseConfigFile) + { + AddToCfgFileOptions(fMQOptionsInCfg,false); + AddToCfgFileOptions(fMQParserOptions,false); + } + } \ No newline at end of file diff --git a/fairmq/options/FairMQProgOptions.h b/fairmq/options/FairMQProgOptions.h index 970dbe2d..8ac2f07c 100644 --- a/fairmq/options/FairMQProgOptions.h +++ b/fairmq/options/FairMQProgOptions.h @@ -74,6 +74,8 @@ public: protected: po::options_description fMQParserOptions; + po::options_description fMQOptionsInCfg; + po::options_description fMQOptionsInCmd; pt::ptree fMQtree; FairMQMap fFairMQmap; diff --git a/fairmq/options/FairProgOptions.cxx b/fairmq/options/FairProgOptions.cxx index 707a1630..38d76231 100644 --- a/fairmq/options/FairProgOptions.cxx +++ b/fairmq/options/FairProgOptions.cxx @@ -64,6 +64,10 @@ int FairProgOptions::AddToCmdLineOptions(const po::options_description& optdesc, int FairProgOptions::AddToCfgFileOptions(const po::options_description& optdesc, bool visible) { + //if UseConfigFile() not yet called, then enable it with required file name to be provided by command line + if(!fUseConfigFile) + UseConfigFile(); + fConfig_file_options.add(optdesc); if(visible) fVisible_options.add(optdesc); @@ -82,8 +86,9 @@ void FairProgOptions::UseConfigFile(const std::string& filename) fUseConfigFile = true; if (filename.empty()) { - fCmdline_options.add_options() - ("config,c", po::value(&fConfigFile)->required(), "Path to configuration file"); + fConfigDesc.add_options() + ("config,c", po::value(&fConfigFile)->required(), "Path to configuration file (required argument)"); + AddToCmdLineOptions(fConfigDesc); } else { @@ -464,6 +469,7 @@ FairProgOptions::VarValInfo_t FairProgOptions::Get_variable_value_info(const po: if(auto q = boost::any_cast(&value)) { std::string val_str = (*q).string(); + //std::string val_str = (*q).filename().generic_string(); return std::make_tuple(val_str,std::string(" [Type=boost::filesystem::path]"),defaulted_val,empty_val); } diff --git a/fairmq/options/FairProgOptions.h b/fairmq/options/FairProgOptions.h index 7ed7438b..cca7cda3 100644 --- a/fairmq/options/FairProgOptions.h +++ b/fairmq/options/FairProgOptions.h @@ -62,6 +62,7 @@ std::ostream& operator<<(std::ostream& os, const std::vector& v) } namespace po = boost::program_options; +namespace fs = boost::filesystem; class FairProgOptions { @@ -87,12 +88,6 @@ public: { val = fvarmap[key].as(); } - else - { - LOG(ERROR) << "Key '"<< key <<"' not found in boost variable map"; - LOG(INFO) << "Command line / txt config file options are the following : "; - this->PrintHelp(); - } } catch(std::exception& e) { @@ -144,7 +139,7 @@ protected: int fVerboseLvl; bool fUseConfigFile; - std::string fConfigFile; + boost::filesystem::path fConfigFile; virtual int NotifySwitchOption(); // UpadateVarMap() and replace() --> helper functions to modify the value of variable map after calling po::store diff --git a/fairmq/options/ProgOptionTest/lib/FairMQParserExample.cxx b/fairmq/options/ProgOptionTest/lib/FairMQParserExample.cxx index 3fdca457..4df42dc1 100644 --- a/fairmq/options/ProgOptionTest/lib/FairMQParserExample.cxx +++ b/fairmq/options/ProgOptionTest/lib/FairMQParserExample.cxx @@ -13,29 +13,6 @@ namespace FairMQParser { - - //////////////////////////////////////////////////////////////////////////// - //----------- filename version - FairMQMap XML::UserParser(const std::string& filename, const std::string& device_id, const std::string& root_node) - { - boost::property_tree::ptree pt; - boost::property_tree::read_xml(filename, pt); - return ptreeToMQMap(pt,device_id,root_node,"xml"); - } - - - - //----------- stringstream version - FairMQMap XML::UserParser(std::stringstream& input_ss, const std::string& device_id, const std::string& root_node) - { - boost::property_tree::ptree pt; - boost::property_tree::read_xml(input_ss, pt); - return ptreeToMQMap(pt,device_id,root_node,"xml"); - } - - - - // other xml examples //////////////////////////////////////////////////////////////////////////// boost::property_tree::ptree MQXML2::UserParser(const std::string& filename) diff --git a/fairmq/options/ProgOptionTest/lib/FairMQParserExample.h b/fairmq/options/ProgOptionTest/lib/FairMQParserExample.h index cefeb281..be20ab06 100644 --- a/fairmq/options/ProgOptionTest/lib/FairMQParserExample.h +++ b/fairmq/options/ProgOptionTest/lib/FairMQParserExample.h @@ -27,15 +27,7 @@ namespace FairMQParser //////////////////////////////////////////////////////////////////////////// /////////////////////////////////// XML //////////////////////////////////// //////////////////////////////////////////////////////////////////////////// - - // xml example 1 - //////////////////////////////////////////////////////////////////////////// - struct XML - { - FairMQMap UserParser(const std::string& filename, const std::string& device_id, const std::string& root_node="fairMQOptions"); - FairMQMap UserParser(std::stringstream& input_ss, const std::string& device_id, const std::string& root_node="fairMQOptions"); - }; - + // xml example 2 //////////////////////////////////////////////////////////////////////////// struct MQXML2 diff --git a/fairmq/tools/FairMQTools.h b/fairmq/tools/FairMQTools.h index d649731b..b8138aa5 100644 --- a/fairmq/tools/FairMQTools.h +++ b/fairmq/tools/FairMQTools.h @@ -14,6 +14,7 @@ #include #include #include +#include using namespace std; @@ -58,6 +59,85 @@ int getHostIPs(map& addressMap) return 0; } + + +// below are SFINAE template functions to check for function member signatures of class +namespace details +{ + /////////////////////////////////////////////////////////////////////////// + // test, at compile time, whether T has BindSendPart member function with returned type R and argument ...Args type + template + struct has_BindSendPart:std::false_type{}; + + template + struct has_BindSendPart + ().BindSendPart(std::declval()...)), R >::value + || std::is_same::value + >::type + >:std::true_type{}; + + /////////////////////////////////////////////////////////////////////////// + // test, at compile time, whether T has BindGetSocketNumber member function with returned type R and argument ...Args type + template + struct has_BindGetSocketNumber:std::false_type{}; + + template + struct has_BindGetSocketNumber + ().BindGetSocketNumber(std::declval()...)), R >::value + || std::is_same::value + >::type + >:std::true_type{}; + + /////////////////////////////////////////////////////////////////////////// + // test, at compile time, whether T has BindGetCurrentIndex member function with returned type R and argument ...Args type + template + struct has_BindGetCurrentIndex:std::false_type{}; + + template + struct has_BindGetCurrentIndex + ().BindGetCurrentIndex(std::declval()...)), R >::value + || std::is_same::value + >::type + >:std::true_type{}; + +}// end namespace details + +/////////////////////////////////////////////////////////////////////////// +// Alias template of the above structs +template +using has_BindSendPart = std::integral_constant::value>; + +template +using has_BindGetSocketNumber = std::integral_constant::value>; + +template +using has_BindGetCurrentIndex = std::integral_constant::value>; + +// enable_if Alias template +template +using enable_if_has_BindSendPart = typename std::enable_if::value,int>::type; +template +using enable_if_hasNot_BindSendPart = typename std::enable_if::value,int>::type; + +template +using enable_if_has_BindGetSocketNumber = typename std::enable_if::value,int>::type; +template +using enable_if_hasNot_BindGetSocketNumber = typename std::enable_if::value,int>::type; + +template +using enable_if_has_BindGetCurrentIndex = typename std::enable_if::value,int>::type; +template +using enable_if_hasNot_BindGetCurrentIndex = typename std::enable_if::value,int>::type; + } // namespace tools } // namespace FairMQ