blob: b23cbaa1eecc8e901a91afd3133f2202b29c566b [file] [log] [blame]
from pybindgen.typehandlers.base import Parameter, ReturnValue, \
join_ctype_and_name, CodeGenerationError, \
param_type_matcher, return_type_matcher, CodegenErrorBase, \
DeclarationsScope, CodeBlock, NotSupportedError, ForwardWrapperBase, ReverseWrapperBase, \
TypeConfigurationError
from pybindgen.cppclass import ReferenceCountingMethodsPolicy, CppClass, CppClassParameterBase, CppClassReturnValueBase, common_shared_object_return
class Ns3PtrMemoryPolicy(ReferenceCountingMethodsPolicy):
def __init__(self, class_name):
"""
Create a memory policy for using ns3::Ptr<> to manage instances of this object.
:param class_name: the full name of the class, e.g. foo::Bar
"""
super(Ns3PtrMemoryPolicy, self).__init__('Ref', 'Unref', 'GetReferenceCount')
self.class_name = class_name
self.pointer_template = 'ns3::Ptr< %s >'
def get_pointer_name(self, class_name):
return self.pointer_template % (class_name,)
def get_delete_code(self, cpp_class):
return "self->obj.~Ptr< %s >();" % (cpp_class.full_name,)
def get_pointer_type(self, class_full_name):
return self.get_pointer_name(class_full_name) + ' '
def get_pointer_to_void_name(self, object_name):
return "::ns3::PeekPointer(%s)" % object_name
def get_instance_creation_function(self):
return ns3_ptr_instance_creation_function
def get_pystruct_init_code(self, cpp_class, obj):
return "new(&%s->obj) %s;" % (obj, self.get_pointer_name(cpp_class.full_name),)
def register_ptr_parameter_and_return(self, cls, name):
class ThisClassNs3PtrParameter(CppClassNs3PtrParameter):
"""Register this C++ class as pass-by-pointer parameter"""
CTYPES = []
cpp_class = cls
cls.ThisClassNs3PtrParameter = ThisClassNs3PtrParameter
try:
param_type_matcher.register(self.get_pointer_name(cls.full_name), cls.ThisClassNs3PtrParameter)
except ValueError:
pass
class ThisClassNs3PtrReturn(CppClassNs3PtrReturnValue):
"""Register this C++ class as pointer return"""
CTYPES = []
cpp_class = cls
cls.ThisClassNs3PtrReturn = ThisClassNs3PtrReturn
try:
return_type_matcher.register(self.get_pointer_name(cls.full_name), cls.ThisClassNs3PtrReturn)
except ValueError:
pass
def register_ptr_alias_parameter_and_return(self, cls, alias):
alias_ptr = '::ns3::Ptr< %s >' % alias
cls.ThisClassNs3PtrParameter.CTYPES.append(alias_ptr)
try:
param_type_matcher.register(alias_ptr, cls.ThisClassNs3PtrParameter)
except ValueError: pass
cls.ThisClassNs3PtrReturn.CTYPES.append(alias_ptr)
try:
return_type_matcher.register(alias_ptr, cls.ThisClassNs3PtrReturn)
except ValueError: pass
def ns3_ptr_instance_creation_function(cpp_class, code_block, lvalue,
parameters, construct_type_name):
"""
ns3::Ptr "instance creation function"; it is called whenever a new
C++ class instance needs to be created
:param cpp_class: the CppClass object whose instance is to be created
:param code_block: CodeBlock object on which the instance creation code should be generated
:param lvalue: lvalue expression that should hold the result in the end
:param parameters: stringified list of parameters
:param construct_type_name: actual name of type to be constructed (it is
not always the class name, sometimes it's
the python helper class)
"""
assert lvalue
assert not lvalue.startswith('None')
if cpp_class.incomplete_type:
raise CodeGenerationError("%s cannot be constructed (incomplete type)"
% cpp_class.full_name)
code_block.write_code(
"%s = ::ns3::Create<%s>(%s);" % (lvalue, construct_type_name, parameters))
class CppClassNs3PtrParameter(CppClassParameterBase):
"Class* handlers"
CTYPES = []
cpp_class = None #cppclass.CppClass('dummy') # CppClass instance
DIRECTIONS = [Parameter.DIRECTION_IN,
Parameter.DIRECTION_OUT,
Parameter.DIRECTION_INOUT]
SUPPORTS_TRANSFORMATIONS = False
def __init__(self, ctype, name, direction=Parameter.DIRECTION_IN, is_const=False,
null_ok=False, default_value=None):
super(CppClassNs3PtrParameter, self).__init__(
ctype, name, direction, is_const, default_value)
self.null_ok = null_ok
def convert_python_to_c(self, wrapper):
"parses python args to get C++ value"
assert isinstance(wrapper, ForwardWrapperBase)
assert isinstance(self.cpp_class, CppClass)
self.py_name = wrapper.declarations.declare_variable(
self.cpp_class.pystruct+'*', self.name,
initializer=(self.default_value and 'NULL' or None))
value_ptr = wrapper.declarations.declare_variable(
self.cpp_class.memory_policy.get_pointer_name(self.cpp_class.full_name), "%s_ptr" % self.name)
if self.null_ok:
num = wrapper.parse_params.add_parameter('O', ['&'+self.py_name], self.name, optional=bool(self.default_value))
wrapper.before_call.write_error_check(
"%s && ((PyObject *) %s != Py_None) && !PyObject_IsInstance((PyObject *) %s, (PyObject *) &%s)"
% (self.py_name, self.py_name, self.py_name, self.cpp_class.pytypestruct),
'PyErr_SetString(PyExc_TypeError, "Parameter %i must be of type %s");' % (num, self.cpp_class.name))
wrapper.before_call.write_code("if (%(PYNAME)s) {\n"
" if ((PyObject *) %(PYNAME)s == Py_None)\n"
" %(VALUE)s = NULL;\n"
" else\n"
" %(VALUE)s = %(PYNAME)s->obj;\n"
"} else {\n"
" %(VALUE)s = NULL;\n"
"}" % dict(PYNAME=self.py_name, VALUE=value_ptr))
else:
wrapper.parse_params.add_parameter(
'O!', ['&'+self.cpp_class.pytypestruct, '&'+self.py_name], self.name, optional=bool(self.default_value))
wrapper.before_call.write_code("if (%s) { %s = %s->obj; }" % (self.py_name, value_ptr, self.py_name))
wrapper.call_params.append(value_ptr)
def convert_c_to_python(self, wrapper):
"""foo"""
## Value transformations
value = self.transformation.untransform(
self, wrapper.declarations, wrapper.after_call, self.value)
## declare wrapper variable
py_name = wrapper.declarations.declare_variable(
self.cpp_class.pystruct+'*', 'py_'+self.cpp_class.name)
self.py_name = py_name
def write_create_new_wrapper():
"""Code path that creates a new wrapper for the parameter"""
## Find out what Python wrapper to use, in case
## automatic_type_narrowing is active and we are not forced to
## make a copy of the object
if self.cpp_class.automatic_type_narrowing:
typeid_map_name = self.cpp_class.get_type_narrowing_root().typeid_map_name
wrapper_type = wrapper.declarations.declare_variable(
'PyTypeObject*', 'wrapper_type', '0')
wrapper.before_call.write_code(
'%s = %s.lookup_wrapper(typeid(*%s), &%s);'
% (wrapper_type, typeid_map_name, value, self.cpp_class.memory_policy.get_pointer_to_void_name(self.cpp_class.pytypestruct)))
else:
wrapper_type = '&'+self.cpp_class.pytypestruct
## Create the Python wrapper object
self.cpp_class.write_allocate_pystruct(wrapper.before_call, py_name, wrapper_type)
self.py_name = py_name
wrapper.before_call.write_code("%s->flags = PYBINDGEN_WRAPPER_FLAG_NONE;" % py_name)
## Assign the C++ value to the Python wrapper
wrapper.before_call.write_code("%s->obj = %s;" % (py_name, value))
if self.cpp_class.helper_class is None:
try:
self.cpp_class.wrapper_registry.write_lookup_wrapper(
wrapper.before_call, self.cpp_class.pystruct, py_name, value)
except NotSupportedError:
write_create_new_wrapper()
self.cpp_class.wrapper_registry.write_register_new_wrapper(wrapper.before_call, py_name,
"%s->obj" % py_name)
else:
wrapper.before_call.write_code("if (%s == NULL)\n{" % py_name)
wrapper.before_call.indent()
write_create_new_wrapper()
self.cpp_class.wrapper_registry.write_register_new_wrapper(wrapper.before_call, py_name,
"%s->obj" % py_name)
wrapper.before_call.unindent()
wrapper.before_call.write_code('}')
wrapper.build_params.add_parameter("N", [py_name])
else:
wrapper.before_call.write_code("if (typeid(*(%s)).name() == typeid(%s).name())\n{"
% (value, self.cpp_class.helper_class.name))
wrapper.before_call.indent()
if self.type_traits.target_is_const:
wrapper.before_call.write_code(
"%s = (%s*) (((%s*) ((%s*) %s))->m_pyself);"
% (py_name, self.cpp_class.pystruct,
self.cpp_class.helper_class.name, self.cpp_class.full_name, value))
wrapper.before_call.write_code("%s->obj = (%s*) (%s);" %
(py_name, self.cpp_class.full_name, value))
else:
wrapper.before_call.write_code(
"%s = (%s*) (((%s*) %s)->m_pyself);"
% (py_name, self.cpp_class.pystruct,
self.cpp_class.helper_class.name, value))
wrapper.before_call.write_code("%s->obj = %s;" % (py_name, value))
wrapper.before_call.write_code("Py_INCREF(%s);" % py_name)
wrapper.before_call.unindent()
wrapper.before_call.write_code("} else {")
wrapper.before_call.indent()
try:
self.cpp_class.wrapper_registry.write_lookup_wrapper(
wrapper.before_call, self.cpp_class.pystruct, py_name, value)
except NotSupportedError:
write_create_new_wrapper()
self.cpp_class.wrapper_registry.write_register_new_wrapper(
wrapper.before_call, py_name, "%s->obj" % py_name)
else:
wrapper.before_call.write_code("if (%s == NULL)\n{" % py_name)
wrapper.before_call.indent()
write_create_new_wrapper()
self.cpp_class.wrapper_registry.write_register_new_wrapper(wrapper.before_call, py_name,
"%s->obj" % py_name)
wrapper.before_call.unindent()
wrapper.before_call.write_code('}') # closes if (%s == NULL)
wrapper.before_call.unindent()
wrapper.before_call.write_code("}") # closes if (typeid(*(%s)) == typeid(%s))\n{
wrapper.build_params.add_parameter("N", [py_name])
class CppClassNs3PtrReturnValue(CppClassReturnValueBase):
"Class* return handler"
CTYPES = []
SUPPORTS_TRANSFORMATIONS = True
cpp_class = None #cppclass.CppClass('dummy') # CppClass instance
def __init__(self, ctype, is_const=False):
super(CppClassNs3PtrReturnValue, self).__init__(ctype, is_const=is_const)
def get_c_error_return(self): # only used in reverse wrappers
"""See ReturnValue.get_c_error_return"""
return "return NULL;"
def convert_c_to_python(self, wrapper):
"""See ReturnValue.convert_c_to_python"""
## Value transformations
value = self.transformation.untransform(
self, wrapper.declarations, wrapper.after_call, self.value)
# if value is NULL, return None
wrapper.after_call.write_code("if (!(%s)) {\n"
" Py_INCREF(Py_None);\n"
" return Py_None;\n"
"}" % value)
## declare wrapper variable
py_name = wrapper.declarations.declare_variable(
self.cpp_class.pystruct+'*', 'py_'+self.cpp_class.name)
self.py_name = py_name
common_shared_object_return(value, py_name, self.cpp_class, wrapper.after_call,
self.type_traits, caller_owns_return=True,
reference_existing_object=False,
type_is_pointer=True)
# return the value
wrapper.build_params.add_parameter("N", [py_name], prepend=True)
def convert_python_to_c(self, wrapper):
"""See ReturnValue.convert_python_to_c"""
name = wrapper.declarations.declare_variable(
self.cpp_class.pystruct+'*', "tmp_%s" % self.cpp_class.name)
wrapper.parse_params.add_parameter(
'O!', ['&'+self.cpp_class.pytypestruct, '&'+name])
value = self.transformation.transform(
self, wrapper.declarations, wrapper.after_call, "%s->obj" % name)
# caller gets a shared pointer
wrapper.after_call.write_code("%s = %s;" % (self.value, value))