• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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