template <typename R, typename... Args> classNodeFunctor<R(const ObjectRef& n, Args...)> { private: /*! \brief internal function pointer type */ typedefR(*FPointer)(const ObjectRef& n, Args...); /*! \brief refer to itself. */ using TSelf = NodeFunctor<R(const ObjectRef& n, Args...)>; /*! \brief internal function table */ std::vector<FPointer> func_;
public: /*! \brief the result type of this functor */ using result_type = R; /*! * \brief Whether the functor can dispatch the corresponding Node * \param n The node to be dispatched * \return Whether dispatching function is registered for n's type. */ boolcan_dispatch(const ObjectRef& n)const{ uint32_t type_index = n->type_index(); return type_index < func_.size() && func_[type_index] != nullptr; } /*! * \brief invoke the functor, dispatch on type of n * \param n The Node argument * \param args The additional arguments * \return The result. */ R operator()(const ObjectRef& n, Args... args)const{ ICHECK(can_dispatch(n)) << "NodeFunctor calls un-registered function on type " << n->GetTypeKey(); return (*func_[n->type_index()])(n, std::forward<Args>(args)...); } /*! * \brief set the dispacher for type TNode * \param f The function to be set. * \tparam TNode the type of Node to be dispatched. * \return reference to self. */ template <typename TNode> TSelf& set_dispatch(FPointer f){ // NOLINT(*) uint32_t tindex = TNode::RuntimeTypeIndex(); if (func_.size() <= tindex) { func_.resize(tindex + 1, nullptr); } ICHECK(func_[tindex] == nullptr) << "Dispatch for " << TNode::_type_key << " is already set"; func_[tindex] = f; return *this; }
NodeFunctor是一个对于节点node的仿函数类,输入为const ObjectRef& n, Args... 返回值是 R,这个类有多态的属性,可注册函数。通过不同的ObjectRef参数从而多态调用注册好的函数
/*! * \brief A wrapper around ExprVisitor which traverses the Dataflow Normal AST. * * MixedModeVisitor treats Expr as dataflow graph, and visits in post-DFS order * * MixedModeVisitor provides the same recursive API as ExprVisitor, and uses * recursion to traverse most forms of the IR, but under the hood it expands nested dataflow regions * of the graph and processes them iteratively to prevent stack overflows */ classMixedModeVisitor :public ::tvm::relay::ExprVisitor{ ... }
\\brief Useful macro to set NodeFunctor dispatch in a global static field.
// Use NodeFunctor to implement ReprPrinter similar to Visitor Pattern. // vtable allows easy patch of new Node types, without changing // interface of ReprPrinter. classReprPrinter { public: std::ostream& stream; the dispatch function. voidprint(Expr e){ conststatic FType& f = *vtable(); f(e, this); }
using FType = NodeFunctor<void (const ObjectRef&, ReprPrinter* )>; // function to return global function table static FType& vtable(); }; // in cpp/cc file ReprPrinter::FType& ReprPrinter::vtable(){ // NOLINT(*) static FType inst; return inst; }