| 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 |