// Author: Enrico Guiraud, Danilo Piparo CERN 02/2018 /************************************************************************* * Copyright (C) 1995-2018, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ // This header contains helper free functions that slim down RDataFrame's programming model #ifndef ROOT_RDF_HELPERS #define ROOT_RDF_HELPERS #include #include #include #include #include // std::transform #include #include #include #include #include #include namespace ROOT { namespace Internal { namespace RDF { template std::function NotHelper(ROOT::TypeTraits::TypeList, F &&f) { return std::function([=](ArgTypes... args) mutable { return !f(args...); }); } template std::function NotHelper(ROOT::TypeTraits::TypeList, Ret (*f)(Args...)) { return std::function([=](ArgTypes... args) mutable { return !f(args...); }); } template class PassAsVecHelper; template class PassAsVecHelper, T, F> { template using AlwaysT = T; F fFunc; public: PassAsVecHelper(F &&f) : fFunc(std::forward(f)) {} auto operator()(AlwaysT... args) -> decltype(fFunc({args...})) { return fFunc({args...}); } }; template auto PassAsVec(F &&f) -> PassAsVecHelper, T, F> { return PassAsVecHelper, T, F>(std::forward(f)); } } // namespace RDF } // namespace Internal namespace RDF { namespace RDFInternal = ROOT::Internal::RDF; // clag-format off /// Given a callable with signature bool(T1, T2, ...) return a callable with same signature that returns the negated result /// /// The callable must have one single non-template definition of operator(). This is a limitation with respect to /// std::not_fn, required for interoperability with RDataFrame. // clang-format on template ::type>::arg_types_nodecay, typename Ret = typename ROOT::TypeTraits::CallableTraits::type>::ret_type> auto Not(F &&f) -> decltype(RDFInternal::NotHelper(Args(), std::forward(f))) { static_assert(std::is_same::value, "RDF::Not requires a callable that returns a bool."); return RDFInternal::NotHelper(Args(), std::forward(f)); } // clang-format off /// PassAsVec is a callable generator that allows passing N variables of type T to a function as a single collection. /// /// PassAsVec(func) returns a callable that takes N arguments of type T, passes them down to function `func` as /// an initializer list `{t1, t2, t3,..., tN}` and returns whatever f({t1, t2, t3, ..., tN}) returns. /// /// Note that for this to work with RDataFrame the type of all columns that the callable is applied to must be exactly T. /// Example usage together with RDataFrame ("varX" columns must all be `float` variables): /// \code /// bool myVecFunc(std::vector args); /// df.Filter(PassAsVec<3, float>(myVecFunc), {"var1", "var2", "var3"}); /// \endcode // clang-format on template auto PassAsVec(F &&f) -> RDFInternal::PassAsVecHelper, T, F> { return RDFInternal::PassAsVecHelper, T, F>(std::forward(f)); } template class RInterface; // clang-format off /// Create a graphviz representation of the dataframe computation graph, return it as a string. /// \param[in] node any node of the graph. Called on the head (first) node, it prints the entire graph. Otherwise, only the branch the node belongs to. // clang-format on template std::string SaveGraph(NodeType node) { ROOT::Internal::RDF::GraphDrawing::GraphCreatorHelper helper; return helper(node); } // clang-format off /// Create a graphviz representation of the dataframe computation graph, write it to the specified file. /// \param[in] node any node of the graph. Called on the head (first) node, it prints the entire graph. Otherwise, only the branch the node belongs to. /// \param[in] outputFile file where to save the representation. // clang-format on template void SaveGraph(NodeType node, const std::string &outputFile) { ROOT::Internal::RDF::GraphDrawing::GraphCreatorHelper helper; std::string dotGraph = helper(node); std::ofstream out(outputFile); if (!out.is_open()) { throw std::runtime_error("Could not open output file \"" + outputFile + "\"for reading"); } out << dotGraph; out.close(); } // clang-format off /// Cast a RDataFrame node to the common type ROOT::RDF::RNode /// \param[in] Any node of a RDataFrame graph // clang-format on template RNode AsRNode(NodeType node) { return node; } } // namespace RDF } // namespace ROOT #endif