-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathpytestclass.pyx
95 lines (67 loc) · 2.75 KB
/
pytestclass.pyx
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
# distutils: language = c++
# distutils: sources = testclass.cpp
from testclass cimport TestClass
cdef class PyTestClass:
"""
Cython wrapper class for C++ class TestClass
"""
cdef:
TestClass *_thisptr
def __cinit__(PyTestClass self):
# Initialize the "this pointer" to NULL so __dealloc__
# knows if there is something to deallocate. Do not
# call new TestClass() here.
self._thisptr = NULL
def __init__(PyTestClass self):
# Constructing the C++ object might raise std::bad_alloc
# which is automatically converted to a Python MemoryError
# by Cython. We therefore need to call "new TestClass()" in
# __init__ instead of __cinit__.
self._thisptr = new TestClass()
def __dealloc__(PyTestClass self):
# Only call del if the C++ object is alive,
# or we will get a segfault.
if self._thisptr != NULL:
del self._thisptr
cdef int _check_alive(PyTestClass self) except -1:
# Beacuse of the context manager protocol, the C++ object
# might die before PyTestClass self is reclaimed.
# We therefore need a small utility to check for the
# availability of self._thisptr
if self._thisptr == NULL:
raise RuntimeError("Wrapped C++ object is deleted")
else:
return 0
property x:
# Here we use a property to expose the public member
# x of TestClass to Python
def __get__(PyTestClass self):
self._check_alive()
return self._thisptr.x
def __set__(PyTestClass self, value):
self._check_alive()
self._thisptr.x = <int> value
property y:
# Here we use a property to expose the public member
# y of TestClass to Python
def __get__(PyTestClass self):
self._check_alive()
return self._thisptr.y
def __set__(PyTestClass self, value):
self._check_alive()
self._thisptr.y = <int> value
def Multiply(PyTestClass self, int a, int b):
self._check_alive()
return self._thisptr.Multiply(a,b)
# The context manager protocol allows us to precisely
# control the liftetime of the wrapped C++ object. del
# is called deterministically and independently of
# the Python garbage collection.
def __enter__(PyTestClass self):
self._check_alive()
return self
def __exit__(PyTestClass self, exc_tp, exc_val, exc_tb):
if self._thisptr != NULL:
del self._thisptr
self._thisptr = NULL # inform __dealloc__
return False # propagate exceptions