Commit 0527db06 authored by Robert Bradshaw's avatar Robert Bradshaw

Merge branch 'ctuple'

parents 28a78cb2 2c104e67
......@@ -47,6 +47,8 @@ Features added
* ``PySlice_*()`` C-API functions are available from the ``cpython.slice``
module.
* Anonymous C tuple types can be declared as (ctype1, ctype2, ...).
* Allow arrays of C++ classes.
Bugs fixed
......
......@@ -256,7 +256,7 @@ class BufferEntry(object):
defcode = code.globalstate['utility_code_def']
funcgen(protocode, defcode, name=funcname, nd=nd)
buf_ptr_type_code = self.buf_ptr_type.declaration_code("")
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
......@@ -627,7 +627,7 @@ def mangle_dtype_name(dtype):
prefix = "nn_"
else:
prefix = ""
type_decl = dtype.declaration_code("")
type_decl = dtype.empty_declaration_code()
type_decl = type_decl.replace(" ", "_")
return prefix + type_decl.replace("[", "_").replace("]", "_")
......@@ -665,7 +665,7 @@ def get_type_information_cname(code, dtype, maxdepth=None):
complex_possible = dtype.is_struct_or_union and dtype.can_be_complex()
declcode = dtype.declaration_code("")
declcode = dtype.empty_declaration_code()
if dtype.is_simple_buffer_dtype():
structinfo_name = "NULL"
elif dtype.is_struct:
......@@ -678,7 +678,7 @@ def get_type_information_cname(code, dtype, maxdepth=None):
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.declaration_code(""), f.cname), safe=True)
(typeinfo, f.name, dtype.empty_declaration_code(), f.cname), safe=True)
typecode.putln(' {NULL, NULL, 0}', safe=True)
typecode.putln("};", safe=True)
else:
......
......@@ -369,7 +369,7 @@ class UtilityCode(UtilityCodeBase):
def specialize(self, pyrex_type=None, **data):
# Dicts aren't hashable...
if pyrex_type is not None:
data['type'] = pyrex_type.declaration_code('')
data['type'] = pyrex_type.empty_declaration_code()
data['type_name'] = pyrex_type.specialization_name()
key = tuple(sorted(data.items()))
try:
......
This diff is collapsed.
......@@ -481,7 +481,7 @@ class FusedCFuncDefNode(StatListNode):
# self._dtype_name(dtype)))
decl_code.putln('ctypedef %s %s "%s"' % (dtype.resolve(),
self._dtype_name(dtype),
dtype.declaration_code("")))
dtype.empty_declaration_code()))
if buffer_type.dtype.is_int:
if str(dtype) not in seen_int_dtypes:
......@@ -729,7 +729,7 @@ class FusedCFuncDefNode(StatListNode):
if self.py_func:
args = [CloneNode(default) for default in defaults if default]
self.defaults_tuple = TupleNode(self.pos, args=args)
self.defaults_tuple = self.defaults_tuple.analyse_types(env, skip_children=True)
self.defaults_tuple = self.defaults_tuple.analyse_types(env, skip_children=True).coerce_to_pyobject(env)
self.defaults_tuple = ProxyNode(self.defaults_tuple)
self.code_object = ProxyNode(self.specialized_pycfuncs[0].code_object)
......
......@@ -237,7 +237,7 @@ class MemoryViewSliceBufferEntry(Buffer.BufferEntry):
def _generate_buffer_lookup_code(self, code, axes, cast_result=True):
bufp = self.buf_ptr
type_decl = self.type.dtype.declaration_code("")
type_decl = self.type.dtype.empty_declaration_code()
for dim, index, access, packing in axes:
shape = "%s.shape[%d]" % (self.cname, dim)
......@@ -467,7 +467,7 @@ def copy_broadcast_memview_src_to_dst(src, dst, code):
def get_1d_fill_scalar_func(type, code):
dtype = type.dtype
type_decl = dtype.declaration_code("")
type_decl = dtype.empty_declaration_code()
dtype_name = mangle_dtype_name(dtype)
context = dict(dtype_name=dtype_name, type_decl=type_decl)
......@@ -482,8 +482,8 @@ def assign_scalar(dst, scalar, code):
"""
verify_direct_dimensions(dst)
dtype = dst.type.dtype
type_decl = dtype.declaration_code("")
slice_decl = dst.type.declaration_code("")
type_decl = dtype.empty_declaration_code()
slice_decl = dst.type.empty_declaration_code()
code.begin_block()
code.putln("%s __pyx_temp_scalar = %s;" % (type_decl, scalar.result()))
......@@ -527,7 +527,7 @@ class ContigSliceIter(SliceIter):
code = self.code
code.begin_block()
type_decl = self.slice_type.dtype.declaration_code("")
type_decl = self.slice_type.dtype.empty_declaration_code()
total_size = ' * '.join("%s.shape[%d]" % (self.slice_temp, i)
for i in range(self.ndim))
......@@ -613,7 +613,7 @@ def get_copy_new_utility(pos, from_memview, to_memview):
context=dict(
context,
mode=mode,
dtype_decl=to_memview.dtype.declaration_code(''),
dtype_decl=to_memview.dtype.empty_declaration_code(),
contig_flag=contig_flag,
ndim=to_memview.ndim,
func_cname=copy_c_or_fortran_cname(to_memview),
......
......@@ -251,7 +251,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
% (entry.name, cname, sig))
for entry in api_vars:
cname = env.mangle(Naming.varptr_prefix, entry.name)
sig = entry.type.declaration_code("")
sig = entry.type.empty_declaration_code()
h_code.putln(
'if (__Pyx_ImportVoidPtr(module, "%s", (void **)&%s, "%s") < 0) goto bad;'
% (entry.name, cname, sig))
......@@ -721,6 +721,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
pass
elif type.is_struct_or_union or type.is_cpp_class:
self.generate_struct_union_predeclaration(entry, code)
elif type.is_ctuple and entry.used:
self.generate_struct_union_predeclaration(entry.type.struct_entry, code)
elif type.is_extension_type:
self.generate_objstruct_predeclaration(type, code)
# Actual declarations
......@@ -734,6 +736,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
self.generate_enum_definition(entry, code)
elif type.is_struct_or_union:
self.generate_struct_union_definition(entry, code)
elif type.is_ctuple and entry.used:
self.generate_struct_union_definition(entry.type.struct_entry, code)
elif type.is_cpp_class:
self.generate_cpp_class_definition(entry, code)
elif type.is_extension_type:
......@@ -776,7 +780,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
def generate_struct_union_predeclaration(self, entry, code):
type = entry.type
if type.is_cpp_class and type.templates:
code.putln("template <typename %s>" % ", typename ".join([T.declaration_code("") for T in type.templates]))
code.putln("template <typename %s>" % ", typename ".join([T.empty_declaration_code() for T in type.templates]))
code.putln(self.sue_predeclaration(type, type.kind, type.cname))
def sue_header_footer(self, type, kind, name):
......@@ -826,12 +830,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
scope = type.scope
if scope:
if type.templates:
code.putln("template <class %s>" % ", class ".join([T.declaration_code("") for T in type.templates]))
code.putln("template <class %s>" % ", class ".join([T.empty_declaration_code() for T in type.templates]))
# Just let everything be public.
code.put("struct %s" % type.cname)
if type.base_classes:
base_class_decl = ", public ".join(
[base_class.declaration_code("") for base_class in type.base_classes])
[base_class.empty_declaration_code() for base_class in type.base_classes])
code.put(" : public %s" % base_class_decl)
code.putln(" {")
has_virtual_methods = False
......@@ -1124,7 +1128,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln(
"%s = (%s)o;" % (
type.declaration_code("p"),
type.declaration_code("")))
type.empty_declaration_code()))
def generate_new_function(self, scope, code, cclass_entry):
tp_slot = TypeSlots.ConstructorSlot("tp_new", '__new__')
......@@ -1226,7 +1230,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
for entry in cpp_class_attrs:
code.putln("new((void*)&(p->%s)) %s();" %
(entry.cname, entry.type.declaration_code("")))
(entry.cname, entry.type.empty_declaration_code()))
for entry in py_attrs:
code.put_init_var_to_py_none(entry, "p->%s", nanny=False)
......@@ -2427,7 +2431,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
if entries:
env.use_utility_code(UtilityCode.load_cached("VoidPtrExport", "ImportExport.c"))
for entry in entries:
signature = entry.type.declaration_code("")
signature = entry.type.empty_declaration_code()
name = code.intern_identifier(entry.name)
code.putln('if (__Pyx_ExportVoidPtr(%s, (void *)&%s, "%s") < 0) %s' % (
name, entry.cname, signature,
......@@ -2495,7 +2499,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
cname = entry.cname
else:
cname = module.mangle(Naming.varptr_prefix, entry.name)
signature = entry.type.declaration_code("")
signature = entry.type.empty_declaration_code()
code.putln(
'if (__Pyx_ImportVoidPtr(%s, "%s", (void **)&%s, "%s") < 0) %s' % (
temp, entry.name, cname, signature,
......
This diff is collapsed.
......@@ -2593,7 +2593,7 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
constant_result=orig_index_type.signed and 1 or 0,
type=PyrexTypes.c_int_type),
ExprNodes.RawCNameExprNode(index.pos, PyrexTypes.c_void_type,
orig_index_type.declaration_code("")),
orig_index_type.empty_declaration_code()),
ExprNodes.RawCNameExprNode(index.pos, conversion_type, convert_func)],
may_return_none=True,
is_temp=node.is_temp,
......
......@@ -2038,9 +2038,21 @@ def p_c_complex_base_type(s, templates = None):
s.next()
base_type = p_c_base_type(s, templates = templates)
declarator = p_c_declarator(s, empty = 1)
s.expect(')')
type_node = Nodes.CComplexBaseTypeNode(pos,
base_type = base_type, declarator = declarator)
if s.sy == ',':
components = [type_node]
while s.sy == ',':
s.next()
if s.sy == ')':
break
base_type = p_c_base_type(s, templates = templates)
declarator = p_c_declarator(s, empty = 1)
components.append(Nodes.CComplexBaseTypeNode(pos,
base_type = base_type, declarator = declarator))
type_node = Nodes.CTupleBaseTypeNode(pos, components = components)
s.expect(')')
if s.sy == '[':
if is_memoryviewslice_access(s):
type_node = p_memoryviewslice_access(s, type_node)
......
This diff is collapsed.
......@@ -606,6 +606,9 @@ class Scope(object):
self.sue_entries.append(entry)
return entry
def declare_tuple_type(self, pos, type):
return self.outer_scope.declare_tuple_type(pos, type)
def declare_var(self, name, type, pos,
cname = None, visibility = 'private',
api = 0, in_pxd = 0, is_cdef = 0):
......@@ -1061,6 +1064,18 @@ class ModuleScope(Scope):
return self.outer_scope.lookup(name, language_level=language_level)
def declare_tuple_type(self, pos, type):
cname = type.cname
if not self.lookup_here(cname):
scope = StructOrUnionScope(cname)
for ix, component in enumerate(type.components):
scope.declare_var(name="f%s" % ix, type=component, pos=pos)
struct_entry = self.declare_struct_or_union(cname + '_struct', 'struct', scope, typedef_flag=True, pos=pos, cname=cname)
self.type_entries.remove(struct_entry)
type.struct_entry = struct_entry
type.entry = self.declare_type(cname, type, pos, cname)
return type.entry
def declare_builtin(self, name, pos):
if not hasattr(builtins, name) \
and name not in Code.non_portable_builtins_map \
......@@ -2114,8 +2129,8 @@ class CppClassScope(Scope):
entry = self.declare(name, cname, type, pos, visibility)
entry.is_variable = 1
if type.is_cfunction and self.type:
if not self.type.templates or not any(T.is_fused for T in self.type.templates):
entry.func_cname = "%s::%s" % (self.type.declaration_code(""), cname)
if not self.type.get_fused_types:
entry.func_cname = "%s::%s" % (self.type.empty_declaration_code(), cname)
if name != "this" and (defining or name != "<init>"):
self.var_entries.append(entry)
if type.is_pyobject and not allow_pyobject:
......
......@@ -311,6 +311,55 @@ static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) {
}
/////////////// ToPyCTupleUtility.proto ///////////////
static PyObject* {{funcname}}({{struct_type_decl}});
/////////////// ToPyCTupleUtility ///////////////
static PyObject* {{funcname}}({{struct_type_decl}} value) {
PyObject* item = NULL;
PyObject* result = PyTuple_New({{size}});
if (!result) goto bad;
{{for ix, component in enumerate(components):}}
{{py:attr = "value.f%s" % ix}}
item = {{component.to_py_function}}({{attr}});
if (!item) goto bad;
PyTuple_SET_ITEM(result, {{ix}}, item);
{{endfor}}
return result;
bad:
Py_XDECREF(item);
Py_XDECREF(result);
return NULL;
}
/////////////// FromPyCTupleUtility.proto ///////////////
static {{struct_type_decl}} {{funcname}}(PyObject *);
/////////////// FromPyCTupleUtility ///////////////
static {{struct_type_decl}} {{funcname}}(PyObject * o) {
{{struct_type_decl}} result;
if (!PyTuple_Check(o) || PyTuple_GET_SIZE(o) != {{size}}) {
PyErr_Format(PyExc_TypeError, "Expected %.16s of size %.8d, got %.200s", "a tuple", {{size}}, Py_TYPE(o)->tp_name);
goto bad;
}
{{for ix, component in enumerate(components):}}
{{py:attr = "result.f%s" % ix}}
{{attr}} = {{component.from_py_function}}(PyTuple_GET_ITEM(o, {{ix}}));
if ({{component.error_condition(attr)}})
goto bad;
{{endfor}}
return result;
bad:
return result;
}
/////////////// ObjectAsUCS4.proto ///////////////
static CYTHON_INLINE Py_UCS4 __Pyx_PyObject_AsPy_UCS4(PyObject*);
......
......@@ -141,6 +141,24 @@ def test_ptr_literal_list_slice_end():
a[:5] = [1,2,3,4,5]
return (a[0], a[1], a[2], a[3], a[4])
def test_multiple_from_slice():
"""
>>> test_multiple_from_slice()
(5, 4, 3)
"""
cdef int *a = [6,5,4,3,2,1]
x, y, z = a[1:4]
return x, y, z
def test_slice_from_multiple():
"""
>>> test_slice_from_multiple()
(6, -1, -2, -3, 2, 1)
"""
cdef int *a = [6,5,4,3,2,1]
a[1:4] = -1, -2, -3
return a[0], a[1], a[2], a[3], a[4], a[5]
def test_literal_tuple():
"""
>>> test_literal_tuple()
......
import cython
def simple_convert(*o):
"""
>>> simple_convert(1, 2)
(1, 2.0)
>>> simple_convert(1)
Traceback (most recent call last):
...
TypeError: Expected a tuple of size 2, got tuple
>>> simple_convert(1, 2, 3)
Traceback (most recent call last):
...
TypeError: Expected a tuple of size 2, got tuple
"""
cdef (int, double) xy = o
return xy
def indexing((int, double) xy):
"""
>>> indexing((1, 2))
(2, 3.0)
"""
x = xy[0]
y = xy[1]
xy[0] = x + 1
xy[1] = y + 1
return xy
def unpacking((int, double) xy):
"""
>>> unpacking((1, 2))
(1, 2.0)
"""
x, y = xy
return x, y
cdef (int, double) side_effect((int, double) xy):
print "called with", xy
return xy
def unpacking_with_side_effect((int, double) xy):
"""
>>> unpacking_with_side_effect((1, 2))
called with (1, 2.0)
(1, 2.0)
"""
x, y = side_effect(xy)
return x, y
def packing_tuple(int x, double y):
"""
>>> packing_tuple(1, 2)
(1, 2.0)
"""
cdef (int, double) xy = (x, y)
return xy
def coerce_packing_tuple(int x, int y):
cdef (int, double) xy = (x, y)
"""
>>> coerce_packing_tuple(1, 2)
(1, 2.0)
"""
return xy
def c_types(int a, double b):
"""
>>> c_types(1, 2)
(1, 2.0)
"""
cdef int* a_ptr
cdef double* b_ptr
cdef (int*, double*) ab = (&a, &b)
a_ptr, b_ptr = ab
return a_ptr[0], b_ptr[0]
cdef (int, int*) cdef_ctuple_return_type(int x, int* x_ptr):
return x, x_ptr
def call_cdef_ctuple_return_type(int x):
"""
>>> call_cdef_ctuple_return_type(2)
(2, 2)
"""
cdef (int, int*) res = cdef_ctuple_return_type(x, &x)
return res[0], res[1][0]
cpdef (int, double) cpdef_ctuple_return_type(int x, double y):
"""
>>> cpdef_ctuple_return_type(1, 2)
(1, 2.0)
"""
return x, y
@cython.infer_types(True)
def test_type_inference():
"""
>>> test_type_inference()
"""
cdef int x = 1
cdef double y = 2
cdef object o = 3
xy = (x, y)
assert cython.typeof(xy) == "(int, double)", cython.typeof(xy)
xo = (x, o)
assert cython.typeof(xo) == "tuple object", cython.typeof(xo)
def test_equality((int, int) ab, (int, int) cd, (int, int) ef):
"""
>>> test_equality((1, 2), (3, 4), (5, 6))
True
>>> test_equality((1, 2), (3, 4), (3, 4))
True
>>> test_equality((3, 4), (3, 4), (3, 4))
False
"""
return ab < cd <= ef
def test_binop((int, int) ab, (double, double) cd):
"""
>>> test_binop((1, 2), (3, 4))
(1, 2, 3.0, 4.0)
"""
return ab + cd
def test_mul((int, int) ab, int c):
"""
>>> test_mul((1, 2), 3)
(1, 2, 1, 2, 1, 2)
"""
return ab * c
def test_unop((int, int) ab):
"""
>>> test_unop((1, 2))
True
"""
return not ab
......@@ -32,8 +32,10 @@ def simple():
assert typeof(u) == "unicode object", typeof(u)
L = [1,2,3]
assert typeof(L) == "list object", typeof(L)
t = (4,5,6)
t = (4,5,6,())
assert typeof(t) == "tuple object", typeof(t)
t2 = (4, 5.0, 6)
assert typeof(t2) == "(long, double, long)", typeof(t)
def builtin_types():
"""
......@@ -80,7 +82,7 @@ def slicing():
assert typeof(L1) == "list object", typeof(L1)
L2 = L[1:2:2]
assert typeof(L2) == "list object", typeof(L2)
t = (4,5,6)
t = (4,5,6,())
assert typeof(t) == "tuple object", typeof(t)
t1 = t[1:2]
assert typeof(t1) == "tuple object", typeof(t1)
......@@ -107,7 +109,7 @@ def indexing():
assert typeof(L) == "list object", typeof(L)
L1 = L[1]
assert typeof(L1) == "Python object", typeof(L1)
t = (4,5,6)
t = (4,5,())
assert typeof(t) == "tuple object", typeof(t)
t1 = t[1]
assert typeof(t1) == "long", typeof(t1)
......
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