From: Dag Sverre Seljebotn Date: Fri, 25 Jul 2008 13:28:45 +0000 (+0200) Subject: Test case cleanup, small bugfix X-Git-Tag: 0.9.8.1~49^2~73 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=0a86ec8f57480a5cec689b2e6500705e0ddf4487;p=cython.git Test case cleanup, small bugfix --- diff --git a/Cython/Compiler/Buffer.py b/Cython/Compiler/Buffer.py index 3a742e44..9f318a68 100644 --- a/Cython/Compiler/Buffer.py +++ b/Cython/Compiler/Buffer.py @@ -116,13 +116,11 @@ def put_access(entry, index_types, index_cnames, tmp_cname, pos, code): nonegs = True if boundscheck: code.putln("%s = -1;" % tmp_cname) - code.putln("//HERE") for idx, (type, cname, shape) in enumerate(zip(index_types, index_cnames, bufaux.shapevars)): if type.signed != 0: nonegs = False # not unsigned, deal with negative index - if idx > 0: code.put("else ") code.putln("if (%s < 0) {" % cname) code.putln("%s += %s;" % (cname, shape.cname)) if boundscheck: @@ -138,12 +136,10 @@ def put_access(entry, index_types, index_cnames, tmp_cname, pos, code): tmp_cname, idx)) # if boundscheck or not nonegs: # code.putln("}") - if boundscheck: + if boundscheck: code.put("if (%s) " % code.unlikely("%s != -1" % tmp_cname)) code.begin_block() - code.putln('PyErr_Format(PyExc_IndexError, ' + - '"Index out of range (buffer lookup, axis %%d)", %s);' % - tmp_cname); + code.putln('__Pyx_BufferIndexError(%s);' % tmp_cname) code.putln(code.error_goto(pos)) code.end_block() @@ -157,6 +153,19 @@ def put_access(entry, index_types, index_cnames, tmp_cname, pos, code): 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): child_attrs = [] @@ -275,6 +284,7 @@ class IntroduceBufferAuxiliaryVars(CythonTransform): self.scope = scope def visit_ModuleNode(self, node): + node.scope.use_utility_code(buffer_boundsfail_error_utility_code) self.handle_scope(node, node.scope) self.visitchildren(node) return node diff --git a/tests/run/bufaccess.pyx b/tests/run/bufaccess.pyx index 949d15e9..a0bff648 100644 --- a/tests/run/bufaccess.pyx +++ b/tests/run/bufaccess.pyx @@ -1,20 +1,8 @@ cimport __cython__ __doc__ = u""" - >>> A = MockBuffer("i", range(10), label="A") - >>> B = MockBuffer("i", range(10), label="B") - >>> 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") + >>> A = IntMockBuffer("A", range(6)) + >>> B = IntMockBuffer("B", range(6)) >>> E = ErrorBuffer("E") >>> acquire_release(A, B) @@ -34,18 +22,18 @@ stats, so need to circumvent this. acquired A released A - >>> as_argument(MockBuffer("i", range(6)), 6) - acquired + >>> as_argument(A, 6) + acquired A 0 1 2 3 4 5 - released + released A >>> as_argument_defval() - acquired + acquired default 0 1 2 3 4 5 - released - >>> as_argument_defval(MockBuffer("i", range(6)), 6) - acquired + released default + >>> as_argument_defval(A, 6) + acquired A 0 1 2 3 4 5 - released + released A >>> cdef_assignment(A, 6) acquired A @@ -63,60 +51,50 @@ stats, so need to circumvent this. 3 released A - >>> #printbuf_float(MockBuffer("f", [1.0, 1.25, 0.75, 1.0]), (4,)) - acquired + >>> printbuf_float(FloatMockBuffer("F", [1.0, 1.25, 0.75, 1.0]), (4,)) + acquired F 1.0 1.25 0.75 1.0 - released + released F - >>> #C = MockBuffer("i", range(6), (2,3)), (2,3) - >>> #printbuf_int_2d(C) - acquired + >>> C = IntMockBuffer("C", range(6), (2,3)) + >>> printbuf_int_2d(C, (2,3)) + acquired C 0 1 2 3 4 5 - released + released C Check negative indexing: >>> get_int_2d(C, 1, 1) + acquired C + released C 4 >>> get_int_2d(C, -1, 0) + acquired C + released C 3 >>> get_int_2d(C, -1, -2) + acquired C + released C 4 >>> get_int_2d(C, -2, -3) + acquired C + released C 0 Out-of-bounds errors: >>> get_int_2d(C, 2, 0) 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): - (buf)[0] = value - return buf + sizeof(float) -cdef char* write_int(char* buf, object value): - (buf)[0] = 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), &write_float), - 'i': (sizeof(int), &write_int) -} - cimport stdlib def acquire_release(o1, o2): @@ -136,7 +114,7 @@ def as_argument(object[int] bufarg, int n): print bufarg[i], 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 for i in range(n): print bufarg[i], @@ -173,6 +151,9 @@ def printbuf_int_2d(o, shape): for j in range(shape[1]): print buf[i, j], print + +def get_int_2d(object[int, 2] buf, int i, int j): + return buf[i, j] cdef class MockBuffer: cdef object format @@ -180,15 +161,13 @@ cdef class MockBuffer: cdef int len, itemsize, ndim cdef Py_ssize_t* strides cdef Py_ssize_t* shape - cdef write_func_ptr wfunc 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.log = "" - if format is None: format = "=%s" % typechar - self.itemsize, x = typemap[typechar] - self.wfunc = x + self.itemsize = self.get_itemsize() + if format is None: format = self.get_default_format() if shape is None: shape = (len(data),) if strides is None: strides = [] @@ -203,7 +182,7 @@ cdef class MockBuffer: self.format = format self.len = len(data) * self.itemsize self.buffer = stdlib.malloc(self.len) - self.fill_buffer(typechar, data) + self.fill_buffer(data) self.ndim = len(shape) self.strides = stdlib.malloc(self.ndim * sizeof(Py_ssize_t)) for i, x in enumerate(strides): @@ -211,9 +190,11 @@ cdef class MockBuffer: self.shape = stdlib.malloc(self.ndim * sizeof(Py_ssize_t)) for i, x in enumerate(shape): self.shape[i] = x - + def __dealloc__(self): + stdlib.free(self.strides) + stdlib.free(self.shape) + def __getbuffer__(MockBuffer self, Py_buffer* buffer, int flags): - global log if buffer is NULL: print u"locking!" return @@ -227,28 +208,46 @@ cdef class MockBuffer: buffer.suboffsets = NULL buffer.itemsize = self.itemsize buffer.internal = NULL - msg = "acquired" - if self.label: msg += " " + self.label + msg = "acquired %s" % self.label print msg self.log += msg + "\n" def __releasebuffer__(MockBuffer self, Py_buffer* buffer): - global log - msg = "released" - if self.label: msg += " " + self.label + msg = "released %s" % self.label print msg self.log += msg + "\n" - cdef fill_buffer(self, typechar, object data): + cdef fill_buffer(self, object data): cdef char* it = self.buffer for value in data: - it = self.wfunc(it, value) + self.write(it, value) + it += self.itemsize def printlog(self): print self.log, def resetlog(self): 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: + (buf)[0] = 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: + (buf)[0] = value + return 0 + cdef get_itemsize(self): return sizeof(int) + cdef get_default_format(self): return "=i" cdef class ErrorBuffer: cdef object label