diff options
author | monster <monster@ydb.tech> | 2022-07-07 14:41:37 +0300 |
---|---|---|
committer | monster <monster@ydb.tech> | 2022-07-07 14:41:37 +0300 |
commit | 06e5c21a835c0e923506c4ff27929f34e00761c2 (patch) | |
tree | 75efcbc6854ef9bd476eb8bf00cc5c900da436a2 /contrib/tools/cython/Cython/Compiler/Buffer.py | |
parent | 03f024c4412e3aa613bb543cf1660176320ba8f4 (diff) | |
download | ydb-06e5c21a835c0e923506c4ff27929f34e00761c2.tar.gz |
fix ya.make
Diffstat (limited to 'contrib/tools/cython/Cython/Compiler/Buffer.py')
-rw-r--r-- | contrib/tools/cython/Cython/Compiler/Buffer.py | 740 |
1 files changed, 0 insertions, 740 deletions
diff --git a/contrib/tools/cython/Cython/Compiler/Buffer.py b/contrib/tools/cython/Cython/Compiler/Buffer.py deleted file mode 100644 index c62a24f568..0000000000 --- a/contrib/tools/cython/Cython/Compiler/Buffer.py +++ /dev/null @@ -1,740 +0,0 @@ -from __future__ import absolute_import - -from .Visitor import CythonTransform -from .ModuleNode import ModuleNode -from .Errors import CompileError -from .UtilityCode import CythonUtilityCode -from .Code import UtilityCode, TempitaUtilityCode - -from . import Options -from . import Interpreter -from . import PyrexTypes -from . import Naming -from . import Symtab - -def dedent(text, reindent=0): - from textwrap import dedent - text = dedent(text) - if reindent > 0: - indent = " " * reindent - text = '\n'.join([indent + x for x in text.split('\n')]) - return text - -class IntroduceBufferAuxiliaryVars(CythonTransform): - - # - # Entry point - # - - buffers_exists = False - using_memoryview = False - - def __call__(self, node): - assert isinstance(node, ModuleNode) - self.max_ndim = 0 - result = super(IntroduceBufferAuxiliaryVars, self).__call__(node) - if self.buffers_exists: - use_bufstruct_declare_code(node.scope) - use_py2_buffer_functions(node.scope) - - return result - - - # - # Basic operations for transforms - # - def handle_scope(self, node, scope): - # For all buffers, insert extra variables in the scope. - # The variables are also accessible from the buffer_info - # on the buffer entry - scope_items = scope.entries.items() - bufvars = [entry for name, entry in scope_items if entry.type.is_buffer] - if len(bufvars) > 0: - bufvars.sort(key=lambda entry: entry.name) - self.buffers_exists = True - - memviewslicevars = [entry for name, entry in scope_items if entry.type.is_memoryviewslice] - if len(memviewslicevars) > 0: - self.buffers_exists = True - - - for (name, entry) in scope_items: - if name == 'memoryview' and isinstance(entry.utility_code_definition, CythonUtilityCode): - self.using_memoryview = True - break - del scope_items - - if isinstance(node, ModuleNode) and len(bufvars) > 0: - # for now...note that pos is wrong - raise CompileError(node.pos, "Buffer vars not allowed in module scope") - for entry in bufvars: - if entry.type.dtype.is_ptr: - raise CompileError(node.pos, "Buffers with pointer types not yet supported.") - - name = entry.name - buftype = entry.type - if buftype.ndim > Options.buffer_max_dims: - raise CompileError(node.pos, - "Buffer ndims exceeds Options.buffer_max_dims = %d" % Options.buffer_max_dims) - if buftype.ndim > self.max_ndim: - self.max_ndim = buftype.ndim - - # Declare auxiliary vars - def decvar(type, prefix): - cname = scope.mangle(prefix, name) - aux_var = scope.declare_var(name=None, cname=cname, - type=type, pos=node.pos) - if entry.is_arg: - aux_var.used = True # otherwise, NameNode will mark whether it is used - - return aux_var - - auxvars = ((PyrexTypes.c_pyx_buffer_nd_type, Naming.pybuffernd_prefix), - (PyrexTypes.c_pyx_buffer_type, Naming.pybufferstruct_prefix)) - pybuffernd, rcbuffer = [decvar(type, prefix) for (type, prefix) in auxvars] - - entry.buffer_aux = Symtab.BufferAux(pybuffernd, rcbuffer) - - scope.buffer_entries = bufvars - self.scope = scope - - def visit_ModuleNode(self, node): - self.handle_scope(node, node.scope) - self.visitchildren(node) - return node - - def visit_FuncDefNode(self, node): - self.handle_scope(node, node.local_scope) - self.visitchildren(node) - return node - -# -# Analysis -# -buffer_options = ("dtype", "ndim", "mode", "negative_indices", "cast") # ordered! -buffer_defaults = {"ndim": 1, "mode": "full", "negative_indices": True, "cast": False} -buffer_positional_options_count = 1 # anything beyond this needs keyword argument - -ERR_BUF_OPTION_UNKNOWN = '"%s" is not a buffer option' -ERR_BUF_TOO_MANY = 'Too many buffer options' -ERR_BUF_DUP = '"%s" buffer option already supplied' -ERR_BUF_MISSING = '"%s" missing' -ERR_BUF_MODE = 'Only allowed buffer modes are: "c", "fortran", "full", "strided" (as a compile-time string)' -ERR_BUF_NDIM = 'ndim must be a non-negative integer' -ERR_BUF_DTYPE = 'dtype must be "object", numeric type or a struct' -ERR_BUF_BOOL = '"%s" must be a boolean' - -def analyse_buffer_options(globalpos, env, posargs, dictargs, defaults=None, need_complete=True): - """ - Must be called during type analysis, as analyse is called - on the dtype argument. - - posargs and dictargs should consist of a list and a dict - of tuples (value, pos). Defaults should be a dict of values. - - Returns a dict containing all the options a buffer can have and - its value (with the positions stripped). - """ - if defaults is None: - defaults = buffer_defaults - - posargs, dictargs = Interpreter.interpret_compiletime_options( - posargs, dictargs, type_env=env, type_args=(0, 'dtype')) - - if len(posargs) > buffer_positional_options_count: - raise CompileError(posargs[-1][1], ERR_BUF_TOO_MANY) - - options = {} - for name, (value, pos) in dictargs.items(): - if not name in buffer_options: - raise CompileError(pos, ERR_BUF_OPTION_UNKNOWN % name) - options[name] = value - - for name, (value, pos) in zip(buffer_options, posargs): - if not name in buffer_options: - raise CompileError(pos, ERR_BUF_OPTION_UNKNOWN % name) - if name in options: - raise CompileError(pos, ERR_BUF_DUP % name) - options[name] = value - - # Check that they are all there and copy defaults - for name in buffer_options: - if not name in options: - try: - options[name] = defaults[name] - except KeyError: - if need_complete: - raise CompileError(globalpos, ERR_BUF_MISSING % name) - - dtype = options.get("dtype") - if dtype and dtype.is_extension_type: - raise CompileError(globalpos, ERR_BUF_DTYPE) - - ndim = options.get("ndim") - if ndim and (not isinstance(ndim, int) or ndim < 0): - raise CompileError(globalpos, ERR_BUF_NDIM) - - mode = options.get("mode") - if mode and not (mode in ('full', 'strided', 'c', 'fortran')): - raise CompileError(globalpos, ERR_BUF_MODE) - - def assert_bool(name): - x = options.get(name) - if not isinstance(x, bool): - raise CompileError(globalpos, ERR_BUF_BOOL % name) - - assert_bool('negative_indices') - assert_bool('cast') - - return options - - -# -# Code generation -# - -class BufferEntry(object): - def __init__(self, entry): - self.entry = entry - self.type = entry.type - self.cname = entry.buffer_aux.buflocal_nd_var.cname - self.buf_ptr = "%s.rcbuffer->pybuffer.buf" % self.cname - self.buf_ptr_type = entry.type.buffer_ptr_type - self.init_attributes() - - def init_attributes(self): - self.shape = self.get_buf_shapevars() - self.strides = self.get_buf_stridevars() - self.suboffsets = self.get_buf_suboffsetvars() - - def get_buf_suboffsetvars(self): - return self._for_all_ndim("%s.diminfo[%d].suboffsets") - - def get_buf_stridevars(self): - return self._for_all_ndim("%s.diminfo[%d].strides") - - def get_buf_shapevars(self): - return self._for_all_ndim("%s.diminfo[%d].shape") - - def _for_all_ndim(self, s): - return [s % (self.cname, i) for i in range(self.type.ndim)] - - def generate_buffer_lookup_code(self, code, index_cnames): - # Create buffer lookup and return it - # This is done via utility macros/inline functions, which vary - # according to the access mode used. - params = [] - nd = self.type.ndim - mode = self.type.mode - if mode == 'full': - for i, s, o in zip(index_cnames, - self.get_buf_stridevars(), - self.get_buf_suboffsetvars()): - params.append(i) - params.append(s) - params.append(o) - funcname = "__Pyx_BufPtrFull%dd" % nd - funcgen = buf_lookup_full_code - else: - if mode == 'strided': - funcname = "__Pyx_BufPtrStrided%dd" % nd - funcgen = buf_lookup_strided_code - elif mode == 'c': - funcname = "__Pyx_BufPtrCContig%dd" % nd - funcgen = buf_lookup_c_code - elif mode == 'fortran': - funcname = "__Pyx_BufPtrFortranContig%dd" % nd - funcgen = buf_lookup_fortran_code - else: - assert False - for i, s in zip(index_cnames, self.get_buf_stridevars()): - params.append(i) - params.append(s) - - # Make sure the utility code is available - if funcname not in code.globalstate.utility_codes: - code.globalstate.utility_codes.add(funcname) - protocode = code.globalstate['utility_code_proto'] - defcode = code.globalstate['utility_code_def'] - funcgen(protocode, defcode, name=funcname, nd=nd) - - buf_ptr_type_code = self.buf_ptr_type.empty_declaration_code() - ptrcode = "%s(%s, %s, %s)" % (funcname, buf_ptr_type_code, self.buf_ptr, - ", ".join(params)) - return ptrcode - - -def get_flags(buffer_aux, buffer_type): - flags = 'PyBUF_FORMAT' - mode = buffer_type.mode - if mode == 'full': - flags += '| PyBUF_INDIRECT' - elif mode == 'strided': - flags += '| PyBUF_STRIDES' - elif mode == 'c': - flags += '| PyBUF_C_CONTIGUOUS' - elif mode == 'fortran': - flags += '| PyBUF_F_CONTIGUOUS' - else: - assert False - if buffer_aux.writable_needed: flags += "| PyBUF_WRITABLE" - return flags - -def used_buffer_aux_vars(entry): - buffer_aux = entry.buffer_aux - buffer_aux.buflocal_nd_var.used = True - buffer_aux.rcbuf_var.used = True - -def put_unpack_buffer_aux_into_scope(buf_entry, code): - # Generate code to copy the needed struct info into local - # variables. - buffer_aux, mode = buf_entry.buffer_aux, buf_entry.type.mode - pybuffernd_struct = buffer_aux.buflocal_nd_var.cname - - fldnames = ['strides', 'shape'] - if mode == 'full': - fldnames.append('suboffsets') - - ln = [] - for i in range(buf_entry.type.ndim): - for fldname in fldnames: - ln.append("%s.diminfo[%d].%s = %s.rcbuffer->pybuffer.%s[%d];" % \ - (pybuffernd_struct, i, fldname, - pybuffernd_struct, fldname, i)) - code.putln(' '.join(ln)) - -def put_init_vars(entry, code): - bufaux = entry.buffer_aux - pybuffernd_struct = bufaux.buflocal_nd_var.cname - pybuffer_struct = bufaux.rcbuf_var.cname - # init pybuffer_struct - code.putln("%s.pybuffer.buf = NULL;" % pybuffer_struct) - code.putln("%s.refcount = 0;" % pybuffer_struct) - # init the buffer object - # code.put_init_var_to_py_none(entry) - # init the pybuffernd_struct - code.putln("%s.data = NULL;" % pybuffernd_struct) - code.putln("%s.rcbuffer = &%s;" % (pybuffernd_struct, pybuffer_struct)) - - -def put_acquire_arg_buffer(entry, code, pos): - buffer_aux = entry.buffer_aux - getbuffer = get_getbuffer_call(code, entry.cname, buffer_aux, entry.type) - - # Acquire any new buffer - code.putln("{") - code.putln("__Pyx_BufFmt_StackElem __pyx_stack[%d];" % entry.type.dtype.struct_nesting_depth()) - code.putln(code.error_goto_if("%s == -1" % getbuffer, pos)) - code.putln("}") - # An exception raised in arg parsing cannot be caught, so no - # need to care about the buffer then. - put_unpack_buffer_aux_into_scope(entry, code) - - -def put_release_buffer_code(code, entry): - code.globalstate.use_utility_code(acquire_utility_code) - code.putln("__Pyx_SafeReleaseBuffer(&%s.rcbuffer->pybuffer);" % entry.buffer_aux.buflocal_nd_var.cname) - - -def get_getbuffer_call(code, obj_cname, buffer_aux, buffer_type): - ndim = buffer_type.ndim - cast = int(buffer_type.cast) - flags = get_flags(buffer_aux, buffer_type) - pybuffernd_struct = buffer_aux.buflocal_nd_var.cname - - dtype_typeinfo = get_type_information_cname(code, buffer_type.dtype) - - code.globalstate.use_utility_code(acquire_utility_code) - return ("__Pyx_GetBufferAndValidate(&%(pybuffernd_struct)s.rcbuffer->pybuffer, " - "(PyObject*)%(obj_cname)s, &%(dtype_typeinfo)s, %(flags)s, %(ndim)d, " - "%(cast)d, __pyx_stack)" % locals()) - - -def put_assign_to_buffer(lhs_cname, rhs_cname, buf_entry, - is_initialized, pos, code): - """ - Generate code for reassigning a buffer variables. This only deals with getting - the buffer auxiliary structure and variables set up correctly, the assignment - itself and refcounting is the responsibility of the caller. - - However, the assignment operation may throw an exception so that the reassignment - never happens. - - Depending on the circumstances there are two possible outcomes: - - Old buffer released, new acquired, rhs assigned to lhs - - Old buffer released, new acquired which fails, reaqcuire old lhs buffer - (which may or may not succeed). - """ - - buffer_aux, buffer_type = buf_entry.buffer_aux, buf_entry.type - pybuffernd_struct = buffer_aux.buflocal_nd_var.cname - flags = get_flags(buffer_aux, buffer_type) - - code.putln("{") # Set up necessary stack for getbuffer - code.putln("__Pyx_BufFmt_StackElem __pyx_stack[%d];" % buffer_type.dtype.struct_nesting_depth()) - - getbuffer = get_getbuffer_call(code, "%s", buffer_aux, buffer_type) # fill in object below - - if is_initialized: - # Release any existing buffer - code.putln('__Pyx_SafeReleaseBuffer(&%s.rcbuffer->pybuffer);' % pybuffernd_struct) - # Acquire - retcode_cname = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False) - code.putln("%s = %s;" % (retcode_cname, getbuffer % rhs_cname)) - code.putln('if (%s) {' % (code.unlikely("%s < 0" % retcode_cname))) - # If acquisition failed, attempt to reacquire the old buffer - # before raising the exception. A failure of reacquisition - # will cause the reacquisition exception to be reported, one - # can consider working around this later. - exc_temps = tuple(code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=False) - for _ in range(3)) - code.putln('PyErr_Fetch(&%s, &%s, &%s);' % exc_temps) - code.putln('if (%s) {' % code.unlikely("%s == -1" % (getbuffer % lhs_cname))) - code.putln('Py_XDECREF(%s); Py_XDECREF(%s); Py_XDECREF(%s);' % exc_temps) # Do not refnanny these! - code.globalstate.use_utility_code(raise_buffer_fallback_code) - code.putln('__Pyx_RaiseBufferFallbackError();') - code.putln('} else {') - code.putln('PyErr_Restore(%s, %s, %s);' % exc_temps) - code.putln('}') - code.putln('%s = %s = %s = 0;' % exc_temps) - for t in exc_temps: - code.funcstate.release_temp(t) - code.putln('}') - # Unpack indices - put_unpack_buffer_aux_into_scope(buf_entry, code) - code.putln(code.error_goto_if_neg(retcode_cname, pos)) - code.funcstate.release_temp(retcode_cname) - else: - # Our entry had no previous value, so set to None when acquisition fails. - # In this case, auxiliary vars should be set up right in initialization to a zero-buffer, - # so it suffices to set the buf field to NULL. - code.putln('if (%s) {' % code.unlikely("%s == -1" % (getbuffer % rhs_cname))) - code.putln('%s = %s; __Pyx_INCREF(Py_None); %s.rcbuffer->pybuffer.buf = NULL;' % - (lhs_cname, - PyrexTypes.typecast(buffer_type, PyrexTypes.py_object_type, "Py_None"), - pybuffernd_struct)) - code.putln(code.error_goto(pos)) - code.put('} else {') - # Unpack indices - put_unpack_buffer_aux_into_scope(buf_entry, code) - code.putln('}') - - code.putln("}") # Release stack - - -def put_buffer_lookup_code(entry, index_signeds, index_cnames, directives, - pos, code, negative_indices, in_nogil_context): - """ - Generates code to process indices and calculate an offset into - a buffer. Returns a C string which gives a pointer which can be - read from or written to at will (it is an expression so caller should - store it in a temporary if it is used more than once). - - As the bounds checking can have any number of combinations of unsigned - arguments, smart optimizations etc. we insert it directly in the function - body. The lookup however is delegated to a inline function that is instantiated - once per ndim (lookup with suboffsets tend to get quite complicated). - - entry is a BufferEntry - """ - negative_indices = directives['wraparound'] and negative_indices - - if directives['boundscheck']: - # Check bounds and fix negative indices. - # We allocate a temporary which is initialized to -1, meaning OK (!). - # If an error occurs, the temp is set to the index dimension the - # error is occurring at. - failed_dim_temp = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False) - code.putln("%s = -1;" % failed_dim_temp) - for dim, (signed, cname, shape) in enumerate(zip(index_signeds, index_cnames, entry.get_buf_shapevars())): - if signed != 0: - # not unsigned, deal with negative index - code.putln("if (%s < 0) {" % cname) - if negative_indices: - code.putln("%s += %s;" % (cname, shape)) - code.putln("if (%s) %s = %d;" % ( - code.unlikely("%s < 0" % cname), - failed_dim_temp, dim)) - else: - code.putln("%s = %d;" % (failed_dim_temp, dim)) - code.put("} else ") - # check bounds in positive direction - if signed != 0: - cast = "" - else: - cast = "(size_t)" - code.putln("if (%s) %s = %d;" % ( - code.unlikely("%s >= %s%s" % (cname, cast, shape)), - failed_dim_temp, dim)) - - if in_nogil_context: - code.globalstate.use_utility_code(raise_indexerror_nogil) - func = '__Pyx_RaiseBufferIndexErrorNogil' - else: - code.globalstate.use_utility_code(raise_indexerror_code) - func = '__Pyx_RaiseBufferIndexError' - - code.putln("if (%s) {" % code.unlikely("%s != -1" % failed_dim_temp)) - code.putln('%s(%s);' % (func, failed_dim_temp)) - code.putln(code.error_goto(pos)) - code.putln('}') - code.funcstate.release_temp(failed_dim_temp) - elif negative_indices: - # Only fix negative indices. - for signed, cname, shape in zip(index_signeds, index_cnames, entry.get_buf_shapevars()): - if signed != 0: - code.putln("if (%s < 0) %s += %s;" % (cname, cname, shape)) - - return entry.generate_buffer_lookup_code(code, index_cnames) - - -def use_bufstruct_declare_code(env): - env.use_utility_code(buffer_struct_declare_code) - - -def buf_lookup_full_code(proto, defin, name, nd): - """ - Generates a buffer lookup function for the right number - of dimensions. The function gives back a void* at the right location. - """ - # _i_ndex, _s_tride, sub_o_ffset - macroargs = ", ".join(["i%d, s%d, o%d" % (i, i, i) for i in range(nd)]) - proto.putln("#define %s(type, buf, %s) (type)(%s_imp(buf, %s))" % (name, macroargs, name, macroargs)) - - funcargs = ", ".join(["Py_ssize_t i%d, Py_ssize_t s%d, Py_ssize_t o%d" % (i, i, i) for i in range(nd)]) - proto.putln("static CYTHON_INLINE void* %s_imp(void* buf, %s);" % (name, funcargs)) - defin.putln(dedent(""" - static CYTHON_INLINE void* %s_imp(void* buf, %s) { - char* ptr = (char*)buf; - """) % (name, funcargs) + "".join([dedent("""\ - ptr += s%d * i%d; - if (o%d >= 0) ptr = *((char**)ptr) + o%d; - """) % (i, i, i, i) for i in range(nd)] - ) + "\nreturn ptr;\n}") - - -def buf_lookup_strided_code(proto, defin, name, nd): - """ - Generates a buffer lookup function for the right number - of dimensions. The function gives back a void* at the right location. - """ - # _i_ndex, _s_tride - args = ", ".join(["i%d, s%d" % (i, i) for i in range(nd)]) - offset = " + ".join(["i%d * s%d" % (i, i) for i in range(nd)]) - proto.putln("#define %s(type, buf, %s) (type)((char*)buf + %s)" % (name, args, offset)) - - -def buf_lookup_c_code(proto, defin, name, nd): - """ - Similar to strided lookup, but can assume that the last dimension - doesn't need a multiplication as long as. - Still we keep the same signature for now. - """ - if nd == 1: - proto.putln("#define %s(type, buf, i0, s0) ((type)buf + i0)" % name) - else: - args = ", ".join(["i%d, s%d" % (i, i) for i in range(nd)]) - offset = " + ".join(["i%d * s%d" % (i, i) for i in range(nd - 1)]) - proto.putln("#define %s(type, buf, %s) ((type)((char*)buf + %s) + i%d)" % (name, args, offset, nd - 1)) - - -def buf_lookup_fortran_code(proto, defin, name, nd): - """ - Like C lookup, but the first index is optimized instead. - """ - if nd == 1: - proto.putln("#define %s(type, buf, i0, s0) ((type)buf + i0)" % name) - else: - args = ", ".join(["i%d, s%d" % (i, i) for i in range(nd)]) - offset = " + ".join(["i%d * s%d" % (i, i) for i in range(1, nd)]) - proto.putln("#define %s(type, buf, %s) ((type)((char*)buf + %s) + i%d)" % (name, args, offset, 0)) - - -def use_py2_buffer_functions(env): - env.use_utility_code(GetAndReleaseBufferUtilityCode()) - - -class GetAndReleaseBufferUtilityCode(object): - # 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. - - requires = None - is_cython_utility = False - - def __init__(self): - pass - - def __eq__(self, other): - return isinstance(other, GetAndReleaseBufferUtilityCode) - - def __hash__(self): - return 24342342 - - def get_tree(self, **kwargs): pass - - def put_code(self, output): - code = output['utility_code_def'] - proto_code = output['utility_code_proto'] - env = output.module_node.scope - cython_scope = env.context.cython_scope - - # Search all types for __getbuffer__ overloads - types = [] - visited_scopes = set() - def find_buffer_types(scope): - if scope in visited_scopes: - return - visited_scopes.add(scope) - for m in scope.cimported_modules: - find_buffer_types(m) - for e in scope.type_entries: - if isinstance(e.utility_code_definition, CythonUtilityCode): - continue - t = e.type - if t.is_extension_type: - if scope is cython_scope and not e.used: - continue - release = get = None - for x in t.scope.pyfunc_entries: - if x.name == u"__getbuffer__": get = x.func_cname - elif x.name == u"__releasebuffer__": release = x.func_cname - if get: - types.append((t.typeptr_cname, get, release)) - - find_buffer_types(env) - - util_code = TempitaUtilityCode.load( - "GetAndReleaseBuffer", from_file="Buffer.c", - context=dict(types=types)) - - proto = util_code.format_code(util_code.proto) - impl = util_code.format_code( - util_code.inject_string_constants(util_code.impl, output)[1]) - - proto_code.putln(proto) - code.putln(impl) - - -def mangle_dtype_name(dtype): - # Use prefixes to separate user defined types from builtins - # (consider "typedef float unsigned_int") - if dtype.is_pyobject: - return "object" - elif dtype.is_ptr: - return "ptr" - else: - if dtype.is_typedef or dtype.is_struct_or_union: - prefix = "nn_" - else: - prefix = "" - return prefix + dtype.specialization_name() - -def get_type_information_cname(code, dtype, maxdepth=None): - """ - Output the run-time type information (__Pyx_TypeInfo) for given dtype, - and return the name of the type info struct. - - Structs with two floats of the same size are encoded as complex numbers. - One can separate between complex numbers declared as struct or with native - encoding by inspecting to see if the fields field of the type is - filled in. - """ - namesuffix = mangle_dtype_name(dtype) - name = "__Pyx_TypeInfo_%s" % namesuffix - structinfo_name = "__Pyx_StructFields_%s" % namesuffix - - if dtype.is_error: return "<error>" - - # It's critical that walking the type info doesn't use more stack - # depth than dtype.struct_nesting_depth() returns, so use an assertion for this - if maxdepth is None: maxdepth = dtype.struct_nesting_depth() - if maxdepth <= 0: - assert False - - if name not in code.globalstate.utility_codes: - code.globalstate.utility_codes.add(name) - typecode = code.globalstate['typeinfo'] - - arraysizes = [] - if dtype.is_array: - while dtype.is_array: - arraysizes.append(dtype.size) - dtype = dtype.base_type - - complex_possible = dtype.is_struct_or_union and dtype.can_be_complex() - - declcode = dtype.empty_declaration_code() - if dtype.is_simple_buffer_dtype(): - structinfo_name = "NULL" - elif dtype.is_struct: - struct_scope = dtype.scope - if dtype.is_const: - struct_scope = struct_scope.const_base_type_scope - # Must pre-call all used types in order not to recurse during utility code writing. - fields = struct_scope.var_entries - assert len(fields) > 0 - types = [get_type_information_cname(code, f.type, maxdepth - 1) - for f in fields] - typecode.putln("static __Pyx_StructField %s[] = {" % structinfo_name, safe=True) - for f, typeinfo in zip(fields, types): - typecode.putln(' {&%s, "%s", offsetof(%s, %s)},' % - (typeinfo, f.name, dtype.empty_declaration_code(), f.cname), safe=True) - typecode.putln(' {NULL, NULL, 0}', safe=True) - typecode.putln("};", safe=True) - else: - assert False - - rep = str(dtype) - - flags = "0" - is_unsigned = "0" - if dtype is PyrexTypes.c_char_type: - is_unsigned = "IS_UNSIGNED(%s)" % declcode - typegroup = "'H'" - elif dtype.is_int: - is_unsigned = "IS_UNSIGNED(%s)" % declcode - typegroup = "%s ? 'U' : 'I'" % is_unsigned - elif complex_possible or dtype.is_complex: - typegroup = "'C'" - elif dtype.is_float: - typegroup = "'R'" - elif dtype.is_struct: - typegroup = "'S'" - if dtype.packed: - flags = "__PYX_BUF_FLAGS_PACKED_STRUCT" - elif dtype.is_pyobject: - typegroup = "'O'" - else: - assert False, dtype - - typeinfo = ('static __Pyx_TypeInfo %s = ' - '{ "%s", %s, sizeof(%s), { %s }, %s, %s, %s, %s };') - tup = (name, rep, structinfo_name, declcode, - ', '.join([str(x) for x in arraysizes]) or '0', len(arraysizes), - typegroup, is_unsigned, flags) - typecode.putln(typeinfo % tup, safe=True) - - return name - -def load_buffer_utility(util_code_name, context=None, **kwargs): - if context is None: - return UtilityCode.load(util_code_name, "Buffer.c", **kwargs) - else: - return TempitaUtilityCode.load(util_code_name, "Buffer.c", context=context, **kwargs) - -context = dict(max_dims=Options.buffer_max_dims) -buffer_struct_declare_code = load_buffer_utility("BufferStructDeclare", context=context) -buffer_formats_declare_code = load_buffer_utility("BufferFormatStructs") - -# Utility function to set the right exception -# The caller should immediately goto_error -raise_indexerror_code = load_buffer_utility("BufferIndexError") -raise_indexerror_nogil = load_buffer_utility("BufferIndexErrorNogil") -raise_buffer_fallback_code = load_buffer_utility("BufferFallbackError") - -acquire_utility_code = load_buffer_utility("BufferGetAndValidate", context=context) -buffer_format_check_code = load_buffer_utility("BufferFormatCheck", context=context) - -# See utility code BufferFormatFromTypeInfo -_typeinfo_to_format_code = load_buffer_utility("TypeInfoToFormat") |