1 from Cython
.Compiler
.Visitor
import CythonTransform
2 from Cython
.Compiler
.ModuleNode
import ModuleNode
3 from Cython
.Compiler
.Errors
import CompileError
4 from Cython
.Compiler
.UtilityCode
import CythonUtilityCode
5 from Cython
.Compiler
.Code
import UtilityCode
, TempitaUtilityCode
7 from Cython
.Compiler
import Options
8 from Cython
.Compiler
import Interpreter
9 from Cython
.Compiler
import PyrexTypes
10 from Cython
.Compiler
import Naming
11 from Cython
.Compiler
import Symtab
14 def dedent(text
, reindent
=0):
15 from textwrap
import dedent
18 indent
= " " * reindent
19 text
= '\n'.join([indent
+ x
for x
in text
.split('\n')])
22 class IntroduceBufferAuxiliaryVars(CythonTransform
):
28 buffers_exists
= False
29 using_memoryview
= False
31 def __call__(self
, node
):
32 assert isinstance(node
, ModuleNode
)
34 result
= super(IntroduceBufferAuxiliaryVars
, self
).__call
__(node
)
35 if self
.buffers_exists
:
36 use_bufstruct_declare_code(node
.scope
)
37 use_py2_buffer_functions(node
.scope
)
38 node
.scope
.use_utility_code(empty_bufstruct_utility
)
44 # Basic operations for transforms
46 def handle_scope(self
, node
, scope
):
47 # For all buffers, insert extra variables in the scope.
48 # The variables are also accessible from the buffer_info
50 bufvars
= [entry
for name
, entry
51 in scope
.entries
.iteritems()
52 if entry
.type.is_buffer
]
54 bufvars
.sort(key
=lambda entry
: entry
.name
)
55 self
.buffers_exists
= True
57 memviewslicevars
= [entry
for name
, entry
58 in scope
.entries
.iteritems()
59 if entry
.type.is_memoryviewslice
]
60 if len(memviewslicevars
) > 0:
61 self
.buffers_exists
= True
64 for (name
, entry
) in scope
.entries
.iteritems():
65 if name
== 'memoryview' and isinstance(entry
.utility_code_definition
, CythonUtilityCode
):
66 self
.using_memoryview
= True
70 if isinstance(node
, ModuleNode
) and len(bufvars
) > 0:
71 # for now...note that pos is wrong
72 raise CompileError(node
.pos
, "Buffer vars not allowed in module scope")
74 if entry
.type.dtype
.is_ptr
:
75 raise CompileError(node
.pos
, "Buffers with pointer types not yet supported.")
79 if buftype
.ndim
> Options
.buffer_max_dims
:
80 raise CompileError(node
.pos
,
81 "Buffer ndims exceeds Options.buffer_max_dims = %d" % Options
.buffer_max_dims
)
82 if buftype
.ndim
> self
.max_ndim
:
83 self
.max_ndim
= buftype
.ndim
85 # Declare auxiliary vars
86 def decvar(type, prefix
):
87 cname
= scope
.mangle(prefix
, name
)
88 aux_var
= scope
.declare_var(name
=None, cname
=cname
,
89 type=type, pos
=node
.pos
)
91 aux_var
.used
= True # otherwise, NameNode will mark whether it is used
95 auxvars
= ((PyrexTypes
.c_pyx_buffer_nd_type
, Naming
.pybuffernd_prefix
),
96 (PyrexTypes
.c_pyx_buffer_type
, Naming
.pybufferstruct_prefix
))
97 pybuffernd
, rcbuffer
= [decvar(type, prefix
) for (type, prefix
) in auxvars
]
99 entry
.buffer_aux
= Symtab
.BufferAux(pybuffernd
, rcbuffer
)
101 scope
.buffer_entries
= bufvars
104 def visit_ModuleNode(self
, node
):
105 self
.handle_scope(node
, node
.scope
)
106 self
.visitchildren(node
)
109 def visit_FuncDefNode(self
, node
):
110 self
.handle_scope(node
, node
.local_scope
)
111 self
.visitchildren(node
)
117 buffer_options
= ("dtype", "ndim", "mode", "negative_indices", "cast") # ordered!
118 buffer_defaults
= {"ndim": 1, "mode": "full", "negative_indices": True, "cast": False}
119 buffer_positional_options_count
= 1 # anything beyond this needs keyword argument
121 ERR_BUF_OPTION_UNKNOWN
= '"%s" is not a buffer option'
122 ERR_BUF_TOO_MANY
= 'Too many buffer options'
123 ERR_BUF_DUP
= '"%s" buffer option already supplied'
124 ERR_BUF_MISSING
= '"%s" missing'
125 ERR_BUF_MODE
= 'Only allowed buffer modes are: "c", "fortran", "full", "strided" (as a compile-time string)'
126 ERR_BUF_NDIM
= 'ndim must be a non-negative integer'
127 ERR_BUF_DTYPE
= 'dtype must be "object", numeric type or a struct'
128 ERR_BUF_BOOL
= '"%s" must be a boolean'
130 def analyse_buffer_options(globalpos
, env
, posargs
, dictargs
, defaults
=None, need_complete
=True):
132 Must be called during type analysis, as analyse is called
133 on the dtype argument.
135 posargs and dictargs should consist of a list and a dict
136 of tuples (value, pos). Defaults should be a dict of values.
138 Returns a dict containing all the options a buffer can have and
139 its value (with the positions stripped).
142 defaults
= buffer_defaults
144 posargs
, dictargs
= Interpreter
.interpret_compiletime_options(posargs
, dictargs
, type_env
=env
, type_args
= (0,'dtype'))
146 if len(posargs
) > buffer_positional_options_count
:
147 raise CompileError(posargs
[-1][1], ERR_BUF_TOO_MANY
)
150 for name
, (value
, pos
) in dictargs
.iteritems():
151 if not name
in buffer_options
:
152 raise CompileError(pos
, ERR_BUF_OPTION_UNKNOWN
% name
)
153 options
[name
] = value
155 for name
, (value
, pos
) in zip(buffer_options
, posargs
):
156 if not name
in buffer_options
:
157 raise CompileError(pos
, ERR_BUF_OPTION_UNKNOWN
% name
)
159 raise CompileError(pos
, ERR_BUF_DUP
% name
)
160 options
[name
] = value
162 # Check that they are all there and copy defaults
163 for name
in buffer_options
:
164 if not name
in options
:
166 options
[name
] = defaults
[name
]
169 raise CompileError(globalpos
, ERR_BUF_MISSING
% name
)
171 dtype
= options
.get("dtype")
172 if dtype
and dtype
.is_extension_type
:
173 raise CompileError(globalpos
, ERR_BUF_DTYPE
)
175 ndim
= options
.get("ndim")
176 if ndim
and (not isinstance(ndim
, int) or ndim
< 0):
177 raise CompileError(globalpos
, ERR_BUF_NDIM
)
179 mode
= options
.get("mode")
180 if mode
and not (mode
in ('full', 'strided', 'c', 'fortran')):
181 raise CompileError(globalpos
, ERR_BUF_MODE
)
183 def assert_bool(name
):
184 x
= options
.get(name
)
185 if not isinstance(x
, bool):
186 raise CompileError(globalpos
, ERR_BUF_BOOL
% name
)
188 assert_bool('negative_indices')
198 class BufferEntry(object):
199 def __init__(self
, entry
):
201 self
.type = entry
.type
202 self
.cname
= entry
.buffer_aux
.buflocal_nd_var
.cname
203 self
.buf_ptr
= "%s.rcbuffer->pybuffer.buf" % self
.cname
204 self
.buf_ptr_type
= self
.entry
.type.buffer_ptr_type
206 def get_buf_suboffsetvars(self
):
207 return self
._for
_all
_ndim
("%s.diminfo[%d].suboffsets")
209 def get_buf_stridevars(self
):
210 return self
._for
_all
_ndim
("%s.diminfo[%d].strides")
212 def get_buf_shapevars(self
):
213 return self
._for
_all
_ndim
("%s.diminfo[%d].shape")
215 def _for_all_ndim(self
, s
):
216 return [s
% (self
.cname
, i
) for i
in range(self
.type.ndim
)]
218 def generate_buffer_lookup_code(self
, code
, index_cnames
):
219 # Create buffer lookup and return it
220 # This is done via utility macros/inline functions, which vary
221 # according to the access mode used.
224 mode
= self
.type.mode
226 for i
, s
, o
in zip(index_cnames
,
227 self
.get_buf_stridevars(),
228 self
.get_buf_suboffsetvars()):
232 funcname
= "__Pyx_BufPtrFull%dd" % nd
233 funcgen
= buf_lookup_full_code
235 if mode
== 'strided':
236 funcname
= "__Pyx_BufPtrStrided%dd" % nd
237 funcgen
= buf_lookup_strided_code
239 funcname
= "__Pyx_BufPtrCContig%dd" % nd
240 funcgen
= buf_lookup_c_code
241 elif mode
== 'fortran':
242 funcname
= "__Pyx_BufPtrFortranContig%dd" % nd
243 funcgen
= buf_lookup_fortran_code
246 for i
, s
in zip(index_cnames
, self
.get_buf_stridevars()):
250 # Make sure the utility code is available
251 if funcname
not in code
.globalstate
.utility_codes
:
252 code
.globalstate
.utility_codes
.add(funcname
)
253 protocode
= code
.globalstate
['utility_code_proto']
254 defcode
= code
.globalstate
['utility_code_def']
255 funcgen(protocode
, defcode
, name
=funcname
, nd
=nd
)
257 buf_ptr_type_code
= self
.buf_ptr_type
.declaration_code("")
258 ptrcode
= "%s(%s, %s, %s)" % (funcname
, buf_ptr_type_code
, self
.buf_ptr
,
263 def get_flags(buffer_aux
, buffer_type
):
264 flags
= 'PyBUF_FORMAT'
265 mode
= buffer_type
.mode
267 flags
+= '| PyBUF_INDIRECT'
268 elif mode
== 'strided':
269 flags
+= '| PyBUF_STRIDES'
271 flags
+= '| PyBUF_C_CONTIGUOUS'
272 elif mode
== 'fortran':
273 flags
+= '| PyBUF_F_CONTIGUOUS'
276 if buffer_aux
.writable_needed
: flags
+= "| PyBUF_WRITABLE"
279 def used_buffer_aux_vars(entry
):
280 buffer_aux
= entry
.buffer_aux
281 buffer_aux
.buflocal_nd_var
.used
= True
282 buffer_aux
.rcbuf_var
.used
= True
284 def put_unpack_buffer_aux_into_scope(buf_entry
, code
):
285 # Generate code to copy the needed struct info into local
287 buffer_aux
, mode
= buf_entry
.buffer_aux
, buf_entry
.type.mode
288 pybuffernd_struct
= buffer_aux
.buflocal_nd_var
.cname
290 fldnames
= ['strides', 'shape']
292 fldnames
.append('suboffsets')
295 for i
in range(buf_entry
.type.ndim
):
296 for fldname
in fldnames
:
297 ln
.append("%s.diminfo[%d].%s = %s.rcbuffer->pybuffer.%s[%d];" % \
298 (pybuffernd_struct
, i
, fldname
,
299 pybuffernd_struct
, fldname
, i
))
300 code
.putln(' '.join(ln
))
302 def put_init_vars(entry
, code
):
303 bufaux
= entry
.buffer_aux
304 pybuffernd_struct
= bufaux
.buflocal_nd_var
.cname
305 pybuffer_struct
= bufaux
.rcbuf_var
.cname
306 # init pybuffer_struct
307 code
.putln("%s.pybuffer.buf = NULL;" % pybuffer_struct
)
308 code
.putln("%s.refcount = 0;" % pybuffer_struct
)
309 # init the buffer object
310 # code.put_init_var_to_py_none(entry)
311 # init the pybuffernd_struct
312 code
.putln("%s.data = NULL;" % pybuffernd_struct
)
313 code
.putln("%s.rcbuffer = &%s;" % (pybuffernd_struct
, pybuffer_struct
))
315 def put_acquire_arg_buffer(entry
, code
, pos
):
316 code
.globalstate
.use_utility_code(acquire_utility_code
)
317 buffer_aux
= entry
.buffer_aux
318 getbuffer
= get_getbuffer_call(code
, entry
.cname
, buffer_aux
, entry
.type)
320 # Acquire any new buffer
322 code
.putln("__Pyx_BufFmt_StackElem __pyx_stack[%d];" % entry
.type.dtype
.struct_nesting_depth())
323 code
.putln(code
.error_goto_if("%s == -1" % getbuffer
, pos
))
325 # An exception raised in arg parsing cannot be catched, so no
326 # need to care about the buffer then.
327 put_unpack_buffer_aux_into_scope(entry
, code
)
329 def put_release_buffer_code(code
, entry
):
330 code
.globalstate
.use_utility_code(acquire_utility_code
)
331 code
.putln("__Pyx_SafeReleaseBuffer(&%s.rcbuffer->pybuffer);" % entry
.buffer_aux
.buflocal_nd_var
.cname
)
333 def get_getbuffer_call(code
, obj_cname
, buffer_aux
, buffer_type
):
334 ndim
= buffer_type
.ndim
335 cast
= int(buffer_type
.cast
)
336 flags
= get_flags(buffer_aux
, buffer_type
)
337 pybuffernd_struct
= buffer_aux
.buflocal_nd_var
.cname
339 dtype_typeinfo
= get_type_information_cname(code
, buffer_type
.dtype
)
341 return ("__Pyx_GetBufferAndValidate(&%(pybuffernd_struct)s.rcbuffer->pybuffer, "
342 "(PyObject*)%(obj_cname)s, &%(dtype_typeinfo)s, %(flags)s, %(ndim)d, "
343 "%(cast)d, __pyx_stack)" % locals())
345 def put_assign_to_buffer(lhs_cname
, rhs_cname
, buf_entry
,
346 is_initialized
, pos
, code
):
348 Generate code for reassigning a buffer variables. This only deals with getting
349 the buffer auxiliary structure and variables set up correctly, the assignment
350 itself and refcounting is the responsibility of the caller.
352 However, the assignment operation may throw an exception so that the reassignment
355 Depending on the circumstances there are two possible outcomes:
356 - Old buffer released, new acquired, rhs assigned to lhs
357 - Old buffer released, new acquired which fails, reaqcuire old lhs buffer
358 (which may or may not succeed).
361 buffer_aux
, buffer_type
= buf_entry
.buffer_aux
, buf_entry
.type
362 code
.globalstate
.use_utility_code(acquire_utility_code
)
363 pybuffernd_struct
= buffer_aux
.buflocal_nd_var
.cname
364 flags
= get_flags(buffer_aux
, buffer_type
)
366 code
.putln("{") # Set up necesarry stack for getbuffer
367 code
.putln("__Pyx_BufFmt_StackElem __pyx_stack[%d];" % buffer_type
.dtype
.struct_nesting_depth())
369 getbuffer
= get_getbuffer_call(code
, "%s", buffer_aux
, buffer_type
) # fill in object below
372 # Release any existing buffer
373 code
.putln('__Pyx_SafeReleaseBuffer(&%s.rcbuffer->pybuffer);' % pybuffernd_struct
)
375 retcode_cname
= code
.funcstate
.allocate_temp(PyrexTypes
.c_int_type
, manage_ref
=False)
376 code
.putln("%s = %s;" % (retcode_cname
, getbuffer
% rhs_cname
))
377 code
.putln('if (%s) {' % (code
.unlikely("%s < 0" % retcode_cname
)))
378 # If acquisition failed, attempt to reacquire the old buffer
379 # before raising the exception. A failure of reacquisition
380 # will cause the reacquisition exception to be reported, one
381 # can consider working around this later.
382 type, value
, tb
= [code
.funcstate
.allocate_temp(PyrexTypes
.py_object_type
, manage_ref
=False)
384 code
.putln('PyErr_Fetch(&%s, &%s, &%s);' % (type, value
, tb
))
385 code
.putln('if (%s) {' % code
.unlikely("%s == -1" % (getbuffer
% lhs_cname
)))
386 code
.putln('Py_XDECREF(%s); Py_XDECREF(%s); Py_XDECREF(%s);' % (type, value
, tb
)) # Do not refnanny these!
387 code
.globalstate
.use_utility_code(raise_buffer_fallback_code
)
388 code
.putln('__Pyx_RaiseBufferFallbackError();')
389 code
.putln('} else {')
390 code
.putln('PyErr_Restore(%s, %s, %s);' % (type, value
, tb
))
391 for t
in (type, value
, tb
):
392 code
.funcstate
.release_temp(t
)
396 put_unpack_buffer_aux_into_scope(buf_entry
, code
)
397 code
.putln(code
.error_goto_if_neg(retcode_cname
, pos
))
398 code
.funcstate
.release_temp(retcode_cname
)
400 # Our entry had no previous value, so set to None when acquisition fails.
401 # In this case, auxiliary vars should be set up right in initialization to a zero-buffer,
402 # so it suffices to set the buf field to NULL.
403 code
.putln('if (%s) {' % code
.unlikely("%s == -1" % (getbuffer
% rhs_cname
)))
404 code
.putln('%s = %s; __Pyx_INCREF(Py_None); %s.rcbuffer->pybuffer.buf = NULL;' %
406 PyrexTypes
.typecast(buffer_type
, PyrexTypes
.py_object_type
, "Py_None"),
408 code
.putln(code
.error_goto(pos
))
411 put_unpack_buffer_aux_into_scope(buf_entry
, code
)
414 code
.putln("}") # Release stack
416 def put_buffer_lookup_code(entry
, index_signeds
, index_cnames
, directives
,
417 pos
, code
, negative_indices
, in_nogil_context
):
419 Generates code to process indices and calculate an offset into
420 a buffer. Returns a C string which gives a pointer which can be
421 read from or written to at will (it is an expression so caller should
422 store it in a temporary if it is used more than once).
424 As the bounds checking can have any number of combinations of unsigned
425 arguments, smart optimizations etc. we insert it directly in the function
426 body. The lookup however is delegated to a inline function that is instantiated
427 once per ndim (lookup with suboffsets tend to get quite complicated).
429 entry is a BufferEntry
431 negative_indices
= directives
['wraparound'] and negative_indices
433 if directives
['boundscheck']:
434 # Check bounds and fix negative indices.
435 # We allocate a temporary which is initialized to -1, meaning OK (!).
436 # If an error occurs, the temp is set to the dimension index the
437 # error is occuring at.
438 tmp_cname
= code
.funcstate
.allocate_temp(PyrexTypes
.c_int_type
, manage_ref
=False)
439 code
.putln("%s = -1;" % tmp_cname
)
440 for dim
, (signed
, cname
, shape
) in enumerate(zip(index_signeds
, index_cnames
,
441 entry
.get_buf_shapevars())):
443 # not unsigned, deal with negative index
444 code
.putln("if (%s < 0) {" % cname
)
446 code
.putln("%s += %s;" % (cname
, shape
))
447 code
.putln("if (%s) %s = %d;" % (
448 code
.unlikely("%s < 0" % cname
), tmp_cname
, dim
))
450 code
.putln("%s = %d;" % (tmp_cname
, dim
))
452 # check bounds in positive direction
457 code
.putln("if (%s) %s = %d;" % (
458 code
.unlikely("%s >= %s%s" % (cname
, cast
, shape
)),
462 code
.globalstate
.use_utility_code(raise_indexerror_nogil
)
463 func
= '__Pyx_RaiseBufferIndexErrorNogil'
465 code
.globalstate
.use_utility_code(raise_indexerror_code
)
466 func
= '__Pyx_RaiseBufferIndexError'
468 code
.putln("if (%s) {" % code
.unlikely("%s != -1" % tmp_cname
))
469 code
.putln('%s(%s);' % (func
, tmp_cname
))
470 code
.putln(code
.error_goto(pos
))
472 code
.funcstate
.release_temp(tmp_cname
)
473 elif negative_indices
:
474 # Only fix negative indices.
475 for signed
, cname
, shape
in zip(index_signeds
, index_cnames
,
476 entry
.get_buf_shapevars()):
478 code
.putln("if (%s < 0) %s += %s;" % (cname
, cname
, shape
))
480 return entry
.generate_buffer_lookup_code(code
, index_cnames
)
483 def use_bufstruct_declare_code(env
):
484 env
.use_utility_code(buffer_struct_declare_code
)
487 def get_empty_bufstruct_code(max_ndim
):
489 static Py_ssize_t __Pyx_zeros[] = {%s};
490 static Py_ssize_t __Pyx_minusones[] = {%s};
491 """) % (", ".join(["0"] * max_ndim
), ", ".join(["-1"] * max_ndim
))
492 return UtilityCode(proto
=code
)
494 empty_bufstruct_utility
= get_empty_bufstruct_code(Options
.buffer_max_dims
)
496 def buf_lookup_full_code(proto
, defin
, name
, nd
):
498 Generates a buffer lookup function for the right number
499 of dimensions. The function gives back a void* at the right location.
501 # _i_ndex, _s_tride, sub_o_ffset
502 macroargs
= ", ".join(["i%d, s%d, o%d" % (i
, i
, i
) for i
in range(nd
)])
503 proto
.putln("#define %s(type, buf, %s) (type)(%s_imp(buf, %s))" % (name
, macroargs
, name
, macroargs
))
505 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
)])
506 proto
.putln("static CYTHON_INLINE void* %s_imp(void* buf, %s);" % (name
, funcargs
))
507 defin
.putln(dedent("""
508 static CYTHON_INLINE void* %s_imp(void* buf, %s) {
509 char* ptr = (char*)buf;
510 """) % (name
, funcargs
) + "".join([dedent("""\
512 if (o%d >= 0) ptr = *((char**)ptr) + o%d;
513 """) % (i
, i
, i
, i
) for i
in range(nd
)]
514 ) + "\nreturn ptr;\n}")
516 def buf_lookup_strided_code(proto
, defin
, name
, nd
):
518 Generates a buffer lookup function for the right number
519 of dimensions. The function gives back a void* at the right location.
522 args
= ", ".join(["i%d, s%d" % (i
, i
) for i
in range(nd
)])
523 offset
= " + ".join(["i%d * s%d" % (i
, i
) for i
in range(nd
)])
524 proto
.putln("#define %s(type, buf, %s) (type)((char*)buf + %s)" % (name
, args
, offset
))
526 def buf_lookup_c_code(proto
, defin
, name
, nd
):
528 Similar to strided lookup, but can assume that the last dimension
529 doesn't need a multiplication as long as.
530 Still we keep the same signature for now.
533 proto
.putln("#define %s(type, buf, i0, s0) ((type)buf + i0)" % name
)
535 args
= ", ".join(["i%d, s%d" % (i
, i
) for i
in range(nd
)])
536 offset
= " + ".join(["i%d * s%d" % (i
, i
) for i
in range(nd
- 1)])
537 proto
.putln("#define %s(type, buf, %s) ((type)((char*)buf + %s) + i%d)" % (name
, args
, offset
, nd
- 1))
539 def buf_lookup_fortran_code(proto
, defin
, name
, nd
):
541 Like C lookup, but the first index is optimized instead.
544 proto
.putln("#define %s(type, buf, i0, s0) ((type)buf + i0)" % name
)
546 args
= ", ".join(["i%d, s%d" % (i
, i
) for i
in range(nd
)])
547 offset
= " + ".join(["i%d * s%d" % (i
, i
) for i
in range(1, nd
)])
548 proto
.putln("#define %s(type, buf, %s) ((type)((char*)buf + %s) + i%d)" % (name
, args
, offset
, 0))
551 def use_py2_buffer_functions(env
):
552 env
.use_utility_code(GetAndReleaseBufferUtilityCode())
554 class GetAndReleaseBufferUtilityCode(object):
555 # Emulation of PyObject_GetBuffer and PyBuffer_Release for Python 2.
556 # For >= 2.6 we do double mode -- use the new buffer interface on objects
557 # which has the right tp_flags set, but emulation otherwise.
560 is_cython_utility
= False
565 def __eq__(self
, other
):
566 return isinstance(other
, GetAndReleaseBufferUtilityCode
)
571 def get_tree(self
): pass
573 def put_code(self
, output
):
574 code
= output
['utility_code_def']
575 proto_code
= output
['utility_code_proto']
576 env
= output
.module_node
.scope
577 cython_scope
= env
.context
.cython_scope
579 # Search all types for __getbuffer__ overloads
581 visited_scopes
= set()
582 def find_buffer_types(scope
):
583 if scope
in visited_scopes
:
585 visited_scopes
.add(scope
)
586 for m
in scope
.cimported_modules
:
588 for e
in scope
.type_entries
:
589 if isinstance(e
.utility_code_definition
, CythonUtilityCode
):
592 if t
.is_extension_type
:
593 if scope
is cython_scope
and not e
.used
:
596 for x
in t
.scope
.pyfunc_entries
:
597 if x
.name
== u
"__getbuffer__": get
= x
.func_cname
598 elif x
.name
== u
"__releasebuffer__": release
= x
.func_cname
600 types
.append((t
.typeptr_cname
, get
, release
))
602 find_buffer_types(env
)
604 util_code
= TempitaUtilityCode
.load(
605 "GetAndReleaseBuffer", from_file
="Buffer.c",
606 context
=dict(types
=types
))
608 proto
= util_code
.format_code(util_code
.proto
)
609 impl
= util_code
.format_code(
610 util_code
.inject_string_constants(util_code
.impl
, output
)[1])
612 proto_code
.putln(proto
)
616 def mangle_dtype_name(dtype
):
617 # Use prefixes to seperate user defined types from builtins
618 # (consider "typedef float unsigned_int")
619 if dtype
.is_pyobject
:
624 if dtype
.is_typedef
or dtype
.is_struct_or_union
:
628 type_decl
= dtype
.declaration_code("")
629 type_decl
= type_decl
.replace(" ", "_")
630 return prefix
+ type_decl
.replace("[", "_").replace("]", "_")
632 def get_type_information_cname(code
, dtype
, maxdepth
=None):
634 Output the run-time type information (__Pyx_TypeInfo) for given dtype,
635 and return the name of the type info struct.
637 Structs with two floats of the same size are encoded as complex numbers.
638 One can seperate between complex numbers declared as struct or with native
639 encoding by inspecting to see if the fields field of the type is
642 namesuffix
= mangle_dtype_name(dtype
)
643 name
= "__Pyx_TypeInfo_%s" % namesuffix
644 structinfo_name
= "__Pyx_StructFields_%s" % namesuffix
646 if dtype
.is_error
: return "<error>"
648 # It's critical that walking the type info doesn't use more stack
649 # depth than dtype.struct_nesting_depth() returns, so use an assertion for this
650 if maxdepth
is None: maxdepth
= dtype
.struct_nesting_depth()
654 if name
not in code
.globalstate
.utility_codes
:
655 code
.globalstate
.utility_codes
.add(name
)
656 typecode
= code
.globalstate
['typeinfo']
660 while dtype
.is_array
:
661 arraysizes
.append(dtype
.size
)
662 dtype
= dtype
.base_type
664 complex_possible
= dtype
.is_struct_or_union
and dtype
.can_be_complex()
666 declcode
= dtype
.declaration_code("")
667 if dtype
.is_simple_buffer_dtype():
668 structinfo_name
= "NULL"
669 elif dtype
.is_struct
:
670 fields
= dtype
.scope
.var_entries
671 # Must pre-call all used types in order not to recurse utility code
673 assert len(fields
) > 0
674 types
= [get_type_information_cname(code
, f
.type, maxdepth
- 1)
676 typecode
.putln("static __Pyx_StructField %s[] = {" % structinfo_name
, safe
=True)
677 for f
, typeinfo
in zip(fields
, types
):
678 typecode
.putln(' {&%s, "%s", offsetof(%s, %s)},' %
679 (typeinfo
, f
.name
, dtype
.declaration_code(""), f
.cname
), safe
=True)
680 typecode
.putln(' {NULL, NULL, 0}', safe
=True)
681 typecode
.putln("};", safe
=True)
689 if dtype
is PyrexTypes
.c_char_type
:
690 is_unsigned
= "IS_UNSIGNED(%s)" % declcode
693 is_unsigned
= "IS_UNSIGNED(%s)" % declcode
694 typegroup
= "%s ? 'U' : 'I'" % is_unsigned
695 elif complex_possible
or dtype
.is_complex
:
699 elif dtype
.is_struct
:
702 flags
= "__PYX_BUF_FLAGS_PACKED_STRUCT"
703 elif dtype
.is_pyobject
:
708 typeinfo
= ('static __Pyx_TypeInfo %s = '
709 '{ "%s", %s, sizeof(%s), { %s }, %s, %s, %s, %s };')
710 tup
= (name
, rep
, structinfo_name
, declcode
,
711 ', '.join([str(x
) for x
in arraysizes
]) or '0', len(arraysizes
),
712 typegroup
, is_unsigned
, flags
)
713 typecode
.putln(typeinfo
% tup
, safe
=True)
717 def load_buffer_utility(util_code_name
, context
=None, **kwargs
):
719 return UtilityCode
.load(util_code_name
, "Buffer.c", **kwargs
)
721 return TempitaUtilityCode
.load(util_code_name
, "Buffer.c", context
=context
, **kwargs
)
723 context
= dict(max_dims
=str(Options
.buffer_max_dims
))
724 buffer_struct_declare_code
= load_buffer_utility("BufferStructDeclare",
728 # Utility function to set the right exception
729 # The caller should immediately goto_error
730 raise_indexerror_code
= load_buffer_utility("BufferIndexError")
731 raise_indexerror_nogil
= load_buffer_utility("BufferIndexErrorNogil")
733 raise_buffer_fallback_code
= load_buffer_utility("BufferFallbackError")
734 buffer_structs_code
= load_buffer_utility(
735 "BufferFormatStructs", proto_block
='utility_code_proto_before_types')
736 acquire_utility_code
= load_buffer_utility("BufferFormatCheck",
738 requires
=[buffer_structs_code
])
740 # See utility code BufferFormatFromTypeInfo
741 _typeinfo_to_format_code
= load_buffer_utility("TypeInfoToFormat", context
={},
742 requires
=[buffer_structs_code
])
743 typeinfo_compare_code
= load_buffer_utility("TypeInfoCompare", context
={},
744 requires
=[buffer_structs_code
])