Commit 2cd11fd8 authored by Mark Florisson's avatar Mark Florisson

@cname for enum/struct in CythonUtilityCode + simple memslice indexing

parent 556722cb
...@@ -93,7 +93,7 @@ class IntroduceBufferAuxiliaryVars(CythonTransform): ...@@ -93,7 +93,7 @@ class IntroduceBufferAuxiliaryVars(CythonTransform):
return aux_var return aux_var
auxvars = ((PyrexTypes.c_pyx_buffer_nd_type, Naming.pybuffernd_prefix), auxvars = ((PyrexTypes.c_pyx_buffer_nd_type, Naming.pybuffernd_prefix),
(PyrexTypes.c_pyx_buffer_type, Naming.pybufferstruct_prefix)) (PyrexTypes.c_pyx_buffer_type, Naming.pybufferstruct_prefix))
pybuffernd, rcbuffer = [decvar(type, prefix) for (type, prefix) in auxvars] pybuffernd, rcbuffer = [decvar(type, prefix) for (type, prefix) in auxvars]
entry.buffer_aux = Symtab.BufferAux(pybuffernd, rcbuffer) entry.buffer_aux = Symtab.BufferAux(pybuffernd, rcbuffer)
...@@ -195,15 +195,26 @@ def analyse_buffer_options(globalpos, env, posargs, dictargs, defaults=None, nee ...@@ -195,15 +195,26 @@ def analyse_buffer_options(globalpos, env, posargs, dictargs, defaults=None, nee
# Code generation # Code generation
# #
def get_buf_suboffsetvars(entry): class BufferEntry(object):
return [("%s.diminfo[%d].suboffsets" % \ def __init__(self, entry):
(entry.buffer_aux.buflocal_nd_var.cname, i)) for i in range(entry.type.ndim)] self.entry = entry
def get_buf_stridevars(entry): self.type = entry.type
return [("%s.diminfo[%d].strides" % \ self.cname = entry.buffer_aux.buflocal_nd_var.cname
(entry.buffer_aux.buflocal_nd_var.cname, i)) for i in range(entry.type.ndim)] self.buf_ptr = "%s.rcbuffer->pybuffer.buf" % self.cname
def get_buf_shapevars(entry): self.buf_ptr_type = self.entry.type.buffer_ptr_type
return [("%s.diminfo[%d].shape" % \
(entry.buffer_aux.buflocal_nd_var.cname, i)) for i in range(entry.type.ndim)] 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 get_flags(buffer_aux, buffer_type): def get_flags(buffer_aux, buffer_type):
flags = 'PyBUF_FORMAT' flags = 'PyBUF_FORMAT'
...@@ -358,7 +369,8 @@ def put_assign_to_buffer(lhs_cname, rhs_cname, buf_entry, ...@@ -358,7 +369,8 @@ def put_assign_to_buffer(lhs_cname, rhs_cname, buf_entry,
code.putln("}") # Release stack code.putln("}") # Release stack
def put_buffer_lookup_code(entry, index_signeds, index_cnames, directives, pos, code): def put_buffer_lookup_code(entry, index_signeds, index_cnames, directives,
pos, code, negative_indices):
""" """
Generates code to process indices and calculate an offset into Generates code to process indices and calculate an offset into
a buffer. Returns a C string which gives a pointer which can be a buffer. Returns a C string which gives a pointer which can be
...@@ -370,11 +382,9 @@ def put_buffer_lookup_code(entry, index_signeds, index_cnames, directives, pos, ...@@ -370,11 +382,9 @@ def put_buffer_lookup_code(entry, index_signeds, index_cnames, directives, pos,
body. The lookup however is delegated to a inline function that is instantiated body. The lookup however is delegated to a inline function that is instantiated
once per ndim (lookup with suboffsets tend to get quite complicated). once per ndim (lookup with suboffsets tend to get quite complicated).
entry is a BufferEntry
""" """
bufaux = entry.buffer_aux negative_indices = directives['wraparound'] and negative_indices
pybuffernd_struct = bufaux.buflocal_nd_var.cname
# bufstruct = bufaux.buffer_info_var.cname
negative_indices = directives['wraparound'] and entry.type.negative_indices
if directives['boundscheck']: if directives['boundscheck']:
# Check bounds and fix negative indices. # Check bounds and fix negative indices.
...@@ -384,7 +394,7 @@ def put_buffer_lookup_code(entry, index_signeds, index_cnames, directives, pos, ...@@ -384,7 +394,7 @@ def put_buffer_lookup_code(entry, index_signeds, index_cnames, directives, pos,
tmp_cname = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False) tmp_cname = code.funcstate.allocate_temp(PyrexTypes.c_int_type, manage_ref=False)
code.putln("%s = -1;" % tmp_cname) code.putln("%s = -1;" % tmp_cname)
for dim, (signed, cname, shape) in enumerate(zip(index_signeds, index_cnames, for dim, (signed, cname, shape) in enumerate(zip(index_signeds, index_cnames,
get_buf_shapevars(entry))): entry.get_buf_shapevars())):
if signed != 0: if signed != 0:
# not unsigned, deal with negative index # not unsigned, deal with negative index
code.putln("if (%s < 0) {" % cname) code.putln("if (%s < 0) {" % cname)
...@@ -412,7 +422,7 @@ def put_buffer_lookup_code(entry, index_signeds, index_cnames, directives, pos, ...@@ -412,7 +422,7 @@ def put_buffer_lookup_code(entry, index_signeds, index_cnames, directives, pos,
elif negative_indices: elif negative_indices:
# Only fix negative indices. # Only fix negative indices.
for signed, cname, shape in zip(index_signeds, index_cnames, for signed, cname, shape in zip(index_signeds, index_cnames,
get_buf_shapevars(entry)): entry.get_buf_shapevars()):
if signed != 0: if signed != 0:
code.putln("if (%s < 0) %s += %s;" % (cname, cname, shape)) code.putln("if (%s < 0) %s += %s;" % (cname, cname, shape))
...@@ -423,7 +433,9 @@ def put_buffer_lookup_code(entry, index_signeds, index_cnames, directives, pos, ...@@ -423,7 +433,9 @@ def put_buffer_lookup_code(entry, index_signeds, index_cnames, directives, pos,
nd = entry.type.ndim nd = entry.type.ndim
mode = entry.type.mode mode = entry.type.mode
if mode == 'full': if mode == 'full':
for i, s, o in zip(index_cnames, get_buf_stridevars(entry), get_buf_suboffsetvars(entry)): for i, s, o in zip(index_cnames,
entry.get_buf_stridevars(),
entry.get_buf_suboffsetvars()):
params.append(i) params.append(i)
params.append(s) params.append(s)
params.append(o) params.append(o)
...@@ -441,7 +453,7 @@ def put_buffer_lookup_code(entry, index_signeds, index_cnames, directives, pos, ...@@ -441,7 +453,7 @@ def put_buffer_lookup_code(entry, index_signeds, index_cnames, directives, pos,
funcgen = buf_lookup_fortran_code funcgen = buf_lookup_fortran_code
else: else:
assert False assert False
for i, s in zip(index_cnames, get_buf_stridevars(entry)): for i, s in zip(index_cnames, entry.get_buf_stridevars()):
params.append(i) params.append(i)
params.append(s) params.append(s)
...@@ -452,11 +464,9 @@ def put_buffer_lookup_code(entry, index_signeds, index_cnames, directives, pos, ...@@ -452,11 +464,9 @@ def put_buffer_lookup_code(entry, index_signeds, index_cnames, directives, pos,
defcode = code.globalstate['utility_code_def'] defcode = code.globalstate['utility_code_def']
funcgen(protocode, defcode, name=funcname, nd=nd) funcgen(protocode, defcode, name=funcname, nd=nd)
ptr_type = entry.type.buffer_ptr_type buf_ptr_type_code = entry.buf_ptr_type.declaration_code("")
ptrcode = "%s(%s, %s.rcbuffer->pybuffer.buf, %s)" % (funcname, ptrcode = "%s(%s, %s, %s)" % (funcname, buf_ptr_type_code, entry.buf_ptr,
ptr_type.declaration_code(""), ", ".join(params))
pybuffernd_struct,
", ".join(params))
return ptrcode return ptrcode
......
...@@ -49,9 +49,15 @@ class UtilityCodeBase(object): ...@@ -49,9 +49,15 @@ class UtilityCodeBase(object):
_utility_cache = {} _utility_cache = {}
@classmethod @classmethod
def _add_utility(self, utility, type, lines, begin_lineno): def _add_utility(cls, utility, type, lines, begin_lineno):
if utility: if utility:
code = '\n' * begin_lineno + ''.join(lines) if cls.is_cython_utility:
# Don't forget our line number
code = '\n' * begin_lineno + ''.join(lines)
else:
# line numbers are not important here
code = '\n'.join(lines)
if type == 'Proto': if type == 'Proto':
utility[0] = code utility[0] = code
else: else:
...@@ -74,8 +80,6 @@ class UtilityCodeBase(object): ...@@ -74,8 +80,6 @@ class UtilityCodeBase(object):
comment = '//' comment = '//'
regex = r'%s\s*Utility(Proto|Code)\s*:\s*((\w|\.)+)\s*' % comment regex = r'%s\s*Utility(Proto|Code)\s*:\s*((\w|\.)+)\s*' % comment
flags = re.DOTALL
utilities = {} utilities = {}
lines = [] lines = []
......
...@@ -2209,6 +2209,10 @@ class IndexNode(ExprNode): ...@@ -2209,6 +2209,10 @@ class IndexNode(ExprNode):
subexprs = ['base', 'index', 'indices'] subexprs = ['base', 'index', 'indices']
indices = None indices = None
# Whether we're assigning to a buffer (in that case it needs to be
# writable)
writable_needed = False
def __init__(self, pos, index, *args, **kw): def __init__(self, pos, index, *args, **kw):
ExprNode.__init__(self, pos, index=index, *args, **kw) ExprNode.__init__(self, pos, index=index, *args, **kw)
self._index = index self._index = index
...@@ -2341,8 +2345,8 @@ class IndexNode(ExprNode): ...@@ -2341,8 +2345,8 @@ class IndexNode(ExprNode):
skip_child_analysis = False skip_child_analysis = False
buffer_access = False buffer_access = False
memoryviewslice_access = False # memoryviewslice_access = False
if self.base.type.is_buffer: if self.base.type.is_buffer or self.base.type.is_memoryviewslice:
if self.indices: if self.indices:
indices = self.indices indices = self.indices
else: else:
...@@ -2360,11 +2364,11 @@ class IndexNode(ExprNode): ...@@ -2360,11 +2364,11 @@ class IndexNode(ExprNode):
if buffer_access: if buffer_access:
assert hasattr(self.base, "entry") # Must be a NameNode-like node assert hasattr(self.base, "entry") # Must be a NameNode-like node
if self.base.type.is_memoryviewslice: # if self.base.type.is_memoryviewslice:
assert hasattr(self.base, "entry") # assert hasattr(self.base, "entry")
if self.indices or not isinstance(self.index, EllipsisNode): # if self.indices or not isinstance(self.index, EllipsisNode):
error(self.pos, "Memoryviews currently support ellipsis indexing only.") # error(self.pos, "Memoryviews currently support ellipsis indexing only.")
else: memoryviewslice_access = True # else: memoryviewslice_access = True
# On cloning, indices is cloned. Otherwise, unpack index into indices # On cloning, indices is cloned. Otherwise, unpack index into indices
assert not (buffer_access and isinstance(self.index, CloneNode)) assert not (buffer_access and isinstance(self.index, CloneNode))
...@@ -2382,13 +2386,15 @@ class IndexNode(ExprNode): ...@@ -2382,13 +2386,15 @@ class IndexNode(ExprNode):
if not self.base.entry.type.writable: if not self.base.entry.type.writable:
error(self.pos, "Writing to readonly buffer") error(self.pos, "Writing to readonly buffer")
else: else:
self.base.entry.buffer_aux.writable_needed = True self.writable_needed = True
if self.type.is_buffer:
self.base.entry.buffer_aux.writable_needed = True
elif memoryviewslice_access: # elif memoryviewslice_access:
self.type = self.base.type # self.type = self.base.type
self.is_memoryviewslice_access = True # self.is_memoryviewslice_access = True
if getting: # if getting:
error(self.pos, "memoryviews currently support setting only.") # error(self.pos, "memoryviews currently support setting only.")
else: else:
base_type = self.base.type base_type = self.base.type
...@@ -2680,18 +2686,30 @@ class IndexNode(ExprNode): ...@@ -2680,18 +2686,30 @@ class IndexNode(ExprNode):
def buffer_lookup_code(self, code): def buffer_lookup_code(self, code):
# Assign indices to temps # Assign indices to temps
index_temps = [code.funcstate.allocate_temp(i.type, manage_ref=False) for i in self.indices] index_temps = [code.funcstate.allocate_temp(i.type, manage_ref=False)
for i in self.indices]
for temp, index in zip(index_temps, self.indices): for temp, index in zip(index_temps, self.indices):
code.putln("%s = %s;" % (temp, index.result())) code.putln("%s = %s;" % (temp, index.result()))
# Generate buffer access code using these temps # Generate buffer access code using these temps
import Buffer import Buffer, MemoryView
# The above could happen because child_attrs is wrong somewhere so that # The above could happen because child_attrs is wrong somewhere so that
# options are not propagated. # options are not propagated.
return Buffer.put_buffer_lookup_code(entry=self.base.entry, entry = self.base.entry
if entry.type.is_buffer:
buffer_entry = Buffer.BufferEntry(entry)
negative_indices = entry.type.negative_indices
else:
buffer_entry = MemoryView.MemoryViewSliceBufferEntry(entry)
negative_indices = Buffer.buffer_defaults['negative_indices']
return Buffer.put_buffer_lookup_code(entry=buffer_entry,
index_signeds=[i.type.signed for i in self.indices], index_signeds=[i.type.signed for i in self.indices],
index_cnames=index_temps, index_cnames=index_temps,
directives=code.globalstate.directives, directives=code.globalstate.directives,
pos=self.pos, code=code) pos=self.pos, code=code,
negative_indices=negative_indices)
def put_nonecheck(self, code): def put_nonecheck(self, code):
code.globalstate.use_utility_code(raise_noneindex_error_utility_code) code.globalstate.use_utility_code(raise_noneindex_error_utility_code)
......
...@@ -6,7 +6,7 @@ from Code import UtilityCode ...@@ -6,7 +6,7 @@ from Code import UtilityCode
from UtilityCode import CythonUtilityCode from UtilityCode import CythonUtilityCode
from PyrexTypes import py_object_type, cython_memoryview_ptr_type from PyrexTypes import py_object_type, cython_memoryview_ptr_type
import Buffer import Buffer
import PyrexTypes
START_ERR = "there must be nothing or the value 0 (zero) in the start slot." START_ERR = "there must be nothing or the value 0 (zero) in the start slot."
STOP_ERR = "Axis specification only allowed in the 'stop' slot." STOP_ERR = "Axis specification only allowed in the 'stop' slot."
...@@ -112,7 +112,7 @@ def put_assign_to_memviewslice(lhs_cname, rhs_cname, memviewslicetype, pos, code ...@@ -112,7 +112,7 @@ def put_assign_to_memviewslice(lhs_cname, rhs_cname, memviewslicetype, pos, code
for i in range(ndim): for i in range(ndim):
code.putln("%s.shape[%d] = %s.shape[%d];" % (lhs_cname, i, rhs_cname, i)) code.putln("%s.shape[%d] = %s.shape[%d];" % (lhs_cname, i, rhs_cname, i))
code.putln("%s.strides[%d] = %s.strides[%d];" % (lhs_cname, i, rhs_cname, i)) code.putln("%s.strides[%d] = %s.strides[%d];" % (lhs_cname, i, rhs_cname, i))
code.putln("%s.suboffsets[%d] = %s.suboffsets[%d];" % (lhs_cname, i, rhs_cname, i)) # code.putln("%s.suboffsets[%d] = %s.suboffsets[%d];" % (lhs_cname, i, rhs_cname, i))
def get_buf_flag(specs): def get_buf_flag(specs):
is_c_contig, is_f_contig = is_cf_contig(specs) is_c_contig, is_f_contig = is_cf_contig(specs)
...@@ -173,6 +173,28 @@ def src_conforms_to_dst(src, dst): ...@@ -173,6 +173,28 @@ def src_conforms_to_dst(src, dst):
return True return True
class MemoryViewSliceBufferEntry(Buffer.BufferEntry):
def __init__(self, entry):
self.entry = entry
self.type = entry.type
self.cname = entry.cname
self.buf_ptr = "%s.data" % self.cname
dtype = self.entry.type.dtype
dtype = PyrexTypes.CPtrType(dtype)
self.buf_ptr_type = dtype
def get_buf_suboffsetvars(self):
return self._for_all_ndim("%s.memview->view.suboffsets[%d]")
def get_buf_stridevars(self):
return self._for_all_ndim("%s.strides[%d]")
def get_buf_shapevars(self):
return self._for_all_ndim("%s.shape[%d]")
def get_copy_func_name(to_memview): def get_copy_func_name(to_memview):
base = "__Pyx_BufferNew_%s_From_%s_%s" base = "__Pyx_BufferNew_%s_From_%s_%s"
if to_memview.is_c_contig: if to_memview.is_c_contig:
...@@ -245,7 +267,7 @@ static int %s(const __Pyx_memviewslice mvs) { ...@@ -245,7 +267,7 @@ static int %s(const __Pyx_memviewslice mvs) {
%(for_loop)s { %(for_loop)s {
#ifdef DEBUG #ifdef DEBUG
printf("mvs.suboffsets[i] %%d\\n", mvs.suboffsets[i]); /* printf("mvs.suboffsets[i] %%d\\n", mvs.suboffsets[i]); */
printf("mvs.strides[i] %%d\\n", mvs.strides[i]); printf("mvs.strides[i] %%d\\n", mvs.strides[i]);
printf("mvs.shape[i] %%d\\n", mvs.shape[i]); printf("mvs.shape[i] %%d\\n", mvs.shape[i]);
printf("size %%d\\n", size); printf("size %%d\\n", size);
...@@ -253,7 +275,7 @@ static int %s(const __Pyx_memviewslice mvs) { ...@@ -253,7 +275,7 @@ static int %s(const __Pyx_memviewslice mvs) {
#endif #endif
#undef DEBUG #undef DEBUG
if(mvs.suboffsets[i] >= 0) { if(mvs.memview->view.suboffsets[i] >= 0) {
return 0; return 0;
} }
if(size * itemsize != mvs.strides[i]) { if(size * itemsize != mvs.strides[i]) {
...@@ -595,6 +617,20 @@ def is_cf_contig(specs): ...@@ -595,6 +617,20 @@ def is_cf_contig(specs):
return is_c_contig, is_f_contig return is_c_contig, is_f_contig
def get_mode(specs):
is_c_contig, is_f_contig = is_cf_contig(specs)
if is_c_contig:
return 'c'
elif is_f_contig:
return 'fortran'
for access, packing in specs:
if access in ('ptr', 'full'):
return 'full'
return 'strided'
def validate_axes_specs(pos, specs): def validate_axes_specs(pos, specs):
packing_specs = ('contig', 'strided', 'follow') packing_specs = ('contig', 'strided', 'follow')
...@@ -622,7 +658,6 @@ def validate_axes_specs(pos, specs): ...@@ -622,7 +658,6 @@ def validate_axes_specs(pos, specs):
if not (is_c_contig or is_f_contig): if not (is_c_contig or is_f_contig):
raise CompileError(pos, "Invalid use of the follow specifier.") raise CompileError(pos, "Invalid use of the follow specifier.")
def _get_resolved_spec(env, spec): def _get_resolved_spec(env, spec):
# spec must be a NameNode or an AttributeNode # spec must be a NameNode or an AttributeNode
if isinstance(spec, NameNode): if isinstance(spec, NameNode):
...@@ -704,13 +739,13 @@ def load_memview_cy_utility(name, *args, **kwargs): ...@@ -704,13 +739,13 @@ def load_memview_cy_utility(name, *args, **kwargs):
def load_memview_c_utility(name, *args, **kwargs): def load_memview_c_utility(name, *args, **kwargs):
return UtilityCode.load_utility_from_file( return UtilityCode.load_utility_from_file(
"MemoryView.c", name, *args, **kwargs) "MemoryView_C.c", name, *args, **kwargs)
def load_memview_c_string(name): def load_memview_c_string(name):
return UtilityCode.load_utility_as_string("MemoryView.c", name) return UtilityCode.load_utility_as_string("MemoryView_C.c", name)
_, copy_template = UtilityCode.load_utility_as_string( _, copy_template = UtilityCode.load_utility_as_string(
"MemoryView.c", "MemviewSliceCopyTemplate") "MemoryView_C.c", "MemviewSliceCopyTemplate")
fmt_dict = { fmt_dict = {
'memview_struct_name': memview_objstruct_cname, 'memview_struct_name': memview_objstruct_cname,
......
...@@ -65,10 +65,21 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -65,10 +65,21 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
self.body.stats.extend(tree.stats) self.body.stats.extend(tree.stats)
else: else:
self.body.stats.append(tree) self.body.stats.append(tree)
selfscope = self.scope
selfscope.utility_code_list.extend(scope.utility_code_list) self.scope.utility_code_list.extend(scope.utility_code_list)
def extend_if_not_in(L1, L2):
for x in L2:
if x not in L1:
L1.append(x)
extend_if_not_in(self.scope.include_files, scope.include_files)
extend_if_not_in(self.scope.included_files, scope.included_files)
extend_if_not_in(self.scope.python_include_files,
scope.python_include_files)
if merge_scope: if merge_scope:
selfscope.merge_in(scope) self.scope.merge_in(scope)
def analyse_declarations(self, env): def analyse_declarations(self, env):
if Options.embed_pos_in_docstring: if Options.embed_pos_in_docstring:
......
...@@ -6977,11 +6977,15 @@ class CnameDecoratorNode(StatNode): ...@@ -6977,11 +6977,15 @@ class CnameDecoratorNode(StatNode):
self.node.analyse_declarations(env) self.node.analyse_declarations(env)
self.is_function = isinstance(self.node, FuncDefNode) self.is_function = isinstance(self.node, FuncDefNode)
is_struct_or_enum = isinstance(self.node, (CStructOrUnionDefNode,
CEnumDefNode))
e = self.node.entry e = self.node.entry
if self.is_function: if self.is_function:
e.cname = self.cname e.cname = self.cname
e.func_cname = self.cname e.func_cname = self.cname
elif is_struct_or_enum:
e.cname = e.type.cname = self.cname
else: else:
scope = self.node.scope scope = self.node.scope
......
...@@ -1255,7 +1255,7 @@ class CnameDirectivesTransform(CythonTransform, SkipDeclarations): ...@@ -1255,7 +1255,7 @@ class CnameDirectivesTransform(CythonTransform, SkipDeclarations):
""" """
def handle_function(self, node): def handle_function(self, node):
if not node.decorators: if not getattr(node, 'decorators', None):
return self.visit_Node(node) return self.visit_Node(node)
for i, decorator in enumerate(node.decorators): for i, decorator in enumerate(node.decorators):
...@@ -1289,6 +1289,8 @@ class CnameDirectivesTransform(CythonTransform, SkipDeclarations): ...@@ -1289,6 +1289,8 @@ class CnameDirectivesTransform(CythonTransform, SkipDeclarations):
visit_FuncDefNode = handle_function visit_FuncDefNode = handle_function
visit_CClassDefNode = handle_function visit_CClassDefNode = handle_function
visit_CEnumDefNode = handle_function
visit_CStructOrUnionDefNode = handle_function
class ForwardDeclareTypes(CythonTransform): class ForwardDeclareTypes(CythonTransform):
...@@ -1576,6 +1578,14 @@ if VALUE is not None: ...@@ -1576,6 +1578,14 @@ if VALUE is not None:
self.visitchildren(node) self.visitchildren(node)
return None return None
def visit_CnameDecoratorNode(self, node):
self.visitchildren(node)
if not node.node:
return None
return node
def create_Property(self, entry): def create_Property(self, entry):
if entry.visibility == 'public': if entry.visibility == 'public':
if entry.type.is_pyobject: if entry.type.is_pyobject:
......
...@@ -7,8 +7,8 @@ ctypedef object (*p_sub_expr_func)(object) ...@@ -7,8 +7,8 @@ ctypedef object (*p_sub_expr_func)(object)
# entry points # entry points
cpdef p_module(PyrexScanner s, pxd, full_module_name) cpdef p_module(PyrexScanner s, pxd, full_module_name, ctx=*)
cpdef p_code(PyrexScanner s, level= *) cpdef p_code(PyrexScanner s, level= *, ctx=*)
# internal parser states # internal parser states
......
...@@ -33,6 +33,7 @@ class Ctx(object): ...@@ -33,6 +33,7 @@ class Ctx(object):
nogil = 0 nogil = 0
namespace = None namespace = None
templates = None templates = None
allow_struct_enum_decorator = False
def __init__(self, **kwds): def __init__(self, **kwds):
self.__dict__.update(kwds) self.__dict__.update(kwds)
...@@ -1754,7 +1755,8 @@ def p_statement(s, ctx, first_statement = 0): ...@@ -1754,7 +1755,8 @@ def p_statement(s, ctx, first_statement = 0):
s.error('decorator not allowed here') s.error('decorator not allowed here')
s.level = ctx.level s.level = ctx.level
decorators = p_decorators(s) decorators = p_decorators(s)
if s.sy not in ('def', 'cdef', 'cpdef', 'class'): bad_toks = 'def', 'cdef', 'cpdef', 'class'
if not ctx.allow_struct_enum_decorator and s.sy not in bad_toks:
s.error("Decorators can only be followed by functions or classes") s.error("Decorators can only be followed by functions or classes")
elif s.sy == 'pass' and cdef_flag: elif s.sy == 'pass' and cdef_flag:
# empty cdef block # empty cdef block
...@@ -1774,7 +1776,10 @@ def p_statement(s, ctx, first_statement = 0): ...@@ -1774,7 +1776,10 @@ def p_statement(s, ctx, first_statement = 0):
s.level = ctx.level s.level = ctx.level
node = p_cdef_statement(s, ctx(overridable = overridable)) node = p_cdef_statement(s, ctx(overridable = overridable))
if decorators is not None: if decorators is not None:
if not isinstance(node, (Nodes.CFuncDefNode, Nodes.CVarDefNode, Nodes.CClassDefNode)): tup = Nodes.CFuncDefNode, Nodes.CVarDefNode, Nodes.CClassDefNode
if ctx.allow_struct_enum_decorator:
tup += Nodes.CStructOrUnionDefNode, Nodes.CEnumDefNode
if not isinstance(node, tup):
s.error("Decorators can only be followed by functions or classes") s.error("Decorators can only be followed by functions or classes")
node.decorators = decorators node.decorators = decorators
return node return node
...@@ -2892,8 +2897,8 @@ def p_doc_string(s): ...@@ -2892,8 +2897,8 @@ def p_doc_string(s):
else: else:
return None return None
def p_code(s, level=None): def p_code(s, level=None, ctx=Ctx):
body = p_statement_list(s, Ctx(level = level), first_statement = 1) body = p_statement_list(s, ctx(level = level), first_statement = 1)
if s.sy != 'EOF': if s.sy != 'EOF':
s.error("Syntax error in statement [%s,%s]" % ( s.error("Syntax error in statement [%s,%s]" % (
repr(s.sy), repr(s.systring))) repr(s.sy), repr(s.systring)))
...@@ -2915,7 +2920,7 @@ def p_compiler_directive_comments(s): ...@@ -2915,7 +2920,7 @@ def p_compiler_directive_comments(s):
s.next() s.next()
return result return result
def p_module(s, pxd, full_module_name): def p_module(s, pxd, full_module_name, ctx=Ctx):
pos = s.position() pos = s.position()
directive_comments = p_compiler_directive_comments(s) directive_comments = p_compiler_directive_comments(s)
...@@ -2930,7 +2935,7 @@ def p_module(s, pxd, full_module_name): ...@@ -2930,7 +2935,7 @@ def p_module(s, pxd, full_module_name):
else: else:
level = 'module' level = 'module'
body = p_statement_list(s, Ctx(level = level), first_statement = 1) body = p_statement_list(s, ctx(level=level), first_statement = 1)
if s.sy != 'EOF': if s.sy != 'EOF':
s.error("Syntax error in statement [%s,%s]" % ( s.error("Syntax error in statement [%s,%s]" % (
repr(s.sy), repr(s.systring))) repr(s.sy), repr(s.systring)))
......
...@@ -368,11 +368,14 @@ class MemoryViewSliceType(PyrexType): ...@@ -368,11 +368,14 @@ class MemoryViewSliceType(PyrexType):
self.dtype = base_dtype self.dtype = base_dtype
self.axes = axes self.axes = axes
self.ndim = len(axes)
import MemoryView import MemoryView
self.is_c_contig, self.is_f_contig = MemoryView.is_cf_contig(self.axes) self.is_c_contig, self.is_f_contig = MemoryView.is_cf_contig(self.axes)
assert not (self.is_c_contig and self.is_f_contig) assert not (self.is_c_contig and self.is_f_contig)
self.mode = MemoryView.get_mode(axes)
def same_as_resolved_type(self, other_type): def same_as_resolved_type(self, other_type):
return ((other_type.is_memoryviewslice and return ((other_type.is_memoryviewslice and
self.dtype.same_as(other_type.dtype) and self.dtype.same_as(other_type.dtype) and
......
...@@ -32,7 +32,7 @@ class StringParseContext(Main.Context): ...@@ -32,7 +32,7 @@ class StringParseContext(Main.Context):
return ModuleScope(module_name, parent_module = None, context = self) return ModuleScope(module_name, parent_module = None, context = self)
def parse_from_strings(name, code, pxds={}, level=None, initial_pos=None, def parse_from_strings(name, code, pxds={}, level=None, initial_pos=None,
context=None): context=None, allow_struct_enum_decorator=False):
""" """
Utility method to parse a (unicode) string of code. This is mostly Utility method to parse a (unicode) string of code. This is mostly
used for internal Cython compiler purposes (creating code snippets used for internal Cython compiler purposes (creating code snippets
...@@ -66,12 +66,15 @@ def parse_from_strings(name, code, pxds={}, level=None, initial_pos=None, ...@@ -66,12 +66,15 @@ def parse_from_strings(name, code, pxds={}, level=None, initial_pos=None,
scanner = PyrexScanner(buf, code_source, source_encoding = encoding, scanner = PyrexScanner(buf, code_source, source_encoding = encoding,
scope = scope, context = context, initial_pos = initial_pos) scope = scope, context = context, initial_pos = initial_pos)
ctx = Parsing.Ctx(allow_struct_enum_decorator=allow_struct_enum_decorator)
if level is None: if level is None:
tree = Parsing.p_module(scanner, 0, module_name) tree = Parsing.p_module(scanner, 0, module_name, ctx=ctx)
tree.scope = scope tree.scope = scope
tree.is_pxd = False tree.is_pxd = False
else: else:
tree = Parsing.p_code(scanner, level=level) tree = Parsing.p_code(scanner, level=level, ctx=ctx)
tree.scope = scope tree.scope = scope
return tree return tree
......
...@@ -86,7 +86,8 @@ class CythonUtilityCode(Code.UtilityCodeBase): ...@@ -86,7 +86,8 @@ class CythonUtilityCode(Code.UtilityCodeBase):
context = CythonUtilityCodeContext(self.name) context = CythonUtilityCodeContext(self.name)
context.prefix = self.prefix context.prefix = self.prefix
#context = StringParseContext(self.name) #context = StringParseContext(self.name)
tree = parse_from_strings(self.name, self.pyx, context=context) tree = parse_from_strings(self.name, self.pyx, context=context,
allow_struct_enum_decorator=True)
pipeline = Pipeline.create_pipeline(context, 'pyx', exclude_classes=excludes) pipeline = Pipeline.create_pipeline(context, 'pyx', exclude_classes=excludes)
if entries_only: if entries_only:
......
...@@ -11,6 +11,7 @@ cdef extern from "Python.h": ...@@ -11,6 +11,7 @@ cdef extern from "Python.h":
PyBUF_F_CONTIGUOUS, PyBUF_F_CONTIGUOUS,
PyBUF_ANY_CONTIGUOUS PyBUF_ANY_CONTIGUOUS
@cname("__pyx_array") @cname("__pyx_array")
cdef class array: cdef class array:
...@@ -87,10 +88,6 @@ cdef class array: ...@@ -87,10 +88,6 @@ cdef class array:
self.data = <char *>malloc(self.len) self.data = <char *>malloc(self.len)
if not self.data: if not self.data:
raise MemoryError("unable to allocate array data.") raise MemoryError("unable to allocate array data.")
else:
self.data = NULL
self.callback_free_data = NULL
def __getbuffer__(self, Py_buffer *info, int flags): def __getbuffer__(self, Py_buffer *info, int flags):
...@@ -139,6 +136,21 @@ cdef array array_cwrapper(tuple shape, Py_ssize_t itemsize, char *format, char * ...@@ -139,6 +136,21 @@ cdef array array_cwrapper(tuple shape, Py_ssize_t itemsize, char *format, char *
# UtilityCode: MemoryView # UtilityCode: MemoryView
# from cpython cimport ...
cdef extern from "pythread.h":
ctypedef void *PyThread_type_lock
PyThread_type_lock PyThread_allocate_lock()
void PyThread_free_lock(PyThread_type_lock)
int PyThread_acquire_lock(PyThread_type_lock, int mode) nogil
void PyThread_release_lock(PyThread_type_lock) nogil
cdef extern from *:
int __Pyx_GetBuffer(object, Py_buffer *, int)
void __Pyx_ReleaseBuffer(Py_buffer *)
@cname('__pyx_MemviewEnum') @cname('__pyx_MemviewEnum')
cdef class Enum(object): cdef class Enum(object):
cdef object name cdef object name
...@@ -147,6 +159,7 @@ cdef class Enum(object): ...@@ -147,6 +159,7 @@ cdef class Enum(object):
def __repr__(self): def __repr__(self):
return self.name return self.name
cdef strided = Enum("<strided axis packing mode>") cdef strided = Enum("<strided axis packing mode>")
cdef contig = Enum("<contig axis packing mode>") cdef contig = Enum("<contig axis packing mode>")
cdef follow = Enum("<follow axis packing mode>") cdef follow = Enum("<follow axis packing mode>")
...@@ -154,25 +167,29 @@ cdef direct = Enum("<direct axis access mode>") ...@@ -154,25 +167,29 @@ cdef direct = Enum("<direct axis access mode>")
cdef ptr = Enum("<ptr axis access mode>") cdef ptr = Enum("<ptr axis access mode>")
cdef full = Enum("<full axis access mode>") cdef full = Enum("<full axis access mode>")
cdef extern from *:
int __Pyx_GetBuffer(object, Py_buffer *, int)
void __Pyx_ReleaseBuffer(Py_buffer *)
@cname('__pyx_memoryview') @cname('__pyx_memoryview')
cdef class memoryview(object): cdef class memoryview(object):
cdef object obj cdef object obj
cdef Py_buffer view cdef Py_buffer view
cdef int gotbuf_flag cdef PyThread_type_lock acqcnt_lock
cdef int acquisition_count
def __cinit__(memoryview self, object obj, int flags): def __cinit__(memoryview self, object obj, int flags):
self.obj = obj self.obj = obj
__Pyx_GetBuffer(self.obj, &self.view, flags) #self.acqcnt_lock = PyThread_allocate_lock()
#if self.acqcnt_lock == NULL:
# raise MemoryError
__Pyx_GetBuffer(obj, &self.view, flags)
def __dealloc__(memoryview self): def __dealloc__(memoryview self):
#PyThread_free_lock(self.acqcnt_lock)
self.obj = None self.obj = None
__Pyx_ReleaseBuffer(&self.view) __Pyx_ReleaseBuffer(&self.view)
@cname('__pyx_memoryview_new') @cname('__pyx_memoryview_new')
cdef memoryview memoryview_cwrapper(object o, int flags): cdef memoryview memoryview_cwrapper(object o, int flags):
return memoryview(o, flags) return memoryview(o, flags)
...@@ -4,10 +4,11 @@ ...@@ -4,10 +4,11 @@
typedef struct { typedef struct {
struct %(memview_struct_name)s *memview; struct %(memview_struct_name)s *memview;
/* For convenience and faster access */
char *data; char *data;
Py_ssize_t shape[%(max_dims)d]; Py_ssize_t shape[%(max_dims)d];
Py_ssize_t strides[%(max_dims)d]; Py_ssize_t strides[%(max_dims)d];
Py_ssize_t suboffsets[%(max_dims)d]; /* Py_ssize_t suboffsets[%(max_dims)d]; */
} %(memviewslice_name)s; } %(memviewslice_name)s;
// UtilityProto: MemviewSliceInit // UtilityProto: MemviewSliceInit
...@@ -24,6 +25,8 @@ typedef struct { ...@@ -24,6 +25,8 @@ typedef struct {
#define __Pyx_IS_C_CONTIG 1 #define __Pyx_IS_C_CONTIG 1
#define __Pyx_IS_F_CONTIG 2 #define __Pyx_IS_F_CONTIG 2
/* #define __PYX_MEMSLICE_GETDATA(SLICE) ((char *) SLICE->memview->view->buf) */
static int __Pyx_ValidateAndInit_memviewslice(struct __pyx_memoryview_obj *memview, static int __Pyx_ValidateAndInit_memviewslice(struct __pyx_memoryview_obj *memview,
int *axes_specs, int c_or_f_flag, int ndim, __Pyx_TypeInfo *dtype, int *axes_specs, int c_or_f_flag, int ndim, __Pyx_TypeInfo *dtype,
__Pyx_BufFmt_StackElem stack[], __Pyx_memviewslice *memviewslice); __Pyx_BufFmt_StackElem stack[], __Pyx_memviewslice *memviewslice);
...@@ -40,7 +43,7 @@ static int __Pyx_ValidateAndInit_memviewslice( ...@@ -40,7 +43,7 @@ static int __Pyx_ValidateAndInit_memviewslice(
int *axes_specs, int *axes_specs,
int c_or_f_flag, int c_or_f_flag,
int ndim, int ndim,
__Pyx_TypeInfo *dtype, __Pyx_TypeInfo *dtype,
__Pyx_BufFmt_StackElem stack[], __Pyx_BufFmt_StackElem stack[],
__Pyx_memviewslice *memviewslice) { __Pyx_memviewslice *memviewslice) {
...@@ -191,11 +194,12 @@ static int __Pyx_init_memviewslice( ...@@ -191,11 +194,12 @@ static int __Pyx_init_memviewslice(
for(i=0; i<ndim; i++) { for(i=0; i<ndim; i++) {
memviewslice->strides[i] = buf->strides[i]; memviewslice->strides[i] = buf->strides[i];
memviewslice->shape[i] = buf->shape[i]; memviewslice->shape[i] = buf->shape[i];
/*
if(buf->suboffsets) { if(buf->suboffsets) {
memviewslice->suboffsets[i] = buf->suboffsets[i]; memviewslice->suboffsets[i] = buf->suboffsets[i];
} else { } else {
memviewslice->suboffsets[i] = -1; memviewslice->suboffsets[i] = -1;
} }*/
} }
__Pyx_INCREF((PyObject *)memview); __Pyx_INCREF((PyObject *)memview);
......
...@@ -55,3 +55,17 @@ def full_or_strided(): ...@@ -55,3 +55,17 @@ def full_or_strided():
cy.array(shape=(10,10), itemsize=sizeof(float), format='f', mode='c') cy.array(shape=(10,10), itemsize=sizeof(float), format='f', mode='c')
cdef object[long long int, ndim=3, mode='strided'] stridedbuf = \ cdef object[long long int, ndim=3, mode='strided'] stridedbuf = \
cy.array(shape=(1,2,3), itemsize=sizeof(long long int), format='q', mode='fortran') cy.array(shape=(1,2,3), itemsize=sizeof(long long int), format='q', mode='fortran')
def dont_allocate_buffer():
"""
>>> dont_allocate_buffer()
callback called 1
"""
cdef cy.array result = cy.array((10, 10), itemsize=sizeof(int), format='i', allocate_buffer=False)
assert result.data == NULL
result.data = <char *> 1
result.callback_free_data = callback
result = None
cdef void callback(char *data):
print "callback called %d" % <long> data
cimport cython
from cython cimport array
from libc.stdlib cimport malloc, free
def create_array(shape, mode='c'):
cdef array result = array(shape, itemsize=sizeof(int), format='i', mode=mode)
cdef int *data = <int *> result.data
cdef int i, j, value
for i in range(shape[0]):
for j in range(shape[1]):
value = i * shape[0] + j
if mode == 'fortran':
data[i + j * 10] = value
else:
data[value] = value
return result
def slice_contig_indexing():
"""
>>> slice_contig_indexing()
98
61
98
61
"""
cdef int[:, ::1] carr = create_array((14, 10))
cdef int[::1, :] farr = create_array((10, 14), mode='fortran')
print carr[9, 8]
print carr[6, 1]
print farr[9, 8]
print farr[6, 1]
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment