diff options
author | Pearu Peterson <pearu.peterson@gmail.com> | 2007-08-07 09:03:40 +0000 |
---|---|---|
committer | Pearu Peterson <pearu.peterson@gmail.com> | 2007-08-07 09:03:40 +0000 |
commit | 45176eddd776226c970b37632205541a1cd37a2c (patch) | |
tree | 0775fdfb5f06af2a05063c01b39baa5c315a5c53 /numpy/f2py | |
parent | 9bee05389a14f3bbf8f59a10b2398c8a4a7232ca (diff) | |
download | numpy-45176eddd776226c970b37632205541a1cd37a2c.tar.gz |
extgen: added argument dependecies support, reviewed reference counting of input and output arguments.
Diffstat (limited to 'numpy/f2py')
-rw-r--r-- | numpy/f2py/lib/extgen/c_type.py | 94 | ||||
-rw-r--r-- | numpy/f2py/lib/extgen/pyc_argument.py | 25 | ||||
-rw-r--r-- | numpy/f2py/lib/extgen/pyc_function.py | 67 |
3 files changed, 141 insertions, 45 deletions
diff --git a/numpy/f2py/lib/extgen/c_type.py b/numpy/f2py/lib/extgen/c_type.py index 8b985f8bb..18fb4d9f8 100644 --- a/numpy/f2py/lib/extgen/c_type.py +++ b/numpy/f2py/lib/extgen/c_type.py @@ -34,12 +34,6 @@ class CTypeBase(Component): def __str__(self): return self.name - def set_pyarg_decl(self, arg): - if arg.input_intent=='return': - arg += CDecl(self, '%s = Py_None' % (arg.pycvar)) - else: - arg += CDecl(self, '%s = NULL' % (arg.pycvar)) - def get_pyarg_fmt(self, arg): if arg.input_intent=='hide': return None return 'O' @@ -49,12 +43,82 @@ class CTypeBase(Component): return '&' + arg.pycvar def get_pyret_fmt(self, arg): - if arg.output_intent=='hide': return None - return 'O' + if arg.output_intent=='return': + # set_converters ensures tha all return values a new references + return 'N' + return def get_pyret_obj(self, arg): - if arg.output_intent=='hide': return None - return arg.pycvar + if arg.output_intent=='return': + return arg.retpycvar + return + + def set_Decl(self, arg): + if arg.input_intent!='hide': + arg += CDecl(self, '%s = NULL' % (arg.pycvar)) + + if arg.output_intent!='hide': + arg += CDecl(self, '%s = NULL' % (arg.retpycvar)) + + def set_converters(self, arg): + """ + Notes for user: + if arg is intent(optional, in, out) and not specified + as function argument then function may created but + it must then have *new reference* (ie use Py_INCREF + unless it is a new reference already). + """ + # this method is called from PyCFunction.update_containers(), + # note that self.parent is None put arg.parent is PyCFunction + # instance. + eval_a = arg.evaluate + FromPyObj = arg.container_FromPyObj + PyObjFrom = arg.container_PyObjFrom + if arg.output_intent=='return': + if arg.input_intent in ['optional', 'extra']: + FromPyObj += eval_a('''\ +if (!(%(pycvar)s==NULL)) { + /* make %(pycvar)r a new reference */ + %(retpycvar)s = %(pycvar)s; + Py_INCREF((PyObject*)%(retpycvar)s); +} +''') + PyObjFrom += eval_a('''\ +if (%(retpycvar)s==NULL) { + /* %(pycvar)r was not specified */ + if (%(pycvar)s==NULL) { + %(retpycvar)s = Py_None; + Py_INCREF((PyObject*)%(retpycvar)s); + } else { + %(retpycvar)s = %(pycvar)s; + /* %(pycvar)r must be a new reference or expect a core dump. */ + } +} elif (!(%(retpycvar)s == %(pycvar)s)) { + /* a new %(retpycvar)r was created, undoing %(pycvar)s new reference */ + Py_DECREF((PyObject*)%(pycvar)s); +} +''') + elif arg.input_intent=='hide': + PyObjFrom += eval_a('''\ +if (%(retpycvar)s==NULL) { + %(retpycvar)s = Py_None; + Py_INCREF((PyObject*)%(retpycvar)s); +} /* else %(retpycvar)r must be a new reference or expect a core dump. */ +''') + elif arg.input_intent=='required': + FromPyObj += eval_a('''\ +/* make %(pycvar)r a new reference */ +%(retpycvar)s = %(pycvar)s; +Py_INCREF((PyObject*)%(retpycvar)s); +''') + PyObjFrom += eval_a('''\ +if (!(%(retpycvar)s==%(pycvar)s)) { + /* a new %(retpycvar)r was created, undoing %(pycvar)r new reference */ + /* %(retpycvar)r must be a new reference or expect a core dump. */ + Py_DECREF((PyObject*)%(pycvar)s); +} +''') + return class _CatchTypeDef(Component): # for doctest template = '%(TypeDef)s' @@ -405,7 +469,6 @@ class CTypePython(CTypeBase): numpy_complex192 = ('PyComplex192ArrType_Type', 'PyComplex192ScalarObject*', 'O!'), numpy_complex256 = ('PyComplex256ArrType_Type', 'PyComplex256ScalarObject*', 'O!'), numeric_array = ('PyArray_Type', 'PyArrayObject*', 'O!'), - c_int = (None, 'int', 'i') ) def initialize(self, typeobj): @@ -468,12 +531,6 @@ class CTypePython(CTypeBase): if arg.output_title: r = ', ' + arg.output_title arg.output_title = tn + r - def set_pyarg_decl(self, arg): - if arg.input_intent=='hide': - arg += CDecl(self, '%s = Py_None' % (arg.pycvar)) - else: - arg += CDecl(self, '%s = NULL' % (arg.pycvar)) - def get_pyarg_fmt(self, arg): if arg.input_intent=='hide': return None return self.pyarg_fmt @@ -490,9 +547,6 @@ class CTypePython(CTypeBase): class CInt(CType): name = provides = 'int' def initialize(self): return self - def set_pyarg_decl(self, arg): - #arg += CDecl(Component.get('PyObject*'), '%s = NULL' % (arg.pycvar)) - arg += CDecl(self, '%s = 0' % (arg.cvar)) def get_pyarg_fmt(self, arg): return 'i' def get_pyarg_obj(self, arg): return '&' + arg.cvar def get_pyret_fmt(self, arg): return 'i' diff --git a/numpy/f2py/lib/extgen/pyc_argument.py b/numpy/f2py/lib/extgen/pyc_argument.py index c8667f2d8..75dd34922 100644 --- a/numpy/f2py/lib/extgen/pyc_argument.py +++ b/numpy/f2py/lib/extgen/pyc_argument.py @@ -10,7 +10,8 @@ class PyCArgument(Component): input_title = None, output_title = None, input_description = None, - output_description = None + output_description = None, + depends = [] ) """ @@ -29,21 +30,37 @@ class PyCArgument(Component): self.output_title = options.pop('output_title', None) self.input_description = options.pop('input_description', None) self.output_description = options.pop('output_description', None) + self.depends = options.pop('depends', []) if options: self.warning('%s unused options: %s\n' % (self.__class__.__name__, options)) map(self.add, components) + self.cvar = name - self.pycvar = name + '_pyc' + self.pycvar = None + self.retpycvar = None if ctype is None: ctype = Component.CTypePython(object) else: ctype = Component.CType(ctype) self.ctype = ctype - ctype.set_pyarg_decl(self) + + if isinstance(ctype, Component.CTypePython): + if self.output_intent == 'return': + if self.input_intent=='hide': + self.retpycvar = name + else: + self.pycvar = name + self.retpycvar = name + '_return' + elif self.input_intent!='hide': + self.pycvar = name + else: + self.pycvar = name + '_pyc' + self.retpycvar = name + '_pyc_r' + ctype.set_titles(self) - #self.add(ctype) + ctype.set_Decl(self) return self diff --git a/numpy/f2py/lib/extgen/pyc_function.py b/numpy/f2py/lib/extgen/pyc_function.py index 1cdbaeb1a..0e2376db9 100644 --- a/numpy/f2py/lib/extgen/pyc_function.py +++ b/numpy/f2py/lib/extgen/pyc_function.py @@ -19,7 +19,7 @@ class PyCFunction(Component): >>> f += PyCArgument('a2',input_intent='required') >>> f += PyCArgument('c2',input_intent='extra') >>> f += PyCArgument('b2',input_intent='optional') - >>> m = ExtensionModule('foo', f) + >>> m = ExtensionModule('test_PyCFunction', f) >>> foo = m.build() #doctest: +ELLIPSIS exec_command... >>> print foo.hello.__doc__ @@ -175,32 +175,57 @@ static PyObject* def update_containers(self): evaluate = self.evaluate - # get containers - FuncTitle = self.container_FuncTitle - FuncDescr = self.container_FuncDescr - ReqArgs = self.container_ReqArgs - OptArgs = self.container_OptArgs - ExtArgs = self.container_ExtArgs - OptExtArgs = self.container_OptExtArgs - OptPyArgFmt = self.container_OptPyArgFmt - ExtPyArgFmt = self.container_ExtPyArgFmt - OptExtPyArgFmt = self.container_OptExtPyArgFmt - ModuleMethod = self.container_ModuleMethod - ModuleFuncDoc = self.container_ModuleFuncDoc - # update ExtensionModule containers: t = '{"%(name)s", (PyCFunction)%(pyc_name)s,\n METH_VARARGS | METH_KEYWORDS, %(pyc_name)s_doc}' - ModuleMethod.add(evaluate(t), self.name) + self.container_ModuleMethod.add(evaluate(t), self.name) # update local containers: - OptExtArgs += OptArgs + ExtArgs - OptExtPyArgFmt += OptPyArgFmt + ExtPyArgFmt - ModuleFuncDoc += evaluate('%(name)s(%(ReqArgs)s%(OptExtArgs)s) -> %(RetArgs)s') + self.container_OptExtArgs += self.container_OptArgs + self.container_ExtArgs + self.container_OptExtPyArgFmt += self.container_OptPyArgFmt + self.container_ExtPyArgFmt + self.container_ModuleFuncDoc += evaluate('%(name)s(%(ReqArgs)s%(OptExtArgs)s) -> %(RetArgs)s') if self.title is not None: - FuncTitle += self.title - ModuleFuncDoc += ' ' + self.title + self.container_FuncTitle += self.title + self.container_ModuleFuncDoc += ' ' + self.title if self.description is not None: - FuncDescr += self.description + self.container_FuncDescr += self.description + + # resolve dependencies + sorted_arguments = [] + sorted_names = [] + comp_map = {} + dep_map = {} + for (c,l) in self.components: + if not isinstance(c, Component.PyCArgument): + continue + d = [n for n in c.depends if n not in sorted_names] + if not d: + sorted_arguments.append((c,l)) + sorted_names.append(c.name) + else: + comp_map[c.name] = (c,l) + dep_map[c.name] = d + + while dep_map: + dep_map_copy = dep_map.copy() + for name, deps in dep_map.items(): + d = [n for n in deps if dep_map.has_key(n)] + if not d: + sorted_arguments.append(comp_map[name]) + del dep_map[name] + else: + dep_map[name] = d + if dep_map_copy==dep_map: + self.warnign('%s: detected cyclic dependencies in %r, incorrect behavior is expected.\n'\ + % (self.provides, dep_map)) + sorted_arguments += dep_map.values() + break + + for c, l in sorted_arguments: + old_parent = c.parent + c.parent = self + c.ctype.set_converters(c) + c.parent = old_parent + return |