helpers.py
Go to the documentation of this file.
1 """Various helpers for instantiation."""
2 
3 import itertools
4 from copy import deepcopy
5 from typing import List, Sequence, Union
6 
7 import gtwrap.interface_parser as parser
8 
9 ClassMembers = Union[parser.Constructor, parser.Method, parser.StaticMethod,
10  parser.GlobalFunction, parser.Operator, parser.Variable,
11  parser.Enum]
12 InstantiatedMembers = Union['InstantiatedConstructor', 'InstantiatedMethod',
13  'InstantiatedStaticMethod',
14  'InstantiatedGlobalFunction']
15 
16 
17 def is_scoped_template(template_typenames: Sequence[str],
18  str_arg_typename: str):
19  """
20  Check if the template given by `str_arg_typename` is a scoped template e.g. T::Value,
21  and if so, return what template from `template_typenames` and
22  the corresponding index matches the scoped template correctly.
23  """
24  for idx, template in enumerate(template_typenames):
25  if "::" in str_arg_typename and \
26  template in str_arg_typename.split("::"):
27  return template, idx
28  return False, -1
29 
30 
32  ctype: parser.Type,
33  template_typenames: Sequence[str],
34  instantiations: Sequence[parser.Typename],
35  cpp_typename: parser.Typename,
36  instantiated_class: 'InstantiatedClass' = None) -> parser.Type:
37  """
38  Instantiate template typename for `ctype`.
39 
40  Args:
41  ctype: The original argument type.
42  template_typenames: List of strings representing the templates.
43  instantiations: List of the instantiations of the templates in `template_typenames`.
44  cpp_typename: Full-namespace cpp class name of this instantiation
45  to replace for arguments of type named `This`.
46  instiated_class: The instantiated class which, if provided,
47  will be used for instantiating `This`.
48 
49  Returns:
50  If `ctype`'s name is in the `template_typenames`, return the
51  corresponding type to replace in `instantiations`.
52  If ctype name is `This`, return the new typename `cpp_typename`.
53  Otherwise, return the original ctype.
54  """
55  # make a deep copy so that there is no overwriting of original template params
56  ctype = deepcopy(ctype)
57 
58  # Check if the return type has template parameters as the typename's name
59  if ctype.typename.instantiations:
60  for idx, instantiation in enumerate(ctype.typename.instantiations):
61  if instantiation.name in template_typenames:
62  template_idx = template_typenames.index(instantiation.name)
63  ctype.typename.instantiations[idx].name =\
64  instantiations[template_idx]
65 
66 
67  str_arg_typename = str(ctype.typename)
68 
69  # Check if template is a scoped template e.g. T::Value where T is the template
70  scoped_template, scoped_idx = is_scoped_template(template_typenames,
71  str_arg_typename)
72 
73  # Instantiate templates which have enumerated instantiations in the template.
74  # E.g. `template<T={double}>`.
75 
76  # Instantiate scoped templates, e.g. T::Value.
77  if scoped_template:
78  # Create a copy of the instantiation so we can modify it.
79  instantiation = deepcopy(instantiations[scoped_idx])
80  # Replace the part of the template with the instantiation
81  instantiation.name = str_arg_typename.replace(scoped_template,
82  instantiation.name)
83  return parser.Type(
84  typename=instantiation,
85  is_const=ctype.is_const,
86  is_shared_ptr=ctype.is_shared_ptr,
87  is_ptr=ctype.is_ptr,
88  is_ref=ctype.is_ref,
89  is_basic=ctype.is_basic,
90  )
91  # Check for exact template match.
92  elif str_arg_typename in template_typenames:
93  idx = template_typenames.index(str_arg_typename)
94  return parser.Type(
95  typename=instantiations[idx],
96  is_const=ctype.is_const,
97  is_shared_ptr=ctype.is_shared_ptr,
98  is_ptr=ctype.is_ptr,
99  is_ref=ctype.is_ref,
100  is_basic=ctype.is_basic,
101  )
102 
103  # If a method has the keyword `This`, we replace it with the (instantiated) class.
104  elif str_arg_typename == 'This':
105  # Check if the class is template instantiated
106  # so we can replace it with the instantiated version.
107  if instantiated_class:
108  name = instantiated_class.original.name
109  namespaces_name = instantiated_class.namespaces()
110  namespaces_name.append(name)
111  cpp_typename = parser.Typename(
112  namespaces_name,
113  instantiations=instantiated_class.instantiations)
114 
115  return parser.Type(
116  typename=cpp_typename,
117  is_const=ctype.is_const,
118  is_shared_ptr=ctype.is_shared_ptr,
119  is_ptr=ctype.is_ptr,
120  is_ref=ctype.is_ref,
121  is_basic=ctype.is_basic,
122  )
123 
124  # Case when 'This' is present in the type namespace, e.g `This::Subclass`.
125  elif 'This' in str_arg_typename:
126  # Check if `This` is in the namespaces
127  if 'This' in ctype.typename.namespaces:
128  # Simply get the index of `This` in the namespace and
129  # replace it with the instantiated name.
130  namespace_idx = ctype.typename.namespaces.index('This')
131  ctype.typename.namespaces[namespace_idx] = cpp_typename.name
132  # Else check if it is in the template namespace, e.g vector<This::Value>
133  else:
134  for idx, instantiation in enumerate(ctype.typename.instantiations):
135  if 'This' in instantiation.namespaces:
136  ctype.typename.instantiations[idx].namespaces = \
137  cpp_typename.namespaces + [cpp_typename.name]
138  return ctype
139 
140  else:
141  return ctype
142 
143 
145  args_list: Sequence[parser.Argument],
146  template_typenames: Sequence[parser.template.Typename],
147  instantiations: Sequence, cpp_typename: parser.Typename):
148  """
149  Instantiate template typenames in an argument list.
150  Type with name `This` will be replaced by @p `cpp_typename`.
151 
152  @param[in] args_list A list of `parser.Argument` to instantiate.
153  @param[in] template_typenames List of template typenames to instantiate,
154  e.g. ['T', 'U', 'V'].
155  @param[in] instantiations List of specific types to instantiate, each
156  associated with each template typename. Each type is a parser.Typename,
157  including its name and full namespaces.
158  @param[in] cpp_typename Full-namespace cpp class name of this instantiation
159  to replace for arguments of type named `This`.
160  @return A new list of parser.Argument which types are replaced with their
161  instantiations.
162  """
163  instantiated_args = []
164  for arg in args_list:
165  new_type = instantiate_type(arg.ctype, template_typenames,
166  instantiations, cpp_typename)
167  instantiated_args.append(
168  parser.Argument(name=arg.name, ctype=new_type,
169  default=arg.default))
170  return instantiated_args
171 
172 
173 def instantiate_return_type(
174  return_type: parser.ReturnType,
175  template_typenames: Sequence[parser.template.Typename],
176  instantiations: Sequence[parser.Typename],
177  cpp_typename: parser.Typename,
178  instantiated_class: 'InstantiatedClass' = None):
179  """Instantiate the return type."""
180  new_type1 = instantiate_type(return_type.type1,
181  template_typenames,
182  instantiations,
183  cpp_typename,
184  instantiated_class=instantiated_class)
185  if return_type.type2:
186  new_type2 = instantiate_type(return_type.type2,
187  template_typenames,
188  instantiations,
189  cpp_typename,
190  instantiated_class=instantiated_class)
191  else:
192  new_type2 = ''
193  return parser.ReturnType(new_type1, new_type2)
194 
195 
196 def instantiate_name(original_name: str,
197  instantiations: Sequence[parser.Typename]):
198  """
199  Concatenate instantiated types with `original_name` to form a new
200  instantiated name.
201 
202  NOTE: To avoid conflicts, we should include the instantiation's
203  namespaces, but that is too verbose.
204  """
205  instantiated_names = []
206  for inst in instantiations:
207  # Ensure the first character of the type is capitalized
208  name = inst.instantiated_name()
209  # Using `capitalize` on the complete name causes other caps to be lower case
210  instantiated_names.append(name.replace(name[0], name[0].capitalize()))
211 
212  return "{}{}".format(original_name, "".join(instantiated_names))
213 
214 
215 class InstantiationHelper:
216  """
217  Helper class for instantiation templates.
218  Requires that `instantiation_type` defines a class method called
219  `construct` to generate the appropriate object type.
220 
221  Signature for `construct` should be
222  ```
223  construct(method,
224  typenames,
225  class_instantiations,
226  method_instantiations,
227  instantiated_args,
228  parent=parent)
229  ```
230  """
231  def __init__(self, instantiation_type: InstantiatedMembers):
232  self.instantiation_type = instantiation_type
233 
234  def instantiate(self, instantiated_methods: List[InstantiatedMembers],
235  method: ClassMembers, typenames: Sequence[str],
236  class_instantiations: Sequence[parser.Typename],
237  method_instantiations: Sequence[parser.Typename],
238  parent: 'InstantiatedClass'):
239  """
240  Instantiate both the class and method level templates.
241  """
242  instantiations = class_instantiations + method_instantiations
243 
244  instantiated_args = instantiate_args_list(method.args.list(),
245  typenames, instantiations,
246  parent.cpp_typename())
247 
248  instantiated_methods.append(
249  self.instantiation_type.construct(method,
250  typenames,
251  class_instantiations,
252  method_instantiations,
253  instantiated_args,
254  parent=parent))
255 
256  return instantiated_methods
257 
258  def multilevel_instantiation(self, methods_list: Sequence[ClassMembers],
259  typenames: Sequence[str],
260  parent: 'InstantiatedClass'):
261  """
262  Helper to instantiate methods at both the class and method level.
263 
264  Args:
265  methods_list: The list of methods in the class to instantiated.
266  typenames: List of class level template parameters, e.g. ['T'].
267  parent: The instantiated class to which `methods_list` belongs.
268  """
269  instantiated_methods = []
270 
271  for method in methods_list:
272  # We creare a copy since we will modify the typenames list.
273  method_typenames = deepcopy(typenames)
274 
275  if isinstance(method.template, parser.template.Template):
276  method_typenames.extend(method.template.typenames)
277 
278  # Get all combinations of template args
279  for instantiations in itertools.product(
280  *method.template.instantiations):
281 
282  instantiated_methods = self.instantiate(
283  instantiated_methods,
284  method,
285  typenames=method_typenames,
286  class_instantiations=parent.instantiations,
287  method_instantiations=list(instantiations),
288  parent=parent)
289 
290  else:
291  # If no constructor level templates, just use the class templates
292  instantiated_methods = self.instantiate(
293  instantiated_methods,
294  method,
295  typenames=method_typenames,
296  class_instantiations=parent.instantiations,
297  method_instantiations=[],
298  parent=parent)
299 
300  return instantiated_methods
Definition: pytypes.h:1403


gtsam
Author(s):
autogenerated on Tue Jul 4 2023 02:34:19