417a418
> 'cxx_template_params' : list,
456a458,459
> if 'cxx_template_params' not in value_dict:
> value_dict['cxx_template_params'] = []
775a779
> _warned_about_nested_templates = False
793c797,832
< class_path = cls._value_dict['cxx_class'].split('::')
---
> class CxxClass(object):
> def __init__(self, sig, template_params=[]):
> # Split the signature into its constituent parts. This could
> # potentially be done with regular expressions, but
> # it's simple enough to pick appart a class signature
> # manually.
> parts = sig.split('<', 1)
> base = parts[0]
> t_args = []
> if len(parts) > 1:
> # The signature had template arguments.
> text = parts[1].rstrip(' \t\n>')
> arg = ''
> # Keep track of nesting to avoid splitting on ","s embedded
> # in the arguments themselves.
> depth = 0
> for c in text:
> if c == '<':
> depth = depth + 1
> if depth > 0 and not \
> self._warned_about_nested_templates:
> self._warned_about_nested_templates = True
> print('Nested template argument in cxx_class.'
> ' This feature is largely untested and '
> ' may not work.')
> elif c == '>':
> depth = depth - 1
> elif c == ',' and depth == 0:
> t_args.append(arg.strip())
> arg = ''
> else:
> arg = arg + c
> if arg:
> t_args.append(arg.strip())
> # Split the non-template part on :: boundaries.
> class_path = base.split('::')
794a834,869
> # The namespaces are everything except the last part of the
> # class path.
> self.namespaces = class_path[:-1]
> # And the class name is the last part.
> self.name = class_path[-1]
>
> self.template_params = template_params
> self.template_arguments = []
> # Iterate through the template arguments and their values. This
> # will likely break if parameter packs are used.
> for arg, param in zip(t_args, template_params):
> type_keys = ('class', 'typename')
> # If a parameter is a type, parse it recursively. Otherwise
> # assume it's a constant, and store it verbatim.
> if any(param.strip().startswith(kw) for kw in type_keys):
> self.template_arguments.append(CxxClass(arg))
> else:
> self.template_arguments.append(arg)
>
> def declare(self, code):
> # First declare any template argument types.
> for arg in self.template_arguments:
> if isinstance(arg, CxxClass):
> arg.declare(code)
> # Re-open the target namespace.
> for ns in self.namespaces:
> code('namespace $ns {')
> # If this is a class template...
> if self.template_params:
> code('template <${{", ".join(self.template_params)}}>')
> # The actual class declaration.
> code('class ${{self.name}};')
> # Close the target namespaces.
> for ns in reversed(self.namespaces):
> code('} // namespace $ns')
>
808a884,886
> cxx_class = CxxClass(cls._value_dict['cxx_class'],
> cls._value_dict['cxx_template_params'])
>
811,816c889
< for ns in class_path[:-1]:
< code('namespace $ns {')
< code('class $0;', class_path[-1])
< for ns in reversed(class_path[:-1]):
< code('} // namespace $ns')
< code()
---
> cxx_class.declare(code)