1 2referents = [] # list "object descriptor -> python object" 3freelist = None 4 5def store(x): 6 "Store the object 'x' and returns a new object descriptor for it." 7 global freelist 8 p = freelist 9 if p is None: 10 p = len(referents) 11 referents.append(x) 12 else: 13 freelist = referents[p] 14 referents[p] = x 15 return p 16 17def discard(p): 18 """Discard (i.e. close) the object descriptor 'p'. 19 Return the original object that was attached to 'p'.""" 20 global freelist 21 x = referents[p] 22 referents[p] = freelist 23 freelist = p 24 return x 25 26class Ref(object): 27 """For use in 'with Ref(x) as ob': open an object descriptor 28 and returns it in 'ob', and close it automatically when the 29 'with' statement finishes.""" 30 def __init__(self, x): 31 self.x = x 32 def __enter__(self): 33 self.p = p = store(self.x) 34 return p 35 def __exit__(self, *args): 36 discard(self.p) 37 38def count_pyobj_alive(): 39 result = len(referents) 40 p = freelist 41 while p is not None: 42 assert result > 0 43 result -= 1 44 p = referents[p] 45 return result 46 47# ------------------------------------------------------------ 48 49if __name__ == '__main__': 50 import api 51 52 ffi = api.PythonFFI() 53 54 ffi.cdef(""" 55 typedef int pyobj_t; 56 int sum_integers(pyobj_t p_list); 57 pyobj_t sum_objects(pyobj_t p_list, pyobj_t p_initial); 58 """) 59 60 @ffi.pyexport("int(pyobj_t)") 61 def length(p_list): 62 list = referents[p_list] 63 return len(list) 64 65 @ffi.pyexport("int(pyobj_t, int)") 66 def getitem(p_list, index): 67 list = referents[p_list] 68 return list[index] 69 70 @ffi.pyexport("pyobj_t(pyobj_t)") 71 def pyobj_dup(p): 72 return store(referents[p]) 73 74 @ffi.pyexport("void(pyobj_t)") 75 def pyobj_close(p): 76 discard(p) 77 78 @ffi.pyexport("pyobj_t(pyobj_t, int)") 79 def pyobj_getitem(p_list, index): 80 list = referents[p_list] 81 return store(list[index]) 82 83 @ffi.pyexport("pyobj_t(pyobj_t, pyobj_t)") 84 def pyobj_add(p1, p2): 85 return store(referents[p1] + referents[p2]) 86 87 lib = ffi.verify(""" 88 typedef int pyobj_t; /* an "object descriptor" number */ 89 90 int sum_integers(pyobj_t p_list) { 91 /* this a demo function written in C, using the API 92 defined above: length() and getitem(). */ 93 int i, result = 0; 94 int count = length(p_list); 95 for (i=0; i<count; i++) { 96 int n = getitem(p_list, i); 97 result += n; 98 } 99 return result; 100 } 101 102 pyobj_t sum_objects(pyobj_t p_list, pyobj_t p_initial) { 103 /* same as above, but keeps all additions as Python objects */ 104 int i; 105 int count = length(p_list); 106 pyobj_t p1 = pyobj_dup(p_initial); 107 for (i=0; i<count; i++) { 108 pyobj_t p2 = pyobj_getitem(p_list, i); 109 pyobj_t p3 = pyobj_add(p1, p2); 110 pyobj_close(p2); 111 pyobj_close(p1); 112 p1 = p3; 113 } 114 return p1; 115 } 116 """) 117 118 with Ref([10, 20, 30, 40]) as p_list: 119 print lib.sum_integers(p_list) 120 with Ref(5) as p_initial: 121 result = discard(lib.sum_objects(p_list, p_initial)) 122 print result 123 124 assert count_pyobj_alive() == 0 125