diff options
author | Anton Samokhvalov <pg83@yandex.ru> | 2022-02-10 16:45:17 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:17 +0300 |
commit | d3a398281c6fd1d3672036cb2d63f842d2cb28c5 (patch) | |
tree | dd4bd3ca0f36b817e96812825ffaf10d645803f2 /contrib/tools/cython/Cython/Compiler/Buffer.py | |
parent | 72cb13b4aff9bc9cf22e49251bc8fd143f82538f (diff) | |
download | ydb-d3a398281c6fd1d3672036cb2d63f842d2cb28c5.tar.gz |
Restoring authorship annotation for Anton Samokhvalov <pg83@yandex.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/tools/cython/Cython/Compiler/Buffer.py')
-rw-r--r-- | contrib/tools/cython/Cython/Compiler/Buffer.py | 1364 |
1 files changed, 682 insertions, 682 deletions
diff --git a/contrib/tools/cython/Cython/Compiler/Buffer.py b/contrib/tools/cython/Cython/Compiler/Buffer.py index 477c038c2e..c62a24f568 100644 --- a/contrib/tools/cython/Cython/Compiler/Buffer.py +++ b/contrib/tools/cython/Cython/Compiler/Buffer.py @@ -1,740 +1,740 @@ -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 +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 - + 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 - - + 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 + 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 - + + 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 = {} + + 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 + 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) - + 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("}") + 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) - + # 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) - + 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. + 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('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.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 (!). + 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;" % ( + 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: + 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)), + 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' - + + 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.putln(code.error_goto(pos)) + code.putln('}') code.funcstate.release_temp(failed_dim_temp) - elif negative_indices: - # Only fix negative indices. + 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 - + 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): + + 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 = "" + # (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. + +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() - + 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: + 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)},' % + 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) - + 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") - + +# 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 +# See utility code BufferFormatFromTypeInfo _typeinfo_to_format_code = load_buffer_utility("TypeInfoToFormat") |