cython

Форк
0
/
cpp_locals_directive.pyx 
231 строка · 5.8 Кб
1
# mode: run
2
# tag: cpp, cpp17, no-cpp-locals
3
# no-cpp-locals because the test is already run with it explicitly set
4

5
# cython: cpp_locals=True
6

7
cimport cython
8

9
from libcpp cimport bool as cppbool
10

11
cdef extern from *:
12
    r"""
13
    static void print_C_destructor();
14

15
    class C {
16
        public:
17
            C() = delete; // look! No default constructor
18
            C(int x, bool print_destructor=true) : x(x), print_destructor(print_destructor) {}
19
            C(C&& rhs) : x(rhs.x), print_destructor(rhs.print_destructor) {
20
                rhs.print_destructor = false; // moved-from instances are deleted silently
21
            }
22
            // also test that we don't require the assignment operator
23
            C& operator=(C&& rhs) = delete;
24
            C(const C& rhs) = delete;
25
            C& operator=(const C& rhs) = default;
26
            ~C() {
27
                if (print_destructor) print_C_destructor();
28
            }
29

30
            int getX() const { return x; }
31

32
        private:
33
            int x;
34
            bool print_destructor;
35
    };
36

37
    C make_C(int x) {
38
        return C(x);
39
    }
40
    """
41
    cdef cppclass C:
42
        C(int)
43
        C(int, cppbool)
44
        int getX() const
45
    C make_C(int) except +  # needs a temp to receive
46

47
# this function just makes sure the output from the destructor can be captured by doctest
48
cdef void print_C_destructor "print_C_destructor" () with gil:
49
    print("~C()")
50

51
def maybe_assign_infer(assign, value, do_print):
52
    """
53
    >>> maybe_assign_infer(True, 5, True)
54
    5
55
    ~C()
56
    >>> maybe_assign_infer(False, 0, True)
57
    Traceback (most recent call last):
58
        ...
59
    UnboundLocalError: local variable 'x' referenced before assignment
60
    >>> maybe_assign_infer(False, 0, False)  # no destructor call here
61
    """
62
    if assign:
63
        x = C(value)
64
    if do_print:
65
        print(x.getX())
66

67
def maybe_assign_cdef(assign, value):
68
    """
69
    >>> maybe_assign_cdef(True, 5)
70
    5
71
    ~C()
72
    >>> maybe_assign_cdef(False, 0)
73
    Traceback (most recent call last):
74
        ...
75
    UnboundLocalError: local variable 'x' referenced before assignment
76
    """
77
    cdef C x
78
    if assign:
79
        x = C(value)
80
    print(x.getX())
81

82
def maybe_assign_annotation(assign, value):
83
    """
84
    >>> maybe_assign_annotation(True, 5)
85
    5
86
    ~C()
87
    >>> maybe_assign_annotation(False, 0)
88
    Traceback (most recent call last):
89
        ...
90
    UnboundLocalError: local variable 'x' referenced before assignment
91
    """
92
    x: C
93
    if assign:
94
        x = C(value)
95
    print(x.getX())
96

97
def maybe_assign_directive1(assign, value):
98
    """
99
    >>> maybe_assign_directive1(True, 5)
100
    5
101
    ~C()
102
    >>> maybe_assign_directive1(False, 0)
103
    Traceback (most recent call last):
104
        ...
105
    UnboundLocalError: local variable 'x' referenced before assignment
106
    """
107
    x = cython.declare(C)
108
    if assign:
109
        x = C(value)
110
    print(x.getX())
111

112
@cython.locals(x=C)
113
def maybe_assign_directive2(assign, value):
114
    """
115
    >>> maybe_assign_directive2(True, 5)
116
    5
117
    ~C()
118
    >>> maybe_assign_directive2(False, 0)
119
    Traceback (most recent call last):
120
        ...
121
    UnboundLocalError: local variable 'x' referenced before assignment
122
    """
123
    if assign:
124
        x = C(value)
125
    print(x.getX())
126

127
def maybe_assign_nocheck(assign, value):
128
    """
129
    >>> maybe_assign_nocheck(True, 5)
130
    5
131
    ~C()
132

133
    # unfortunately it's quite difficult to test not assigning because there's a decent chance it'll crash
134
    """
135
    if assign:
136
        x = C(value)
137
    with cython.initializedcheck(False):
138
        print(x.getX())
139

140
def uses_temp(value):
141
    """
142
    needs a temp to handle the result of make_C - still doesn't use the default constructor
143
    >>> uses_temp(10)
144
    10
145
    ~C()
146
    """
147

148
    x = make_C(value)
149
    print(x.getX())
150

151
# c should not be optional - it isn't easy to check this, but we can at least check it compiles
152
cdef void has_argument(C c):
153
    print(c.getX())
154

155
def call_has_argument():
156
    """
157
    >>> call_has_argument()
158
    50
159
    """
160
    has_argument(C(50, False))
161

162
cdef class HoldsC:
163
    """
164
    >>> inst = HoldsC(True, False)
165
    >>> inst.getCX()
166
    10
167
    >>> access_from_function_with_different_directive(inst)
168
    10
169
    10
170
    >>> inst.getCX()  # it was changed in access_from_function_with_different_directive
171
    20
172
    >>> inst = HoldsC(False, False)
173
    >>> inst.getCX()
174
    Traceback (most recent call last):
175
        ...
176
    AttributeError: C++ attribute 'value' is not initialized
177
    >>> access_from_function_with_different_directive(inst)
178
    Traceback (most recent call last):
179
        ...
180
    AttributeError: C++ attribute 'value' is not initialized
181
    """
182
    cdef C value
183
    def __cinit__(self, initialize, print_destructor):
184
        if initialize:
185
            self.value = C(10, print_destructor)
186

187
    def getCX(self):
188
        return self.value.getX()
189

190
cdef acceptC(C& c):
191
    return c.getX()
192

193
@cython.cpp_locals(False)
194
def access_from_function_with_different_directive(HoldsC c):
195
    # doctest is in HoldsC class
196
    print(acceptC(c.value))  # this originally tried to pass a __Pyx_Optional<C> as a C instance
197
    print(c.value.getX())
198
    c.value = C(20, False) # make sure that we can change it too
199

200
def dont_test_on_pypy(f):
201
    import sys
202
    if not hasattr(sys, "pypy_version_info"):
203
        return f
204

205
@dont_test_on_pypy  # non-deterministic destruction
206
def testHoldsCDestruction(initialize):
207
    """
208
    >>> testHoldsCDestruction(True)
209
    ~C()
210
    >>> testHoldsCDestruction(False)  # no destructor
211
    """
212
    x = HoldsC(initialize, True)
213
    del x
214

215
cdef C global_var
216

217
def initialize_global_var():
218
    global global_var
219
    global_var = C(-1, False)
220

221
def read_global_var():
222
    """
223
    >>> read_global_var()
224
    Traceback (most recent call last):
225
        ...
226
    NameError: C++ global 'global_var' is not initialized
227
    >>> initialize_global_var()
228
    >>> read_global_var()
229
    -1
230
    """
231
    print(global_var.getX())
232

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.