| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- referents = [] # list "object descriptor -> python object"
- freelist = None
- def store(x):
- "Store the object 'x' and returns a new object descriptor for it."
- global freelist
- p = freelist
- if p is None:
- p = len(referents)
- referents.append(x)
- else:
- freelist = referents[p]
- referents[p] = x
- return p
- def discard(p):
- """Discard (i.e. close) the object descriptor 'p'.
- Return the original object that was attached to 'p'."""
- global freelist
- x = referents[p]
- referents[p] = freelist
- freelist = p
- return x
- class Ref(object):
- """For use in 'with Ref(x) as ob': open an object descriptor
- and returns it in 'ob', and close it automatically when the
- 'with' statement finishes."""
- def __init__(self, x):
- self.x = x
- def __enter__(self):
- self.p = p = store(self.x)
- return p
- def __exit__(self, *args):
- discard(self.p)
- def count_pyobj_alive():
- result = len(referents)
- p = freelist
- while p is not None:
- assert result > 0
- result -= 1
- p = referents[p]
- return result
- # ------------------------------------------------------------
- if __name__ == '__main__':
- import api
- ffi = api.PythonFFI()
- ffi.cdef("""
- typedef int pyobj_t;
- int sum_integers(pyobj_t p_list);
- pyobj_t sum_objects(pyobj_t p_list, pyobj_t p_initial);
- """)
- @ffi.pyexport("int(pyobj_t)")
- def length(p_list):
- list = referents[p_list]
- return len(list)
- @ffi.pyexport("int(pyobj_t, int)")
- def getitem(p_list, index):
- list = referents[p_list]
- return list[index]
- @ffi.pyexport("pyobj_t(pyobj_t)")
- def pyobj_dup(p):
- return store(referents[p])
- @ffi.pyexport("void(pyobj_t)")
- def pyobj_close(p):
- discard(p)
- @ffi.pyexport("pyobj_t(pyobj_t, int)")
- def pyobj_getitem(p_list, index):
- list = referents[p_list]
- return store(list[index])
- @ffi.pyexport("pyobj_t(pyobj_t, pyobj_t)")
- def pyobj_add(p1, p2):
- return store(referents[p1] + referents[p2])
- lib = ffi.verify("""
- typedef int pyobj_t; /* an "object descriptor" number */
- int sum_integers(pyobj_t p_list) {
- /* this a demo function written in C, using the API
- defined above: length() and getitem(). */
- int i, result = 0;
- int count = length(p_list);
- for (i=0; i<count; i++) {
- int n = getitem(p_list, i);
- result += n;
- }
- return result;
- }
- pyobj_t sum_objects(pyobj_t p_list, pyobj_t p_initial) {
- /* same as above, but keeps all additions as Python objects */
- int i;
- int count = length(p_list);
- pyobj_t p1 = pyobj_dup(p_initial);
- for (i=0; i<count; i++) {
- pyobj_t p2 = pyobj_getitem(p_list, i);
- pyobj_t p3 = pyobj_add(p1, p2);
- pyobj_close(p2);
- pyobj_close(p1);
- p1 = p3;
- }
- return p1;
- }
- """)
- with Ref([10, 20, 30, 40]) as p_list:
- print lib.sum_integers(p_list)
- with Ref(5) as p_initial:
- result = discard(lib.sum_objects(p_list, p_initial))
- print result
- assert count_pyobj_alive() == 0
|