// @(#)root/thread:$Id$ // Author: Xavier Valls November 2017 /************************************************************************* * Copyright (C) 1995-2006, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ #ifndef ROOT_TSequentialExecutor #define ROOT_TSequentialExecutor #include "RConfigure.h" #include "ROOT/TExecutor.hxx" #include #include namespace ROOT { class TSequentialExecutor: public TExecutor { public: explicit TSequentialExecutor(){}; TSequentialExecutor(TSequentialExecutor &) = delete; TSequentialExecutor &operator=(TSequentialExecutor &) = delete; template void Foreach(F func, unsigned nTimes); template void Foreach(F func, ROOT::TSeq args); /// \cond template void Foreach(F func, std::initializer_list args); /// \endcond template void Foreach(F func, std::vector &args); using TExecutor::Map; template> auto Map(F func, unsigned nTimes) -> std::vector::type>; template> auto Map(F func, ROOT::TSeq args) -> std::vector::type>; template> auto Map(F func, std::vector &args) -> std::vector::type>; // // MapReduce // // the late return types also check at compile-time whether redfunc is compatible with func, // // other than checking that func is compatible with the type of arguments. // // a static_assert check in TSequentialExecutor::Reduce is used to check that redfunc is compatible with the type returned by func using TExecutor::MapReduce; template> auto MapReduce(F func, unsigned nTimes, R redfunc) -> typename std::result_of::type; template> auto MapReduce(F func, std::vector &args, R redfunc) -> typename std::result_of::type; using TExecutor::Reduce; template auto Reduce(const std::vector &objs, R redfunc) -> decltype(redfunc(objs)); }; /************ TEMPLATE METHODS IMPLEMENTATION ******************/ ////////////////////////////////////////////////////////////////////////// /// Execute func (with no arguments) nTimes. /// Functions that take more than zero arguments can be executed (with /// fixed arguments) by wrapping them in a lambda or with std::bind. template void TSequentialExecutor::Foreach(F func, unsigned nTimes) { for (auto i = 0U; i < nTimes; ++i) func(); } ////////////////////////////////////////////////////////////////////////// /// Execute func, taking an element of a /// sequence as argument. template void TSequentialExecutor::Foreach(F func, ROOT::TSeq args) { for(auto i : args) func(i); } /// \cond ////////////////////////////////////////////////////////////////////////// /// Execute func, taking an element of a /// initializer_list as argument. template void TSequentialExecutor::Foreach(F func, std::initializer_list args) { std::vector vargs(std::move(args)); Foreach(func, vargs); } /// \endcond ////////////////////////////////////////////////////////////////////////// /// Execute func, taking an element of an /// std::vector as argument. template void TSequentialExecutor::Foreach(F func, std::vector &args) { unsigned int nToProcess = args.size(); for(auto i: ROOT::TSeqI(nToProcess)) func(args[i]); } ////////////////////////////////////////////////////////////////////////// /// Execute func (with no arguments) nTimes. /// A vector containg executions' results is returned. /// Functions that take more than zero arguments can be executed (with /// fixed arguments) by wrapping them in a lambda or with std::bind. template auto TSequentialExecutor::Map(F func, unsigned nTimes) -> std::vector::type> { using retType = decltype(func()); std::vector reslist(nTimes); for(auto i: ROOT::TSeqI(nTimes)) reslist[i] = func(); return reslist; } ////////////////////////////////////////////////////////////////////////// /// Execute func, taking an element of a /// sequence as argument. /// A vector containg executions' results is returned. template auto TSequentialExecutor::Map(F func, ROOT::TSeq args) -> std::vector::type> { using retType = decltype(func(*args.begin())); std::vector reslist(args.size()); for(auto i: args) reslist[i] = func(i); return reslist; } ////////////////////////////////////////////////////////////////////////// /// Execute func, taking an element of an /// std::vector as argument. /// A vector containg executions' results is returned. // actual implementation of the Map method. all other calls with arguments eventually // call this one template auto TSequentialExecutor::Map(F func, std::vector &args) -> std::vector::type> { // //check whether func is callable using retType = decltype(func(args.front())); unsigned int nToProcess = args.size(); std::vector reslist(nToProcess); for(auto i: ROOT::TSeqI(nToProcess)) reslist[i] = func(args[i]); return reslist; } template auto TSequentialExecutor::MapReduce(F func, unsigned nTimes, R redfunc) -> typename std::result_of::type { return Reduce(Map(func, nTimes), redfunc); } template auto TSequentialExecutor::MapReduce(F func, std::vector &args, R redfunc) -> typename std::result_of::type { return Reduce(Map(func, args), redfunc); } ////////////////////////////////////////////////////////////////////////// /// "Reduce" an std::vector into a single object by passing a /// function as the second argument defining the reduction operation. template auto TSequentialExecutor::Reduce(const std::vector &objs, R redfunc) -> decltype(redfunc(objs)) { // check we can apply reduce to objs static_assert(std::is_same::value, "redfunc does not have the correct signature"); return redfunc(objs); } } // namespace ROOT #endif