Drake
cpp_template_pybind.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <string>
4 #include <utility>
5 
6 #include "pybind11/functional.h"
7 #include "pybind11/pybind11.h"
8 #include "pybind11/stl.h"
9 
11 // `GetPyTypes` is implemented specifically for `cpp_template`; to simplify
12 // dependencies, this is included transitively.
14 
15 namespace drake {
16 namespace pydrake {
17 namespace internal {
18 
19 // C++ interface for `pydrake.util.cpp_template.get_or_init`.
20 // Please see that function for common parameters.
21 // @param template_cls_name Name of the template class in `cpp_template`,
22 // resolves to class to be passed as `template_cls`.
23 inline py::object GetOrInitTemplate(
24  py::handle scope, const std::string& name,
25  const std::string& template_cls_name,
26  py::tuple args = py::tuple(), py::dict kwargs = py::dict()) {
27  const char module_name[] = "pydrake.util.cpp_template";
28  py::handle m = py::module::import(module_name);
29  return m.attr("get_or_init")(
30  scope, name, m.attr(template_cls_name.c_str()), *args, **kwargs);
31 }
32 
33 // Adds instantiation to a Python template.
34 inline void AddInstantiation(
35  py::handle py_template, py::handle obj, py::tuple param) {
36  py_template.attr("add_instantiation")(param, obj);
37 }
38 
39 // Gets name for a given instantiation.
40 inline std::string GetInstantiationName(
41  py::handle py_template, py::tuple param) {
42  return py::cast<std::string>(
43  py_template.attr("_instantiation_name")(param));
44 }
45 
46 } // namespace internal
47 
48 
49 /// Provides a temporary, unique name for a class instantiation that
50 /// will be passed to `AddTemplateClass`.
51 template <typename T>
52 std::string TemporaryClassName(
53  const std::string& name = "TemporaryName") {
54  return "_" + name + "_" + typeid(T).name();
55 }
56 
57 /// Adds a template class instantiation.
58 /// @param scope Parent scope of the template.
59 /// @param name Name of the template.
60 /// @param py_class Class instantiation to be added.
61 /// @note The class name should be *unique*. If you would like automatic unique
62 /// names, consider constructing the class binding as
63 /// `py::class_<Class, ...>(m, TemporaryClassName<Class>().c_str())`.
64 /// @param param Parameters for the instantiation.
65 inline py::object AddTemplateClass(
66  py::handle scope, const std::string& name,
67  py::handle py_class, py::tuple param) {
68  py::object py_template =
69  internal::GetOrInitTemplate(scope, name, "TemplateClass");
70  internal::AddInstantiation(py_template, py_class, param);
71  return py_template;
72 }
73 
74 /// Provides a convenience wrapper for defining a template class instantiation
75 /// and a default instantiation (if not already defined).
76 /// The default instantiation is named `default_name`, while the template is
77 /// named `default_name + template_suffix`.
78 /// @return pybind11 class
79 template <typename Class, typename... Options>
80 py::class_<Class, Options...> DefineTemplateClassWithDefault(
81  py::handle scope, const std::string& default_name, py::tuple param,
82  const std::string& template_suffix = "_") {
83  const std::string template_name = default_name + template_suffix;
84  // Define class with temporary name.
85  py::class_<Class, Options...> py_class(
86  scope, TemporaryClassName<Class>().c_str());
87  // Register instantiation.
88  AddTemplateClass(scope, template_name, py_class, param);
89  // Declare default instantiation if it does not already exist.
90  if (!py::hasattr(scope, default_name.c_str())) {
91  scope.attr(default_name.c_str()) = py_class;
92  }
93  return py_class;
94 }
95 
96 /// Declares a template function.
97 /// @param scope Parent scope of the template.
98 /// @param name Name of the template.
99 /// @param func Function to be added.
100 /// @param param Parameters for the instantiation.
101 template <typename Func>
103  py::handle scope, const std::string& name, Func&& func,
104  py::tuple param) {
105  // TODO(eric.cousineau): Use `py::sibling` if overloads are needed.
106  py::object py_template =
107  internal::GetOrInitTemplate(scope, name, "TemplateFunction");
108  py::object py_func = py::cpp_function(
109  std::forward<Func>(func),
110  py::name(internal::GetInstantiationName(py_template, param).c_str()));
111  internal::AddInstantiation(py_template, py_func, param);
112  return py_template;
113 }
114 
115 /// Declares a template method.
116 /// @param scope Parent scope of the template. This should be a class.
117 /// @param name Name of the template.
118 /// @param method Method to be added.
119 /// @param param Parameters for the instantiation.
120 template <typename Method>
121 py::object AddTemplateMethod(
122  py::handle scope, const std::string& name, Method&& method,
123  py::tuple param) {
124  py::object py_template =
126  scope, name, "TemplateMethod", py::make_tuple(scope));
127  py::object py_func = py::cpp_function(
128  std::forward<Method>(method),
129  py::name(internal::GetInstantiationName(py_template, param).c_str()),
130  py::is_method(scope));
131  internal::AddInstantiation(py_template, py_func, param);
132  return py_template;
133 }
134 
135 } // namespace pydrake
136 } // namespace drake
Definition: automotive_demo.cc:90
std::string TemporaryClassName(const std::string &name="TemporaryName")
Provides a temporary, unique name for a class instantiation that will be passed to AddTemplateClass...
Definition: cpp_template_pybind.h:52
Provides a mechanism to map C++ types to canonical Python types.
void AddInstantiation(py::handle py_template, py::handle obj, py::tuple param)
Definition: cpp_template_pybind.h:34
py::class_< Class, Options... > DefineTemplateClassWithDefault(py::handle scope, const std::string &default_name, py::tuple param, const std::string &template_suffix="_")
Provides a convenience wrapper for defining a template class instantiation and a default instantiatio...
Definition: cpp_template_pybind.h:80
py::object GetOrInitTemplate(py::handle scope, const std::string &name, const std::string &template_cls_name, py::tuple args=py::tuple(), py::dict kwargs=py::dict())
Definition: cpp_template_pybind.h:23
py::object AddTemplateFunction(py::handle scope, const std::string &name, Func &&func, py::tuple param)
Declares a template function.
Definition: cpp_template_pybind.h:102
py::object AddTemplateClass(py::handle scope, const std::string &name, py::handle py_class, py::tuple param)
Adds a template class instantiation.
Definition: cpp_template_pybind.h:65
py::object AddTemplateMethod(py::handle scope, const std::string &name, Method &&method, py::tuple param)
Declares a template method.
Definition: cpp_template_pybind.h:121
const char * func
Definition: drake_throw.h:16
std::string GetInstantiationName(py::handle py_template, py::tuple param)
Definition: cpp_template_pybind.h:40