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