pyobj.py 3.3 KB

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