You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

125 lines
3.3 KiB

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