Add general support for templated classes (previously only classes with non-templated typedefs were allowed).
This commit is contained in:
1 parent
68cb0dc934
commit
bbfbe4702e
2 files changed
+91
-28
No files matched your search
+33
-7
@@ -33,7 +33,7 @@ class CppHelperClass(object):
|
||||
class_ -- original CppClass wrapper object
|
||||
"""
|
||||
self.class_ = class_
|
||||
self.name = class_.name + "_PythonProxy"
|
||||
self.name = class_.pystruct + "__PythonHelper"
|
||||
self.virtual_parent_callers = {}
|
||||
self.virtual_proxies = []
|
||||
self.cannot_be_constructed = False
|
||||
@@ -95,7 +95,7 @@ class CppHelperClass(object):
|
||||
code_sink.writeln("%s(%s)" % (self.name, ', '.join(params)))
|
||||
code_sink.indent()
|
||||
code_sink.writeln(": %s(%s), m_pyself(NULL)\n{}" %
|
||||
(self.class_.name,
|
||||
(self.class_.full_name,
|
||||
', '.join([param.name for param in cons.parameters])))
|
||||
code_sink.unindent()
|
||||
code_sink.writeln()
|
||||
@@ -261,7 +261,8 @@ class CppClass(object):
|
||||
def __init__(self, name, parent=None, incref_method=None, decref_method=None,
|
||||
automatic_type_narrowing=None, allow_subclassing=None,
|
||||
is_singleton=False, outer_class=None,
|
||||
peekref_method=None):
|
||||
peekref_method=None,
|
||||
template_parameters=(), custom_template_class_name=None):
|
||||
"""Constructor
|
||||
name -- class name
|
||||
parent -- optional parent class wrapper
|
||||
@@ -290,8 +291,10 @@ class CppClass(object):
|
||||
self.outer_class = outer_class
|
||||
self._module = None
|
||||
self.name = name
|
||||
self.template_parameters = template_parameters
|
||||
self.custom_template_class_name = custom_template_class_name
|
||||
self.is_singleton = is_singleton
|
||||
self.full_name = None # full name with C++ namespaces attached
|
||||
self.full_name = None # full name with C++ namespaces attached and template parameters
|
||||
self.methods = {} # name => OverloadedMethod
|
||||
self.constructors = [] # (name, wrapper) pairs
|
||||
self.slots = dict()
|
||||
@@ -478,7 +481,21 @@ class CppClass(object):
|
||||
else:
|
||||
return s
|
||||
|
||||
flat_name = ''.join([make_upper(s) for s in self.full_name.split('::')])
|
||||
def mangle(s):
|
||||
"make a name Like<This,and,That> look Like__lt__This_and_That__gt__"
|
||||
s = s.replace('<', '__lt__').replace('>', '__gt__').replace(',', '_')
|
||||
s = s.replace(' ', '_').replace('&', '__amp__').replace('*', '__star__')
|
||||
return s
|
||||
|
||||
def flatten(name):
|
||||
"make a name like::This look LikeThis"
|
||||
return ''.join([make_upper(mangle(s)) for s in name.split('::')])
|
||||
|
||||
flat_name = flatten(self.full_name)
|
||||
|
||||
if self.template_parameters:
|
||||
self.full_name += "< %s >" % (', '.join(self.template_parameters))
|
||||
flat_name += '__' + '_'.join([flatten(s) for s in self.template_parameters])
|
||||
|
||||
self._pystruct = "Py%s%s" % (prefix, flat_name)
|
||||
self.metaclass_name = "%sMeta" % flat_name
|
||||
@@ -818,14 +835,23 @@ typedef struct {
|
||||
|
||||
module.after_init.write_error_check('PyType_Ready(&%s)'
|
||||
% (self.pytypestruct,))
|
||||
|
||||
if self.template_parameters:
|
||||
if self.custom_template_class_name is None:
|
||||
class_python_name = utils.get_mangled_name(self.name, self.template_parameters)
|
||||
else:
|
||||
class_python_name = self.custom_template_class_name
|
||||
else:
|
||||
class_python_name = self.name
|
||||
|
||||
if self.outer_class is None:
|
||||
module.after_init.write_code(
|
||||
'PyModule_AddObject(m, \"%s\", (PyObject *) &%s);' % (
|
||||
self.name, self.pytypestruct))
|
||||
class_python_name, self.pytypestruct))
|
||||
else:
|
||||
module.after_init.write_code(
|
||||
'PyDict_SetItemString((PyObject*) %s.tp_dict, \"%s\", (PyObject *) &%s);' % (
|
||||
self.outer_class.pytypestruct, self.name, self.pytypestruct))
|
||||
self.outer_class.pytypestruct, class_python_name, self.pytypestruct))
|
||||
|
||||
have_constructor = self._generate_constructor(code_sink)
|
||||
|
||||
|
||||
+58
-21
@@ -49,6 +49,21 @@ class ErrorHandler(settings.ErrorHandler):
|
||||
return True
|
||||
settings.error_handler = ErrorHandler()
|
||||
|
||||
_digits = re.compile(r"\s*\d+\s*")
|
||||
def normalize_name(decl_string):
|
||||
if templates.is_instantiation(decl_string):
|
||||
cls_name, template_parameters = templates.split(decl_string)
|
||||
else:
|
||||
cls_name = decl_string
|
||||
template_parameters = None
|
||||
if not _digits.match(cls_name):
|
||||
if not cls_name.startswith('::'):
|
||||
cls_name = '::' + cls_name
|
||||
if template_parameters is None:
|
||||
return cls_name
|
||||
else:
|
||||
return "%s< %s >" % (cls_name, ', '.join([normalize_name(name) for name in template_parameters]))
|
||||
|
||||
|
||||
class GccXmlTypeRegistry(object):
|
||||
def __init__(self):
|
||||
@@ -57,19 +72,23 @@ class GccXmlTypeRegistry(object):
|
||||
|
||||
def register_class(self, cpp_class, alias=None):
|
||||
assert isinstance(cpp_class, CppClass)
|
||||
if cpp_class.full_name.startswith('::'):
|
||||
full_name = cpp_class.full_name
|
||||
else:
|
||||
full_name = '::' + cpp_class.full_name
|
||||
full_name = normalize_name(cpp_class.full_name)
|
||||
#print >> sys.stderr, "******** registering class %s as %s" \
|
||||
# % (cpp_class.gccxml_definition, full_name)
|
||||
self.classes[full_name] = cpp_class
|
||||
if alias is not None:
|
||||
alias = normalize_name(alias)
|
||||
self.classes[alias] = cpp_class
|
||||
#print >> sys.stderr, "******** registering class %s also as alias %s" \
|
||||
# % (cpp_class.gccxml_definition, alias)
|
||||
|
||||
def find_class(self, class_name, module_namespace):
|
||||
if not class_name.startswith(module_namespace):
|
||||
class_name = module_namespace + class_name
|
||||
if not class_name.startswith('::'):
|
||||
class_name = '::' + class_name
|
||||
class_name = normalize_name(class_name)
|
||||
#if '<' in class_name:
|
||||
# print >> sys.stderr, "******** looking for class %s" \
|
||||
# % (class_name)
|
||||
return self.classes[class_name]
|
||||
|
||||
def get_class_type_traits(self, type_info):
|
||||
@@ -83,8 +102,12 @@ class GccXmlTypeRegistry(object):
|
||||
is_pointer = False
|
||||
pointer_is_const = False
|
||||
if isinstance(base_type, cpptypes.declarated_t):
|
||||
class_name = normalize_name(base_type.decl_string)
|
||||
#if '<' in class_name:
|
||||
# print >> sys.stderr, "******** looking for class %s" \
|
||||
# % (class_name)
|
||||
try:
|
||||
cpp_class = self.classes[base_type.decl_string]
|
||||
cpp_class = self.classes[class_name]
|
||||
except KeyError:
|
||||
return (None, is_const, is_pointer, is_reference, pointer_is_const)
|
||||
|
||||
@@ -427,10 +450,7 @@ class ModuleParser(object):
|
||||
if typedef_type == cls:
|
||||
break
|
||||
else:
|
||||
warnings.warn_explicit("Class %s ignored because it is templated; templates not yet supported"
|
||||
% cls.decl_string,
|
||||
Warning, cls.location.file_name, cls.location.line)
|
||||
continue
|
||||
typedef = None
|
||||
|
||||
if len(cls.bases) > 1:
|
||||
warnings.warn_explicit(("Class %s ignored because it uses multiple "
|
||||
@@ -494,19 +514,42 @@ class ModuleParser(object):
|
||||
if not self._class_has_public_destructor(cls):
|
||||
kwargs.setdefault('is_singleton', True)
|
||||
|
||||
custom_template_class_name = None
|
||||
template_parameters = ()
|
||||
if typedef is None:
|
||||
name = cls.name
|
||||
alias = None
|
||||
if templates.is_instantiation(cls.decl_string):
|
||||
cls_name, template_parameters = templates.split(cls.name)
|
||||
assert template_parameters
|
||||
a1 = 1
|
||||
if '::' in cls_name:
|
||||
cls_name = cls_name.split('::')[-1]
|
||||
template_instance_names = global_annotations.get('template_instance_names', '')
|
||||
if template_instance_names:
|
||||
for mapping in template_instance_names.split('|'):
|
||||
type_names, name = mapping.split('=>')
|
||||
instance_types = type_names.split(',')
|
||||
if instance_types == template_parameters:
|
||||
custom_template_class_name = name
|
||||
break
|
||||
else:
|
||||
a2 = 1
|
||||
cls_name = cls.name
|
||||
else:
|
||||
name = typedef.name
|
||||
cls_name = typedef.name
|
||||
alias = '::'.join([module.cpp_namespace_prefix, cls.name])
|
||||
#print >> sys.stderr, "******** registering class %s" % cls
|
||||
class_wrapper = CppClass(name, parent=base_class_wrapper, outer_class=outer_class, **kwargs)
|
||||
|
||||
class_wrapper = CppClass(cls_name, parent=base_class_wrapper, outer_class=outer_class,
|
||||
template_parameters=template_parameters,
|
||||
custom_template_class_name=custom_template_class_name,
|
||||
**kwargs)
|
||||
class_wrapper.gccxml_definition = cls
|
||||
module.add_class(class_wrapper)
|
||||
registered_classes[cls] = class_wrapper
|
||||
type_registry.register_class(class_wrapper, alias)
|
||||
|
||||
del cls_name
|
||||
|
||||
## scan for nested classes/enums
|
||||
self._scan_namespace_types(module, module_namespace, outer_class=class_wrapper)
|
||||
|
||||
@@ -514,12 +557,6 @@ class ModuleParser(object):
|
||||
other_class = type_registry.find_class(operator.return_type.decl_string, '::')
|
||||
class_wrapper.implicitly_converts_to(other_class)
|
||||
|
||||
assert typedef is not None or \
|
||||
(cls.decl_string in type_registry.classes\
|
||||
and type_registry.classes[cls.decl_string] == class_wrapper)
|
||||
|
||||
|
||||
|
||||
for cls, class_wrapper in registered_classes.iteritems():
|
||||
self._scan_methods(cls, class_wrapper)
|
||||
|
||||
|
||||
Reference in new issue
Block a user