type.py
Go to the documentation of this file.
1 """
2 GTSAM Copyright 2010-2020, Georgia Tech Research Corporation,
3 Atlanta, Georgia 30332-0415
4 All Rights Reserved
5 
6 See LICENSE for the license information
7 
8 Define the parser rules and classes for various C++ types.
9 
10 Author: Duy Nguyen Ta, Fan Jiang, Matthew Sklar, Varun Agrawal, and Frank Dellaert
11 """
12 
13 # pylint: disable=unnecessary-lambda, expression-not-assigned
14 
15 from typing import Iterable, List, Union
16 
17 from pyparsing import Forward, Optional, Or, ParseResults, delimitedList
18 
19 from .tokens import (BASIS_TYPES, CONST, IDENT, LOPBRACK, RAW_POINTER, REF,
20  ROPBRACK, SHARED_POINTER)
21 
22 
23 class Typename:
24  """
25  Generic type which can be either a basic type or a class type,
26  similar to C++'s `typename` aka a qualified dependent type.
27  Contains type name with full namespace and template arguments.
28 
29  E.g.
30  ```
31  gtsam::PinholeCamera<gtsam::Cal3S2>
32  ```
33 
34  will give the name as `PinholeCamera`, namespace as `gtsam`,
35  and template instantiations as `[gtsam::Cal3S2]`.
36 
37  Args:
38  namespaces_and_name: A list representing the namespaces of the type
39  with the type being the last element.
40  instantiations: Template parameters to the type.
41  """
42 
43  namespaces_name_rule = delimitedList(IDENT, "::")
44  instantiation_name_rule = delimitedList(IDENT, "::")
45  rule = (
46  namespaces_name_rule("namespaces_and_name") #
47  ).setParseAction(lambda t: Typename(t))
48 
49  def __init__(self,
50  t: ParseResults,
51  instantiations: Union[tuple, list, str, ParseResults] = ()):
52  self.name = t[-1] # the name is the last element in this list
53  self.namespaces = t[:-1]
54 
55  if instantiations:
56  if isinstance(instantiations, Iterable):
57  self.instantiations = instantiations # type: ignore
58  else:
59  self.instantiations = instantiations.asList()
60  else:
61  self.instantiations = []
62 
63  if self.name in ["Matrix", "Vector"] and not self.namespaces:
64  self.namespaces = ["gtsam"]
65 
66  @staticmethod
67  def from_parse_result(parse_result: Union[str, list]):
68  """Unpack the parsed result to get the Typename instance."""
69  return parse_result[0]
70 
71  def __repr__(self) -> str:
72  return self.to_cpp()
73 
74  def instantiated_name(self) -> str:
75  """Get the instantiated name of the type."""
76  res = self.name
77  for instantiation in self.instantiations:
78  res += instantiation.instantiated_name()
79  return res
80 
81  def qualified_name(self):
82  """Return the fully qualified name, e.g. `gtsam::internal::PoseKey`."""
83  return "::".join(self.namespaces + [self.name])
84 
85  def to_cpp(self) -> str:
86  """Generate the C++ code for wrapping."""
87  idx = 1 if self.namespaces and not self.namespaces[0] else 0
88  if self.instantiations:
89  cpp_name = self.name + "<{}>".format(", ".join(
90  [inst.to_cpp() for inst in self.instantiations]))
91  else:
92  cpp_name = self.name
93  return '{}{}{}'.format(
94  "::".join(self.namespaces[idx:]),
95  "::" if self.namespaces[idx:] else "",
96  cpp_name,
97  )
98 
99  def __eq__(self, other) -> bool:
100  if isinstance(other, Typename):
101  return str(self) == str(other)
102  else:
103  return False
104 
105  def __ne__(self, other) -> bool:
106  res = self.__eq__(other)
107  return not res
108 
109 
110 class BasicType:
111  """
112  Basic types are the fundamental built-in types in C++ such as double, int, char, etc.
113 
114  When using templates, the basis type will take on the same form as the template.
115 
116  E.g.
117  ```
118  template<T = {double}>
119  void func(const T& x);
120  ```
121 
122  will give
123 
124  ```
125  m_.def("CoolFunctionDoubleDouble",[](const double& s) {
126  return wrap_example::CoolFunction<double,double>(s);
127  }, py::arg("s"));
128  ```
129  """
130 
131  rule = (Or(BASIS_TYPES)("typename")).setParseAction(lambda t: BasicType(t))
132 
133  def __init__(self, t: ParseResults):
134  self.typename = Typename(t.asList())
135 
136 
138  """
139  Custom defined types with the namespace.
140  Essentially any C++ data type that is not a BasicType.
141 
142  E.g.
143  ```
144  gtsam::Matrix wTc;
145  ```
146 
147  Here `gtsam::Matrix` is a custom type.
148  """
149 
150  rule = (Typename.rule("typename")).setParseAction(lambda t: CustomType(t))
151 
152  def __init__(self, t: ParseResults):
153  self.typename = Typename(t)
154 
155 
156 class Type:
157  """
158  Parsed datatype, can be either a fundamental type or a custom datatype.
159  E.g. void, double, size_t, Matrix.
160 
161  The type can optionally be a raw pointer, shared pointer or reference.
162  Can also be optionally qualified with a `const`, e.g. `const int`.
163  """
164  rule = (
165  Optional(CONST("is_const")) #
166  + (BasicType.rule("basis") | CustomType.rule("qualified")) # BR
167  + Optional(
168  SHARED_POINTER("is_shared_ptr") | RAW_POINTER("is_ptr")
169  | REF("is_ref")) #
170  ).setParseAction(lambda t: Type.from_parse_result(t))
171 
172  def __init__(self, typename: Typename, is_const: str, is_shared_ptr: str,
173  is_ptr: str, is_ref: str, is_basic: bool):
174  self.typename = typename
175  self.is_const = is_const
176  self.is_shared_ptr = is_shared_ptr
177  self.is_ptr = is_ptr
178  self.is_ref = is_ref
179  self.is_basic = is_basic
180 
181  @staticmethod
182  def from_parse_result(t: ParseResults):
183  """Return the resulting Type from parsing the source."""
184  if t.basis:
185  return Type(
186  typename=t.basis.typename,
187  is_const=t.is_const,
188  is_shared_ptr=t.is_shared_ptr,
189  is_ptr=t.is_ptr,
190  is_ref=t.is_ref,
191  is_basic=True,
192  )
193  elif t.qualified:
194  return Type(
195  typename=t.qualified.typename,
196  is_const=t.is_const,
197  is_shared_ptr=t.is_shared_ptr,
198  is_ptr=t.is_ptr,
199  is_ref=t.is_ref,
200  is_basic=False,
201  )
202  else:
203  raise ValueError("Parse result is not a Type")
204 
205  def __repr__(self) -> str:
206  is_ptr_or_ref = "{0}{1}{2}".format(self.is_shared_ptr, self.is_ptr,
207  self.is_ref)
208  return "{is_const}{self.typename}{is_ptr_or_ref}".format(
209  self=self,
210  is_const="const " if self.is_const else "",
211  is_ptr_or_ref=" " + is_ptr_or_ref if is_ptr_or_ref else "")
212 
213  def to_cpp(self, use_boost: bool) -> str:
214  """
215  Generate the C++ code for wrapping.
216 
217  Treat all pointers as "const shared_ptr<T>&"
218  Treat Matrix and Vector as "const Matrix&" and "const Vector&" resp.
219 
220  Args:
221  use_boost: Flag indicating whether to use boost::shared_ptr or std::shared_ptr.
222  """
223  shared_ptr_ns = "boost" if use_boost else "std"
224 
225  if self.is_shared_ptr:
226  typename = "{ns}::shared_ptr<{typename}>".format(
227  ns=shared_ptr_ns, typename=self.typename.to_cpp())
228  elif self.is_ptr:
229  typename = "{typename}*".format(typename=self.typename.to_cpp())
230  elif self.is_ref or self.typename.name in ["Matrix", "Vector"]:
231  typename = typename = "{typename}&".format(
232  typename=self.typename.to_cpp())
233  else:
234  typename = self.typename.to_cpp()
235 
236  return ("{const}{typename}".format(
237  const="const " if
238  (self.is_const
239  or self.typename.name in ["Matrix", "Vector"]) else "",
240  typename=typename))
241 
242 
244  """
245  Parser rule for data types which are templated.
246  This is done so that the template parameters can be pointers/references.
247 
248  E.g. std::vector<double>, BearingRange<Pose3, Point3>
249  """
250 
251  rule = Forward()
252  rule << (
253  Optional(CONST("is_const")) #
254  + Typename.rule("typename") #
255  + (
256  LOPBRACK #
257  + delimitedList(Type.rule ^ rule, ",")("template_params") #
258  + ROPBRACK) #
259  + Optional(
260  SHARED_POINTER("is_shared_ptr") | RAW_POINTER("is_ptr")
261  | REF("is_ref")) #
262  ).setParseAction(lambda t: TemplatedType.from_parse_result(t))
263 
264  def __init__(self, typename: Typename, template_params: List[Type],
265  is_const: str, is_shared_ptr: str, is_ptr: str, is_ref: str):
266  instantiations = [param.typename for param in template_params]
267  # Recreate the typename but with the template params as instantiations.
268  self.typename = Typename(typename.namespaces + [typename.name],
269  instantiations)
270 
271  self.template_params = template_params
272 
273  self.is_const = is_const
274  self.is_shared_ptr = is_shared_ptr
275  self.is_ptr = is_ptr
276  self.is_ref = is_ref
277 
278  @staticmethod
279  def from_parse_result(t: ParseResults):
280  """Get the TemplatedType from the parser results."""
281  return TemplatedType(t.typename, t.template_params, t.is_const,
282  t.is_shared_ptr, t.is_ptr, t.is_ref)
283 
284  def __repr__(self):
285  return "TemplatedType({typename.namespaces}::{typename.name})".format(
286  typename=self.typename)
287 
288  def to_cpp(self, use_boost: bool):
289  """
290  Generate the C++ code for wrapping.
291 
292  Args:
293  use_boost: Flag indicating whether to use boost::shared_ptr or std::shared_ptr.
294  """
295  # Use Type.to_cpp to do the heavy lifting for the template parameters.
296  template_args = ", ".join(
297  [t.to_cpp(use_boost) for t in self.template_params])
298 
299  typename = "{typename}<{template_args}>".format(
300  typename=self.typename.qualified_name(),
301  template_args=template_args)
302 
303  shared_ptr_ns = "boost" if use_boost else "std"
304  if self.is_shared_ptr:
305  typename = "{ns}::shared_ptr<{typename}>".format(ns=shared_ptr_ns,
306  typename=typename)
307  elif self.is_ptr:
308  typename = "{typename}*".format(typename=typename)
309  elif self.is_ref or self.typename.name in ["Matrix", "Vector"]:
310  typename = typename = "{typename}&".format(typename=typename)
311  else:
312  pass
313 
314  return ("{const}{typename}".format(
315  const="const " if
316  (self.is_const
317  or self.typename.name in ["Matrix", "Vector"]) else "",
318  typename=typename))
bool isinstance(handle obj)
Definition: pytypes.h:384
Definition: pytypes.h:928


gtsam
Author(s):
autogenerated on Sat May 8 2021 02:51:19