1# mode: run
2# tag: cpp, werror
3
4from __future__ import division
5
6from cython cimport typeof
7
8cimport cython.operator
9from cython.operator cimport typeid, dereference as deref
10
11from libc.string cimport const_char
12from libcpp cimport bool
13
14
15cdef out(s, result_type=None):
16    print '%s [%s]' % (s.decode('ascii'), result_type)
17
18
19cdef iout(int s, result_type=None):
20    print '%s [%s]' % (s, result_type)
21
22
23cdef extern from "cpp_operators_helper.h" nogil:
24    cdef cppclass TestOps:
25
26        const_char* operator+() except +
27        const_char* operator-() except +
28        const_char* operator*() except +
29        const_char* operator~() except +
30        const_char* operator!() except +
31
32        # FIXME: using 'except +' here leads to wrong calls ???
33        const_char* operator++()
34        const_char* operator--()
35        const_char* operator++(int)
36        const_char* operator--(int)
37
38        const_char* operator+(int) except +
39        const_char* operator+(int,const TestOps&) except +
40        const_char* operator-(int) except +
41        const_char* operator-(int,const TestOps&) except +
42        const_char* operator*(int) except +
43        # deliberately omitted operator* to test case where only defined outside class
44        const_char* operator/(int) except +
45        const_char* operator/(int,const TestOps&) except +
46        const_char* operator%(int) except +
47        const_char* operator%(int,const TestOps&) except +
48
49        const_char* operator|(int) except +
50        const_char* operator|(int,const TestOps&) except +
51        const_char* operator&(int) except +
52        const_char* operator&(int,const TestOps&) except +
53        const_char* operator^(int) except +
54        const_char* operator^(int,const TestOps&) except +
55        const_char* operator,(int) except +
56        const_char* operator,(int,const TestOps&) except +
57
58        const_char* operator<<(int) except +
59        const_char* operator<<(int,const TestOps&) except +
60        const_char* operator>>(int) except +
61        const_char* operator>>(int,const TestOps&) except +
62
63        # FIXME: using 'except +' here leads to invalid C++ code ???
64        const_char* operator==(int)
65        const_char* operator!=(int)
66        const_char* operator>=(int)
67        const_char* operator<=(int)
68        const_char* operator>(int)
69        const_char* operator<(int)
70
71        const_char* operator[](int) except +
72        const_char* operator()(int) except +
73
74    # Defining the operator outside the class does work
75    # but doesn't help when importing from pxd files
76    # (they don't get imported)
77    const_char* operator+(float,const TestOps&) except +
78    # deliberately omitted operator- to test case where only defined in class
79    const_char* operator*(float,const TestOps&) except +
80    const_char* operator/(float,const TestOps&) except +
81    const_char* operator%(float,const TestOps&) except +
82
83    const_char* operator|(float,const TestOps&) except +
84    const_char* operator&(float,const TestOps&) except +
85    const_char* operator^(float,const TestOps&) except +
86    const_char* operator,(float,const TestOps&) except +
87
88    const_char* operator<<(float,const TestOps&) except +
89    const_char* operator>>(float,const TestOps&) except +
90
91    cdef cppclass RefTestOps:
92
93        int& operator+() except +
94        int& operator-() except +
95        int& operator*() except +
96        int& operator~() except +
97        int& operator!() except +
98
99        int& operator++() except +
100        int& operator--() except +
101        int& operator++(int) except +
102        int& operator--(int) except +
103
104        int& operator+(int) except +
105        int& operator+(int,const TestOps&) except +
106        int& operator-(int) except +
107        int& operator-(int,const TestOps&) except +
108        int& operator*(int) except +
109        # deliberately omitted operator* to test case where only defined outside class
110        int& operator/(int) except +
111        int& operator/(int,const TestOps&) except +
112        int& operator%(int) except +
113        int& operator%(int,const TestOps&) except +
114
115        int& operator|(int) except +
116        int& operator|(int,const TestOps&) except +
117        int& operator&(int) except +
118        int& operator&(int,const TestOps&) except +
119        int& operator^(int) except +
120        int& operator^(int,const TestOps&) except +
121        int& operator,(int) except +
122        int& operator,(int,const TestOps&) except +
123
124        int& operator<<(int) except +
125        int& operator<<(int,const TestOps&) except +
126        int& operator>>(int) except +
127        int& operator>>(int,const TestOps&) except +
128
129        int& operator==(int) except +
130        int& operator!=(int) except +
131        int& operator>=(int) except +
132        int& operator<=(int) except +
133        int& operator>(int) except +
134        int& operator<(int) except +
135
136        int& operator[](int) except +
137        int& operator()(int) except +
138
139    cdef cppclass TruthClass:
140        TruthClass()
141        TruthClass(bool)
142        bool operator bool()
143        bool value
144
145
146cdef cppclass TruthSubClass(TruthClass):
147    pass
148
149
150def test_unops():
151    """
152    >>> test_unops()
153    unary + [const_char *]
154    unary - [const_char *]
155    unary ~ [const_char *]
156    unary * [const_char *]
157    unary ! [const_char *]
158    """
159    cdef TestOps* t = new TestOps()
160    out(+t[0], typeof(+t[0]))
161    out(-t[0], typeof(-t[0]))
162    out(~t[0], typeof(~t[0]))
163    x = deref(t[0])
164    out(x, typeof(x))
165    out(not t[0], typeof(not t[0]))
166    del t
167
168def test_incdec():
169    """
170    >>> test_incdec()
171    unary ++ [const_char *]
172    unary -- [const_char *]
173    post ++ [const_char *]
174    post -- [const_char *]
175    """
176    cdef TestOps* t = new TestOps()
177    a = cython.operator.preincrement(t[0])
178    out(a, typeof(a))
179    b = cython.operator.predecrement(t[0])
180    out(b, typeof(b))
181    c = cython.operator.postincrement(t[0])
182    out(c, typeof(c))
183    d = cython.operator.postdecrement(t[0])
184    out(d, typeof(d))
185    del t
186
187def test_binop():
188    """
189    >>> test_binop()
190    binary + [const_char *]
191    binary - [const_char *]
192    binary * [const_char *]
193    binary / [const_char *]
194    binary % [const_char *]
195    binary & [const_char *]
196    binary | [const_char *]
197    binary ^ [const_char *]
198    binary << [const_char *]
199    binary >> [const_char *]
200    binary COMMA [const_char *]
201    """
202    cdef TestOps* t = new TestOps()
203    out(t[0] + 1, typeof(t[0] + 1))
204    out(t[0] - 1, typeof(t[0] - 1))
205    out(t[0] * 1, typeof(t[0] * 1))
206    out(t[0] / 1, typeof(t[0] / 1))
207    out(t[0] % 1, typeof(t[0] % 1))
208
209    out(t[0] & 1, typeof(t[0] & 1))
210    out(t[0] | 1, typeof(t[0] | 1))
211    out(t[0] ^ 1, typeof(t[0] ^ 1))
212
213    out(t[0] << 1, typeof(t[0] << 1))
214    out(t[0] >> 1, typeof(t[0] >> 1))
215
216    x = cython.operator.comma(t[0], 1)
217    out(x, typeof(x))
218    del t
219
220def test_nonmember_binop():
221    """
222    >>> test_nonmember_binop()
223    nonmember binary + [const_char *]
224    nonmember binary - [const_char *]
225    nonmember binary / [const_char *]
226    nonmember binary % [const_char *]
227    nonmember binary & [const_char *]
228    nonmember binary | [const_char *]
229    nonmember binary ^ [const_char *]
230    nonmember binary << [const_char *]
231    nonmember binary >> [const_char *]
232    nonmember binary COMMA [const_char *]
233    nonmember binary2 + [const_char *]
234    nonmember binary2 * [const_char *]
235    nonmember binary2 / [const_char *]
236    nonmember binary2 % [const_char *]
237    nonmember binary2 & [const_char *]
238    nonmember binary2 | [const_char *]
239    nonmember binary2 ^ [const_char *]
240    nonmember binary2 << [const_char *]
241    nonmember binary2 >> [const_char *]
242    nonmember binary2 COMMA [const_char *]
243    """
244
245    cdef TestOps* t = new TestOps()
246    out(1 + t[0], typeof(1 + t[0]))
247    out(1 - t[0], typeof(1 - t[0]))
248    # * deliberately omitted
249    out(1 / t[0], typeof(1 / t[0]))
250    out(1 % t[0], typeof(1 % t[0]))
251    out(1 & t[0], typeof(1 & t[0]))
252    out(1 | t[0], typeof(1 | t[0]))
253    out(1 ^ t[0], typeof(1 ^ t[0]))
254    out(1 << t[0], typeof(1 << t[0]))
255    out(1 >> t[0], typeof(1 >> t[0]))
256
257    x = cython.operator.comma(1, t[0])
258    out(x, typeof(x))
259
260    # now test float operators defined outside class
261    out(1. + t[0], typeof(1. + t[0]))
262    # operator - deliberately omitted
263    out(1. * t[0], typeof(1. * t[0]))
264    out(1. / t[0], typeof(1. / t[0]))
265    out(1. % t[0], typeof(1. % t[0]))
266    out(1. & t[0], typeof(1. & t[0]))
267    out(1. | t[0], typeof(1. | t[0]))
268    out(1. ^ t[0], typeof(1. ^ t[0]))
269    out(1. << t[0], typeof(1. << t[0]))
270    out(1. >> t[0], typeof(1. >> t[0]))
271
272    # for some reason we need a cdef here - not sure this is quite right
273    y = cython.operator.comma(1., t[0])
274    out(y, typeof(y))
275    del t
276
277def test_cmp():
278    """
279    >>> test_cmp()
280    binary == [const_char *]
281    binary != [const_char *]
282    binary >= [const_char *]
283    binary > [const_char *]
284    binary <= [const_char *]
285    binary < [const_char *]
286    """
287    cdef TestOps* t = new TestOps()
288    out(t[0] == 1, typeof(t[0] == 1))
289    out(t[0] != 1, typeof(t[0] != 1))
290    out(t[0] >= 1, typeof(t[0] >= 1))
291    out(t[0] > 1, typeof(t[0] > 1))
292    out(t[0] <= 1, typeof(t[0] <= 1))
293    out(t[0] < 1, typeof(t[0] < 1))
294    del t
295
296
297def test_index_call():
298    """
299    >>> test_index_call()
300    binary [] [const_char *]
301    binary () [const_char *]
302    """
303    cdef TestOps* t = new TestOps()
304    out(t[0][100], typeof(t[0][100]))
305    out(t[0](100), typeof(t[0](100)))
306    del t
307
308
309def test_index_assignment():
310    """
311    >>> test_index_assignment()
312    0 [int &]
313    123 [int [&]]
314    """
315    cdef RefTestOps* t = new RefTestOps()
316    iout(t[0][100], typeof(t[0][100]))
317    t[0][99] = 123
318    iout(t[0](100), typeof(t[0](100)))
319    del t
320
321
322def test_bool_op():
323    """
324    >>> test_bool_op()
325    """
326    cdef TruthClass yes = TruthClass(True)
327    cdef TruthClass no = TruthClass(False)
328    if yes:
329        pass
330    else:
331        assert False
332    if no:
333        assert False
334
335def test_bool_cond():
336    """
337    >>> test_bool_cond()
338    """
339    assert (TruthClass(False) or TruthClass(False)).value == False
340    assert (TruthClass(False) or TruthClass(True)).value == True
341    assert (TruthClass(True) or TruthClass(False)).value == True
342    assert (TruthClass(True) or TruthClass(True)).value == True
343
344    assert (TruthClass(False) and TruthClass(False)).value == False
345    assert (TruthClass(False) and TruthClass(True)).value == False
346    assert (TruthClass(True) and TruthClass(False)).value == False
347    assert (TruthClass(True) and TruthClass(True)).value == True
348
349
350ctypedef int* int_ptr
351
352def test_typeid_op():
353    """
354    >>> test_typeid_op()
355    """
356    cdef TruthClass* test_1 = new TruthClass()
357    cdef TruthSubClass* test_2 = new TruthSubClass()
358    cdef TruthClass* test_3 = <TruthClass*> test_2
359    cdef TruthClass* test_4 = <TruthClass*> 0
360
361    assert typeid(TruthClass).name()
362    assert typeid(test_1).name()
363    assert typeid(TruthClass) == typeid(deref(test_1))
364
365    assert typeid(TruthSubClass).name()
366    assert typeid(test_2).name()
367    assert typeid(TruthSubClass) == typeid(deref(test_2))
368    assert typeid(TruthSubClass) == typeid(deref(test_3))
369    assert typeid(TruthClass) != typeid(deref(test_3))
370
371    assert typeid(TruthClass).name()
372    assert typeid(test_3).name()
373    assert typeid(TruthSubClass).name()
374    assert typeid(deref(test_2)).name()
375    assert typeid(int_ptr).name()
376
377    try:
378        typeid(deref(test_4))
379        assert False
380    except TypeError:
381        assert True
382
383    del test_1, test_2
384