From: Dag Sverre Seljebotn Date: Thu, 21 May 2009 20:33:33 +0000 (+0200) Subject: Fix for#257 X-Git-Tag: 0.12.alpha0~288 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=81f9a985fabc4e44bcc5647a2b0a62e0a18bbf26;p=cython.git Fix for#257 --- diff --git a/Cython/Compiler/Buffer.py b/Cython/Compiler/Buffer.py index 91fd6adb..bfcedc9c 100644 --- a/Cython/Compiler/Buffer.py +++ b/Cython/Compiler/Buffer.py @@ -432,7 +432,7 @@ def use_empty_bufstruct_code(env, max_ndim): Py_ssize_t __Pyx_zeros[] = {%s}; Py_ssize_t __Pyx_minusones[] = {%s}; """) % (", ".join(["0"] * max_ndim), ", ".join(["-1"] * max_ndim)) - env.use_utility_code(UtilityCode(proto=code), "empty_bufstruct_code") + env.use_utility_code(UtilityCode(proto=code)) def buf_lookup_full_code(proto, defin, name, nd): @@ -494,7 +494,6 @@ def use_py2_buffer_functions(env): # Emulation of PyObject_GetBuffer and PyBuffer_Release for Python 2. # For >= 2.6 we do double mode -- use the new buffer interface on objects # which has the right tp_flags set, but emulation otherwise. - codename = "PyObject_GetBuffer" # just a representative unique key # Search all types for __getbuffer__ overloads types = [] @@ -567,7 +566,7 @@ def use_py2_buffer_functions(env): #define __Pyx_GetBuffer PyObject_GetBuffer #define __Pyx_ReleaseBuffer PyBuffer_Release #endif - """), impl = code), codename) + """), impl = code)) def mangle_dtype_name(dtype): diff --git a/Cython/Compiler/Code.py b/Cython/Compiler/Code.py index 8ac93610..a54372cc 100644 --- a/Cython/Compiler/Code.py +++ b/Cython/Compiler/Code.py @@ -18,9 +18,13 @@ import DebugFlags from Cython.Utils import none_or_sub -# a simple class that simplifies the usage of utility code - class UtilityCode(object): + # Stores utility code to add during code generation. + # + # See GlobalState.put_utility_code. + # + # hashes/equals by instance + def __init__(self, proto=None, impl=None, init=None, cleanup=None, requires=None): self.proto = proto self.impl = impl diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py index 682bc28e..7a0780f9 100644 --- a/Cython/Compiler/PyrexTypes.py +++ b/Cython/Compiler/PyrexTypes.py @@ -1236,6 +1236,44 @@ class CFuncTypeArg(object): def declaration_code(self, for_display = 0): return self.type.declaration_code(self.cname, for_display) +class StructUtilityCode(object): + def __init__(self, type, forward_decl): + self.type = type + self.header = "static PyObject* %s(%s)" % (type.to_py_function, type.declaration_code('s')) + self.forward_decl = forward_decl + + def __eq__(self, other): + return isinstance(other, StructUtilityCode) and self.header == other.header + def __hash__(self): + return hash(self.header) + + def put_code(self, output): + code = output['utility_code_def'] + proto = output['utility_code_proto'] + + code.putln("%s {" % self.header) + code.putln("PyObject* res;") + code.putln("PyObject* member;") + code.putln("res = PyDict_New(); if (res == NULL) return NULL;") + for member in self.type.scope.var_entries: + nameconst_cname = code.get_py_string_const(member.name, identifier=True) + code.putln("member = %s(s.%s); if (member == NULL) goto bad;" % ( + member.type.to_py_function, member.cname)) + code.putln("if (PyDict_SetItem(res, %s, member) < 0) goto bad;" % nameconst_cname) + code.putln("Py_DECREF(member);") + code.putln("return res;") + code.putln("bad:") + code.putln("Py_XDECREF(member);") + code.putln("Py_DECREF(res);") + code.putln("return NULL;") + code.putln("}") + + # This is a bit of a hack, we need a forward declaration + # due to the way things are ordered in the module... + if self.forward_decl: + proto.putln(self.type.declaration_code('') + ';') + proto.putln(self.header + ";") + class CStructOrUnionType(CType): # name string @@ -1264,39 +1302,18 @@ class CStructOrUnionType(CType): def create_to_py_utility_code(self, env): if env.outer_scope is None: return False + + if self._convert_code is False: return # tri-state-ish + if self._convert_code is None: - import Code - code = Code.CCodeWriter() - Code.GlobalState(code) - header = "static PyObject* %s(%s)" % (self.to_py_function, self.declaration_code('s')) - code.putln("%s {" % header) - code.putln("PyObject* res;") - code.putln("PyObject* member;") - code.putln("res = PyDict_New(); if (res == NULL) return NULL;") for member in self.scope.var_entries: - if member.type.to_py_function and member.type.create_to_py_utility_code(env): - interned_name = env.get_string_const(member.name, identifier=True) - env.add_py_string(interned_name) - code.putln("member = %s(s.%s); if (member == NULL) goto bad;" % ( - member.type.to_py_function, member.cname)) - code.putln("if (PyDict_SetItem(res, %s, member) < 0) goto bad;" % interned_name.pystring_cname) - code.putln("Py_DECREF(member);") - else: + if not member.type.to_py_function or not member.type.create_to_py_utility_code(env): self.to_py_function = None + self._convert_code = False return False - code.putln("return res;") - code.putln("bad:") - code.putln("Py_XDECREF(member);") - code.putln("Py_DECREF(res);") - code.putln("return NULL;") - code.putln("}") - proto = header + ";" - # This is a bit of a hack, we need a forward declaration - # due to the way things are ordered in the module... entry = env.lookup(self.name) - if entry.visibility != 'extern': - proto = self.declaration_code('') + ';\n' + proto - self._convert_code = UtilityCode(proto=proto, impl=code.buffer.getvalue()) + forward_decl = (entry.visibility != 'extern') + self._convert_code = StructUtilityCode(self, forward_decl) env.use_utility_code(self._convert_code) return True