Commit 0a86ec8f authored by Dag Sverre Seljebotn's avatar Dag Sverre Seljebotn

Test case cleanup, small bugfix

parent 1b6b0e50
...@@ -116,13 +116,11 @@ def put_access(entry, index_types, index_cnames, tmp_cname, pos, code): ...@@ -116,13 +116,11 @@ def put_access(entry, index_types, index_cnames, tmp_cname, pos, code):
nonegs = True nonegs = True
if boundscheck: if boundscheck:
code.putln("%s = -1;" % tmp_cname) code.putln("%s = -1;" % tmp_cname)
code.putln("//HERE")
for idx, (type, cname, shape) in enumerate(zip(index_types, index_cnames, for idx, (type, cname, shape) in enumerate(zip(index_types, index_cnames,
bufaux.shapevars)): bufaux.shapevars)):
if type.signed != 0: if type.signed != 0:
nonegs = False nonegs = False
# not unsigned, deal with negative index # not unsigned, deal with negative index
if idx > 0: code.put("else ")
code.putln("if (%s < 0) {" % cname) code.putln("if (%s < 0) {" % cname)
code.putln("%s += %s;" % (cname, shape.cname)) code.putln("%s += %s;" % (cname, shape.cname))
if boundscheck: if boundscheck:
...@@ -138,12 +136,10 @@ def put_access(entry, index_types, index_cnames, tmp_cname, pos, code): ...@@ -138,12 +136,10 @@ def put_access(entry, index_types, index_cnames, tmp_cname, pos, code):
tmp_cname, idx)) tmp_cname, idx))
# if boundscheck or not nonegs: # if boundscheck or not nonegs:
# code.putln("}") # code.putln("}")
if boundscheck: if boundscheck:
code.put("if (%s) " % code.unlikely("%s != -1" % tmp_cname)) code.put("if (%s) " % code.unlikely("%s != -1" % tmp_cname))
code.begin_block() code.begin_block()
code.putln('PyErr_Format(PyExc_IndexError, ' + code.putln('__Pyx_BufferIndexError(%s);' % tmp_cname)
'"Index out of range (buffer lookup, axis %%d)", %s);' %
tmp_cname);
code.putln(code.error_goto(pos)) code.putln(code.error_goto(pos))
code.end_block() code.end_block()
...@@ -157,6 +153,19 @@ def put_access(entry, index_types, index_cnames, tmp_cname, pos, code): ...@@ -157,6 +153,19 @@ def put_access(entry, index_types, index_cnames, tmp_cname, pos, code):
return valuecode return valuecode
# Utility function to set the right exception
# The caller should immediately goto_error
buffer_boundsfail_error_utility_code = [
"""
static void __Pyx_BufferIndexError(int axis); /*proto*/
""","""
static void __Pyx_BufferIndexError(int axis) {
PyErr_Format(PyExc_IndexError,
"Out of bounds on buffer access (axis %d)", axis);
}
"""]
class PureCFuncNode(Node): class PureCFuncNode(Node):
child_attrs = [] child_attrs = []
...@@ -275,6 +284,7 @@ class IntroduceBufferAuxiliaryVars(CythonTransform): ...@@ -275,6 +284,7 @@ class IntroduceBufferAuxiliaryVars(CythonTransform):
self.scope = scope self.scope = scope
def visit_ModuleNode(self, node): def visit_ModuleNode(self, node):
node.scope.use_utility_code(buffer_boundsfail_error_utility_code)
self.handle_scope(node, node.scope) self.handle_scope(node, node.scope)
self.visitchildren(node) self.visitchildren(node)
return node return node
......
cimport __cython__ cimport __cython__
__doc__ = u""" __doc__ = u"""
>>> A = MockBuffer("i", range(10), label="A") >>> A = IntMockBuffer("A", range(6))
>>> B = MockBuffer("i", range(10), label="B") >>> B = IntMockBuffer("B", range(6))
>>> E = ErrorBuffer("E")
>>> acquire_release(A, B)
acquired A
released A
acquired B
released B
"""
__doc__ = u"""
>>> A = MockBuffer("i", range(10), label="A")
>>> B = MockBuffer("i", range(10), label="B")
>>> E = ErrorBuffer("E") >>> E = ErrorBuffer("E")
>>> acquire_release(A, B) >>> acquire_release(A, B)
...@@ -34,18 +22,18 @@ stats, so need to circumvent this. ...@@ -34,18 +22,18 @@ stats, so need to circumvent this.
acquired A acquired A
released A released A
>>> as_argument(MockBuffer("i", range(6)), 6) >>> as_argument(A, 6)
acquired acquired A
0 1 2 3 4 5 0 1 2 3 4 5
released released A
>>> as_argument_defval() >>> as_argument_defval()
acquired acquired default
0 1 2 3 4 5 0 1 2 3 4 5
released released default
>>> as_argument_defval(MockBuffer("i", range(6)), 6) >>> as_argument_defval(A, 6)
acquired acquired A
0 1 2 3 4 5 0 1 2 3 4 5
released released A
>>> cdef_assignment(A, 6) >>> cdef_assignment(A, 6)
acquired A acquired A
...@@ -63,60 +51,50 @@ stats, so need to circumvent this. ...@@ -63,60 +51,50 @@ stats, so need to circumvent this.
3 3
released A released A
>>> #printbuf_float(MockBuffer("f", [1.0, 1.25, 0.75, 1.0]), (4,)) >>> printbuf_float(FloatMockBuffer("F", [1.0, 1.25, 0.75, 1.0]), (4,))
acquired acquired F
1.0 1.25 0.75 1.0 1.0 1.25 0.75 1.0
released released F
>>> #C = MockBuffer("i", range(6), (2,3)), (2,3) >>> C = IntMockBuffer("C", range(6), (2,3))
>>> #printbuf_int_2d(C) >>> printbuf_int_2d(C, (2,3))
acquired acquired C
0 1 2 0 1 2
3 4 5 3 4 5
released released C
Check negative indexing: Check negative indexing:
>>> get_int_2d(C, 1, 1) >>> get_int_2d(C, 1, 1)
acquired C
released C
4 4
>>> get_int_2d(C, -1, 0) >>> get_int_2d(C, -1, 0)
acquired C
released C
3 3
>>> get_int_2d(C, -1, -2) >>> get_int_2d(C, -1, -2)
acquired C
released C
4 4
>>> get_int_2d(C, -2, -3) >>> get_int_2d(C, -2, -3)
acquired C
released C
0 0
Out-of-bounds errors: Out-of-bounds errors:
>>> get_int_2d(C, 2, 0) >>> get_int_2d(C, 2, 0)
Traceback (most recent call last): Traceback (most recent call last):
... ...
IndexError: on purpose IndexError: Out of bounds on buffer access (axis 0)
>>> get_int_2d(C, 0, -4)
Traceback (most recent call last):
...
IndexError: Out of bounds on buffer access (axis 1)
""" """
__sdfdoc__ = """
>>> printbuf_float(MockBuffer("f", [1.0, 1.25, 0.75, 1.0]), (4,))
acquired
1.0 1.25 0.75 1.0
released
"""
ctypedef char* (*write_func_ptr)(char*, object)
cdef char* write_float(char* buf, object value):
(<float*>buf)[0] = <float>value
return buf + sizeof(float)
cdef char* write_int(char* buf, object value):
(<int*>buf)[0] = <int>value
return buf + sizeof(int)
# long can hold a pointer on all target platforms,
# though really we should have a seperate typedef for this..
# TODO: Should create subclasses of MockBuffer instead.
typemap = {
'f': (sizeof(float), <unsigned long>&write_float),
'i': (sizeof(int), <unsigned long>&write_int)
}
cimport stdlib cimport stdlib
def acquire_release(o1, o2): def acquire_release(o1, o2):
...@@ -136,7 +114,7 @@ def as_argument(object[int] bufarg, int n): ...@@ -136,7 +114,7 @@ def as_argument(object[int] bufarg, int n):
print bufarg[i], print bufarg[i],
print print
def as_argument_defval(object[int] bufarg=MockBuffer('i', range(6)), int n=6): def as_argument_defval(object[int] bufarg=IntMockBuffer('default', range(6)), int n=6):
cdef int i cdef int i
for i in range(n): for i in range(n):
print bufarg[i], print bufarg[i],
...@@ -173,6 +151,9 @@ def printbuf_int_2d(o, shape): ...@@ -173,6 +151,9 @@ def printbuf_int_2d(o, shape):
for j in range(shape[1]): for j in range(shape[1]):
print buf[i, j], print buf[i, j],
print print
def get_int_2d(object[int, 2] buf, int i, int j):
return buf[i, j]
cdef class MockBuffer: cdef class MockBuffer:
cdef object format cdef object format
...@@ -180,15 +161,13 @@ cdef class MockBuffer: ...@@ -180,15 +161,13 @@ cdef class MockBuffer:
cdef int len, itemsize, ndim cdef int len, itemsize, ndim
cdef Py_ssize_t* strides cdef Py_ssize_t* strides
cdef Py_ssize_t* shape cdef Py_ssize_t* shape
cdef write_func_ptr wfunc
cdef object label, log cdef object label, log
def __init__(self, typechar, data, shape=None, strides=None, format=None, label=None): def __init__(self, label, data, shape=None, strides=None, format=None):
self.label = label self.label = label
self.log = "" self.log = ""
if format is None: format = "=%s" % typechar self.itemsize = self.get_itemsize()
self.itemsize, x = typemap[typechar] if format is None: format = self.get_default_format()
self.wfunc = <write_func_ptr><unsigned long>x
if shape is None: shape = (len(data),) if shape is None: shape = (len(data),)
if strides is None: if strides is None:
strides = [] strides = []
...@@ -203,7 +182,7 @@ cdef class MockBuffer: ...@@ -203,7 +182,7 @@ cdef class MockBuffer:
self.format = format self.format = format
self.len = len(data) * self.itemsize self.len = len(data) * self.itemsize
self.buffer = <char*>stdlib.malloc(self.len) self.buffer = <char*>stdlib.malloc(self.len)
self.fill_buffer(typechar, data) self.fill_buffer(data)
self.ndim = len(shape) self.ndim = len(shape)
self.strides = <Py_ssize_t*>stdlib.malloc(self.ndim * sizeof(Py_ssize_t)) self.strides = <Py_ssize_t*>stdlib.malloc(self.ndim * sizeof(Py_ssize_t))
for i, x in enumerate(strides): for i, x in enumerate(strides):
...@@ -211,9 +190,11 @@ cdef class MockBuffer: ...@@ -211,9 +190,11 @@ cdef class MockBuffer:
self.shape = <Py_ssize_t*>stdlib.malloc(self.ndim * sizeof(Py_ssize_t)) self.shape = <Py_ssize_t*>stdlib.malloc(self.ndim * sizeof(Py_ssize_t))
for i, x in enumerate(shape): for i, x in enumerate(shape):
self.shape[i] = x self.shape[i] = x
def __dealloc__(self):
stdlib.free(self.strides)
stdlib.free(self.shape)
def __getbuffer__(MockBuffer self, Py_buffer* buffer, int flags): def __getbuffer__(MockBuffer self, Py_buffer* buffer, int flags):
global log
if buffer is NULL: if buffer is NULL:
print u"locking!" print u"locking!"
return return
...@@ -227,28 +208,46 @@ cdef class MockBuffer: ...@@ -227,28 +208,46 @@ cdef class MockBuffer:
buffer.suboffsets = NULL buffer.suboffsets = NULL
buffer.itemsize = self.itemsize buffer.itemsize = self.itemsize
buffer.internal = NULL buffer.internal = NULL
msg = "acquired" msg = "acquired %s" % self.label
if self.label: msg += " " + self.label
print msg print msg
self.log += msg + "\n" self.log += msg + "\n"
def __releasebuffer__(MockBuffer self, Py_buffer* buffer): def __releasebuffer__(MockBuffer self, Py_buffer* buffer):
global log msg = "released %s" % self.label
msg = "released"
if self.label: msg += " " + self.label
print msg print msg
self.log += msg + "\n" self.log += msg + "\n"
cdef fill_buffer(self, typechar, object data): cdef fill_buffer(self, object data):
cdef char* it = self.buffer cdef char* it = self.buffer
for value in data: for value in data:
it = self.wfunc(it, value) self.write(it, value)
it += self.itemsize
def printlog(self): def printlog(self):
print self.log, print self.log,
def resetlog(self): def resetlog(self):
self.log = "" self.log = ""
cdef int write(self, char* buf, object value) except -1: raise Exception()
cdef get_itemsize(self):
print "ERROR, not subclassed", self.__class__
cdef get_default_format(self):
print "ERROR, not subclassed", self.__class__
cdef class FloatMockBuffer(MockBuffer):
cdef int write(self, char* buf, object value) except -1:
(<float*>buf)[0] = <float>value
return 0
cdef get_itemsize(self): return sizeof(float)
cdef get_default_format(self): return "=f"
cdef class IntMockBuffer(MockBuffer):
cdef int write(self, char* buf, object value) except -1:
(<int*>buf)[0] = <int>value
return 0
cdef get_itemsize(self): return sizeof(int)
cdef get_default_format(self): return "=i"
cdef class ErrorBuffer: cdef class ErrorBuffer:
cdef object label cdef object label
......
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