blob: b23cbaa1eecc8e901a91afd3133f2202b29c566b [file] [log] [blame]
Alexander Afanasyev5713e7a2015-01-02 01:08:18 -08001
2from pybindgen.typehandlers.base import Parameter, ReturnValue, \
3 join_ctype_and_name, CodeGenerationError, \
4 param_type_matcher, return_type_matcher, CodegenErrorBase, \
5 DeclarationsScope, CodeBlock, NotSupportedError, ForwardWrapperBase, ReverseWrapperBase, \
6 TypeConfigurationError
7
8from pybindgen.cppclass import ReferenceCountingMethodsPolicy, CppClass, CppClassParameterBase, CppClassReturnValueBase, common_shared_object_return
9
10class Ns3PtrMemoryPolicy(ReferenceCountingMethodsPolicy):
11 def __init__(self, class_name):
12 """
13 Create a memory policy for using ns3::Ptr<> to manage instances of this object.
14
15 :param class_name: the full name of the class, e.g. foo::Bar
16 """
17 super(Ns3PtrMemoryPolicy, self).__init__('Ref', 'Unref', 'GetReferenceCount')
18
19 self.class_name = class_name
20 self.pointer_template = 'ns3::Ptr< %s >'
21
22 def get_pointer_name(self, class_name):
23 return self.pointer_template % (class_name,)
24
25 def get_delete_code(self, cpp_class):
26 return "self->obj.~Ptr< %s >();" % (cpp_class.full_name,)
27
28 def get_pointer_type(self, class_full_name):
29 return self.get_pointer_name(class_full_name) + ' '
30
31 def get_pointer_to_void_name(self, object_name):
32 return "::ns3::PeekPointer(%s)" % object_name
33
34 def get_instance_creation_function(self):
35 return ns3_ptr_instance_creation_function
36
37 def get_pystruct_init_code(self, cpp_class, obj):
38 return "new(&%s->obj) %s;" % (obj, self.get_pointer_name(cpp_class.full_name),)
39
40 def register_ptr_parameter_and_return(self, cls, name):
41 class ThisClassNs3PtrParameter(CppClassNs3PtrParameter):
42 """Register this C++ class as pass-by-pointer parameter"""
43 CTYPES = []
44 cpp_class = cls
45 cls.ThisClassNs3PtrParameter = ThisClassNs3PtrParameter
46 try:
47 param_type_matcher.register(self.get_pointer_name(cls.full_name), cls.ThisClassNs3PtrParameter)
48 except ValueError:
49 pass
50
51 class ThisClassNs3PtrReturn(CppClassNs3PtrReturnValue):
52 """Register this C++ class as pointer return"""
53 CTYPES = []
54 cpp_class = cls
55 cls.ThisClassNs3PtrReturn = ThisClassNs3PtrReturn
56 try:
57 return_type_matcher.register(self.get_pointer_name(cls.full_name), cls.ThisClassNs3PtrReturn)
58 except ValueError:
59 pass
60
61 def register_ptr_alias_parameter_and_return(self, cls, alias):
62 alias_ptr = '::ns3::Ptr< %s >' % alias
63 cls.ThisClassNs3PtrParameter.CTYPES.append(alias_ptr)
64 try:
65 param_type_matcher.register(alias_ptr, cls.ThisClassNs3PtrParameter)
66 except ValueError: pass
67
68 cls.ThisClassNs3PtrReturn.CTYPES.append(alias_ptr)
69 try:
70 return_type_matcher.register(alias_ptr, cls.ThisClassNs3PtrReturn)
71 except ValueError: pass
72
73def ns3_ptr_instance_creation_function(cpp_class, code_block, lvalue,
74 parameters, construct_type_name):
75 """
76 ns3::Ptr "instance creation function"; it is called whenever a new
77 C++ class instance needs to be created
78
79 :param cpp_class: the CppClass object whose instance is to be created
80 :param code_block: CodeBlock object on which the instance creation code should be generated
81 :param lvalue: lvalue expression that should hold the result in the end
82 :param parameters: stringified list of parameters
83 :param construct_type_name: actual name of type to be constructed (it is
84 not always the class name, sometimes it's
85 the python helper class)
86 """
87 assert lvalue
88 assert not lvalue.startswith('None')
89 if cpp_class.incomplete_type:
90 raise CodeGenerationError("%s cannot be constructed (incomplete type)"
91 % cpp_class.full_name)
92 code_block.write_code(
93 "%s = ::ns3::Create<%s>(%s);" % (lvalue, construct_type_name, parameters))
94
95class CppClassNs3PtrParameter(CppClassParameterBase):
96 "Class* handlers"
97 CTYPES = []
98 cpp_class = None #cppclass.CppClass('dummy') # CppClass instance
99 DIRECTIONS = [Parameter.DIRECTION_IN,
100 Parameter.DIRECTION_OUT,
101 Parameter.DIRECTION_INOUT]
102 SUPPORTS_TRANSFORMATIONS = False
103
104 def __init__(self, ctype, name, direction=Parameter.DIRECTION_IN, is_const=False,
105 null_ok=False, default_value=None):
106 super(CppClassNs3PtrParameter, self).__init__(
107 ctype, name, direction, is_const, default_value)
108 self.null_ok = null_ok
109
110
111 def convert_python_to_c(self, wrapper):
112 "parses python args to get C++ value"
113 assert isinstance(wrapper, ForwardWrapperBase)
114 assert isinstance(self.cpp_class, CppClass)
115
116 self.py_name = wrapper.declarations.declare_variable(
117 self.cpp_class.pystruct+'*', self.name,
118 initializer=(self.default_value and 'NULL' or None))
119
120 value_ptr = wrapper.declarations.declare_variable(
121 self.cpp_class.memory_policy.get_pointer_name(self.cpp_class.full_name), "%s_ptr" % self.name)
122
123 if self.null_ok:
124 num = wrapper.parse_params.add_parameter('O', ['&'+self.py_name], self.name, optional=bool(self.default_value))
125
126 wrapper.before_call.write_error_check(
127
128 "%s && ((PyObject *) %s != Py_None) && !PyObject_IsInstance((PyObject *) %s, (PyObject *) &%s)"
129 % (self.py_name, self.py_name, self.py_name, self.cpp_class.pytypestruct),
130
131 'PyErr_SetString(PyExc_TypeError, "Parameter %i must be of type %s");' % (num, self.cpp_class.name))
132
133 wrapper.before_call.write_code("if (%(PYNAME)s) {\n"
134 " if ((PyObject *) %(PYNAME)s == Py_None)\n"
135 " %(VALUE)s = NULL;\n"
136 " else\n"
137 " %(VALUE)s = %(PYNAME)s->obj;\n"
138 "} else {\n"
139 " %(VALUE)s = NULL;\n"
140 "}" % dict(PYNAME=self.py_name, VALUE=value_ptr))
141
142 else:
143
144 wrapper.parse_params.add_parameter(
145 'O!', ['&'+self.cpp_class.pytypestruct, '&'+self.py_name], self.name, optional=bool(self.default_value))
146 wrapper.before_call.write_code("if (%s) { %s = %s->obj; }" % (self.py_name, value_ptr, self.py_name))
147
148 wrapper.call_params.append(value_ptr)
149
150
151
152 def convert_c_to_python(self, wrapper):
153 """foo"""
154
155 ## Value transformations
156 value = self.transformation.untransform(
157 self, wrapper.declarations, wrapper.after_call, self.value)
158
159 ## declare wrapper variable
160 py_name = wrapper.declarations.declare_variable(
161 self.cpp_class.pystruct+'*', 'py_'+self.cpp_class.name)
162 self.py_name = py_name
163
164 def write_create_new_wrapper():
165 """Code path that creates a new wrapper for the parameter"""
166
167 ## Find out what Python wrapper to use, in case
168 ## automatic_type_narrowing is active and we are not forced to
169 ## make a copy of the object
170 if self.cpp_class.automatic_type_narrowing:
171
172 typeid_map_name = self.cpp_class.get_type_narrowing_root().typeid_map_name
173 wrapper_type = wrapper.declarations.declare_variable(
174 'PyTypeObject*', 'wrapper_type', '0')
175 wrapper.before_call.write_code(
176 '%s = %s.lookup_wrapper(typeid(*%s), &%s);'
177 % (wrapper_type, typeid_map_name, value, self.cpp_class.memory_policy.get_pointer_to_void_name(self.cpp_class.pytypestruct)))
178 else:
179 wrapper_type = '&'+self.cpp_class.pytypestruct
180
181 ## Create the Python wrapper object
182 self.cpp_class.write_allocate_pystruct(wrapper.before_call, py_name, wrapper_type)
183 self.py_name = py_name
184
185 wrapper.before_call.write_code("%s->flags = PYBINDGEN_WRAPPER_FLAG_NONE;" % py_name)
186
187 ## Assign the C++ value to the Python wrapper
188 wrapper.before_call.write_code("%s->obj = %s;" % (py_name, value))
189
190 if self.cpp_class.helper_class is None:
191 try:
192 self.cpp_class.wrapper_registry.write_lookup_wrapper(
193 wrapper.before_call, self.cpp_class.pystruct, py_name, value)
194 except NotSupportedError:
195 write_create_new_wrapper()
196 self.cpp_class.wrapper_registry.write_register_new_wrapper(wrapper.before_call, py_name,
197 "%s->obj" % py_name)
198 else:
199 wrapper.before_call.write_code("if (%s == NULL)\n{" % py_name)
200 wrapper.before_call.indent()
201 write_create_new_wrapper()
202 self.cpp_class.wrapper_registry.write_register_new_wrapper(wrapper.before_call, py_name,
203 "%s->obj" % py_name)
204 wrapper.before_call.unindent()
205 wrapper.before_call.write_code('}')
206 wrapper.build_params.add_parameter("N", [py_name])
207 else:
208 wrapper.before_call.write_code("if (typeid(*(%s)).name() == typeid(%s).name())\n{"
209 % (value, self.cpp_class.helper_class.name))
210 wrapper.before_call.indent()
211
212 if self.type_traits.target_is_const:
213 wrapper.before_call.write_code(
214 "%s = (%s*) (((%s*) ((%s*) %s))->m_pyself);"
215 % (py_name, self.cpp_class.pystruct,
216 self.cpp_class.helper_class.name, self.cpp_class.full_name, value))
217 wrapper.before_call.write_code("%s->obj = (%s*) (%s);" %
218 (py_name, self.cpp_class.full_name, value))
219 else:
220 wrapper.before_call.write_code(
221 "%s = (%s*) (((%s*) %s)->m_pyself);"
222 % (py_name, self.cpp_class.pystruct,
223 self.cpp_class.helper_class.name, value))
224 wrapper.before_call.write_code("%s->obj = %s;" % (py_name, value))
225 wrapper.before_call.write_code("Py_INCREF(%s);" % py_name)
226 wrapper.before_call.unindent()
227 wrapper.before_call.write_code("} else {")
228 wrapper.before_call.indent()
229
230 try:
231 self.cpp_class.wrapper_registry.write_lookup_wrapper(
232 wrapper.before_call, self.cpp_class.pystruct, py_name, value)
233 except NotSupportedError:
234 write_create_new_wrapper()
235 self.cpp_class.wrapper_registry.write_register_new_wrapper(
236 wrapper.before_call, py_name, "%s->obj" % py_name)
237 else:
238 wrapper.before_call.write_code("if (%s == NULL)\n{" % py_name)
239 wrapper.before_call.indent()
240 write_create_new_wrapper()
241 self.cpp_class.wrapper_registry.write_register_new_wrapper(wrapper.before_call, py_name,
242 "%s->obj" % py_name)
243 wrapper.before_call.unindent()
244 wrapper.before_call.write_code('}') # closes if (%s == NULL)
245
246 wrapper.before_call.unindent()
247 wrapper.before_call.write_code("}") # closes if (typeid(*(%s)) == typeid(%s))\n{
248 wrapper.build_params.add_parameter("N", [py_name])
249
250
251
252
253class CppClassNs3PtrReturnValue(CppClassReturnValueBase):
254 "Class* return handler"
255 CTYPES = []
256 SUPPORTS_TRANSFORMATIONS = True
257 cpp_class = None #cppclass.CppClass('dummy') # CppClass instance
258
259 def __init__(self, ctype, is_const=False):
260 super(CppClassNs3PtrReturnValue, self).__init__(ctype, is_const=is_const)
261
262 def get_c_error_return(self): # only used in reverse wrappers
263 """See ReturnValue.get_c_error_return"""
264 return "return NULL;"
265
266 def convert_c_to_python(self, wrapper):
267 """See ReturnValue.convert_c_to_python"""
268
269 ## Value transformations
270 value = self.transformation.untransform(
271 self, wrapper.declarations, wrapper.after_call, self.value)
272
273 # if value is NULL, return None
274 wrapper.after_call.write_code("if (!(%s)) {\n"
275 " Py_INCREF(Py_None);\n"
276 " return Py_None;\n"
277 "}" % value)
278
279 ## declare wrapper variable
280 py_name = wrapper.declarations.declare_variable(
281 self.cpp_class.pystruct+'*', 'py_'+self.cpp_class.name)
282 self.py_name = py_name
283
284 common_shared_object_return(value, py_name, self.cpp_class, wrapper.after_call,
285 self.type_traits, caller_owns_return=True,
286 reference_existing_object=False,
287 type_is_pointer=True)
288
289 # return the value
290 wrapper.build_params.add_parameter("N", [py_name], prepend=True)
291
292
293 def convert_python_to_c(self, wrapper):
294 """See ReturnValue.convert_python_to_c"""
295 name = wrapper.declarations.declare_variable(
296 self.cpp_class.pystruct+'*', "tmp_%s" % self.cpp_class.name)
297 wrapper.parse_params.add_parameter(
298 'O!', ['&'+self.cpp_class.pytypestruct, '&'+name])
299
300 value = self.transformation.transform(
301 self, wrapper.declarations, wrapper.after_call, "%s->obj" % name)
302
303 # caller gets a shared pointer
304 wrapper.after_call.write_code("%s = %s;" % (self.value, value))