1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
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
|