bufaccess.pyx 4.63 KB
Newer Older
1 2 3
cimport __cython__

__doc__ = u"""
4 5 6
    >>> A = MockBuffer("i", range(10), label="A")
    >>> B = MockBuffer("i", range(10), label="B")
    >>> E = ErrorBuffer("E")
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
7
    
8 9 10 11 12
    >>> acquire_release(A, B)
    acquired A
    released A
    acquired B
    released B
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
13 14 15 16

    Apparently, doctest won't handle mixed exceptions and print
    stats, so need to circumvent this.
    >>> A.resetlog()
17 18 19 20
    >>> acquire_raise(A)
    Traceback (most recent call last):
        ...
    Exception: on purpose
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
21 22 23 24
    >>> A.printlog()
    acquired A
    released A
    
25 26 27 28
    >>> printbuf_float(MockBuffer("f", [1.0, 1.25, 0.75, 1.0]), (4,))
    acquired
    1.0 1.25 0.75 1.0
    released
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
29
    
30 31 32 33 34
    >>> printbuf_int_2d(MockBuffer("i", range(6), (2,3)), (2,3))
    acquired
    0 1 2
    3 4 5
    released
35 36
"""

Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
37

38 39 40 41
def acquire_release(o1, o2):
    cdef object[int] buf
    buf = o1
    buf = o2
42

43 44 45
def acquire_raise(o):
    cdef object[int] buf
    buf = o
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
46
    print "a"
47 48
    raise Exception("on purpose")
    
49 50
def printbuf_float(o, shape):
    # should make shape builtin
51 52 53 54 55 56 57 58 59 60 61
    cdef object[float] buf
    buf = o
    cdef int i, j
    for i in range(shape[0]):
        print buf[i],
    print
 

def printbuf_int_2d(o, shape):
    # should make shape builtin
    cdef object[int, 2] buf
62 63 64 65 66 67 68 69
    buf = o
    cdef int i, j
    for i in range(shape[0]):
        for j in range(shape[1]):
            print buf[i, j],
        print
 

70 71 72 73 74 75 76
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)
77

78 79 80 81 82 83 84
# 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)
}
85 86 87 88 89 90 91 92 93
 
cimport stdlib

cdef class MockBuffer:
    cdef object format
    cdef char* buffer
    cdef int len, itemsize, ndim
    cdef Py_ssize_t* strides
    cdef Py_ssize_t* shape
94
    cdef write_func_ptr wfunc
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
95
    cdef object label, log
96
    
97 98
    def __init__(self, typechar, data, shape=None, strides=None, format=None, label=None):
        self.label = label
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
99
        self.log = ""
100 101 102
        if format is None: format = "=%s" % typechar
        self.itemsize, x = typemap[typechar]
        self.wfunc = <write_func_ptr><unsigned long>x
103 104 105 106
        if shape is None: shape = (len(data),)
        if strides is None:
            strides = []
            cumprod = 1
107 108 109
            rshape = list(shape)
            rshape.reverse()
            for s in rshape:
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
                strides.append(cumprod)
                cumprod *= s
            strides.reverse()
        strides = [x * self.itemsize for x in strides]
        self.format = format
        self.len = len(data) * self.itemsize
        self.buffer = <char*>stdlib.malloc(self.len)
        self.fill_buffer(typechar, data)
        self.ndim = len(shape)
        self.strides = <Py_ssize_t*>stdlib.malloc(self.ndim * sizeof(Py_ssize_t))
        for i, x in enumerate(strides):
            self.strides[i] = x
        self.shape = <Py_ssize_t*>stdlib.malloc(self.ndim * sizeof(Py_ssize_t))

    def __getbuffer__(MockBuffer self, Py_buffer* buffer, int flags):
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
125
        global log
126 127 128 129 130 131 132 133 134 135 136 137 138
        if buffer is NULL:
            print u"locking!"
            return
        buffer.buf = self.buffer
        buffer.len = self.len
        buffer.readonly = 0
        buffer.format = <char*>self.format
        buffer.ndim = self.ndim
        buffer.shape = self.shape
        buffer.strides = self.strides
        buffer.suboffsets = NULL
        buffer.itemsize = self.itemsize
        buffer.internal = NULL
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
139 140 141 142
        msg = "acquired"
        if self.label: msg += " " + self.label
        print msg
        self.log += msg + "\n"
143 144

    def __releasebuffer__(MockBuffer self, Py_buffer* buffer):
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
145 146 147 148 149
        global log
        msg = "released"
        if self.label: msg += " " + self.label
        print msg
        self.log += msg + "\n"
150 151
        
    cdef fill_buffer(self, typechar, object data):
152
        cdef char* it = self.buffer
153
        for value in data:
154
            it = self.wfunc(it, value)
Dag Sverre Seljebotn's avatar
Dag Sverre Seljebotn committed
155 156 157 158 159 160

    def printlog(self):
        print self.log,

    def resetlog(self):
        self.log = ""
161
            
162 163 164 165 166 167 168 169 170 171 172
cdef class ErrorBuffer:
    cdef object label
    
    def __init__(self, label):
        self.label = label

    def __getbuffer__(MockBuffer self, Py_buffer* buffer, int flags):
        raise Exception("acquiring %s" % self.label)

    def __releasebuffer__(MockBuffer self, Py_buffer* buffer):
        raise Exception("releasing %s" % self.label)