Skip to content

Commit bf5f9d8

Browse files
committed
Implement creating native complex subclasses
1 parent b395064 commit bf5f9d8

File tree

7 files changed

+200
-113
lines changed

7 files changed

+200
-113
lines changed

graalpython/com.oracle.graal.python.cext/src/complexobject.c

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,6 @@ _Py_c_abs(Py_complex z)
221221
return result;
222222
}
223223

224-
#if 0 // GraalPy change
225224
static PyObject *
226225
complex_subtype_from_c_complex(PyTypeObject *type, Py_complex cval)
227226
{
@@ -232,7 +231,6 @@ complex_subtype_from_c_complex(PyTypeObject *type, Py_complex cval)
232231
((PyComplexObject *)op)->cval = cval;
233232
return op;
234233
}
235-
#endif // GraalPy change
236234

237235
PyObject *
238236
PyComplex_FromCComplex(Py_complex cval)
@@ -241,8 +239,7 @@ PyComplex_FromCComplex(Py_complex cval)
241239
return GraalPyComplex_FromDoubles(cval.real, cval.imag);
242240
}
243241

244-
#if 0 // GraalPy change
245-
static PyObject *
242+
PyObject * // GraalPy change: remove static
246243
complex_subtype_from_doubles(PyTypeObject *type, double real, double imag)
247244
{
248245
Py_complex c;
@@ -251,6 +248,7 @@ complex_subtype_from_doubles(PyTypeObject *type, double real, double imag)
251248
return complex_subtype_from_c_complex(type, c);
252249
}
253250

251+
#if 0 // GraalPy change
254252
PyObject *
255253
PyComplex_FromDoubles(double real, double imag)
256254
{
@@ -259,29 +257,33 @@ PyComplex_FromDoubles(double real, double imag)
259257
c.imag = imag;
260258
return PyComplex_FromCComplex(c);
261259
}
260+
#endif // GraalPy change
262261

263262
double
264263
PyComplex_RealAsDouble(PyObject *op)
265264
{
266-
if (PyComplex_Check(op)) {
265+
// GraalPy change: different implementation
266+
if (!points_to_py_handle_space(op) && PyComplex_Check(op)) {
267267
return ((PyComplexObject *)op)->cval.real;
268268
}
269269
else {
270-
return PyFloat_AsDouble(op);
270+
return GraalPyTruffleComplex_RealAsDouble(op);
271271
}
272272
}
273273

274274
double
275275
PyComplex_ImagAsDouble(PyObject *op)
276276
{
277-
if (PyComplex_Check(op)) {
277+
// GraalPy change: different implementation
278+
if (!points_to_py_handle_space(op) && PyComplex_Check(op)) {
278279
return ((PyComplexObject *)op)->cval.imag;
279280
}
280281
else {
281-
return 0.0;
282+
return GraalPyTruffleComplex_ImagAsDouble(op);
282283
}
283284
}
284285

286+
#if 0 // GraalPy change
285287
static PyObject *
286288
try_complex_special_method(PyObject *op)
287289
{
@@ -320,6 +322,10 @@ Py_complex
320322
PyComplex_AsCComplex(PyObject *op)
321323
{
322324
// GraalPy change: different implementation
325+
/* If op is already of type PyComplex_Type, return its value */
326+
if (!points_to_py_handle_space(op) && PyComplex_Check(op)) {
327+
return ((PyComplexObject *)op)->cval;
328+
}
323329
PyObject* parts = GraalPyTruffleComplex_AsCComplex(op);
324330
Py_complex result;
325331
if(parts != NULL) {

graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_complex.py

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,10 @@
3636
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3737
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3838
# SOFTWARE.
39+
import operator
40+
41+
from . import CPyExtTestCase, CPyExtFunction, unhandled_error_compare, CPyExtType, is_native_object
3942

40-
import sys
41-
from . import CPyExtTestCase, CPyExtFunction, CPyExtFunctionOutVars, unhandled_error_compare, GRAALPYTHON
4243
__dir__ = __file__.rpartition("/")[0]
4344

4445

@@ -84,13 +85,30 @@ class DummyComplexSubclass(complex):
8485
pass
8586

8687

88+
NativeComplexSubclass = CPyExtType(
89+
"NativeComplexSubclass",
90+
'',
91+
struct_base='PyComplexObject base;',
92+
tp_base='&PyComplex_Type',
93+
tp_new='0',
94+
tp_alloc='0',
95+
tp_free='0',
96+
)
97+
98+
99+
class ManagedNativeComplexSubclass(NativeComplexSubclass):
100+
pass
101+
102+
87103
class TestPyComplex(CPyExtTestCase):
88104

89105
test_PyComplex_AsCComplex = CPyExtFunction(
90106
lambda args: True,
91107
lambda: (
92108
(complex(1.0, 2.0), 1.0, 2.0),
93109
(DummyComplexSubclass(2.0, 3.0), 2.0, 3.0),
110+
(NativeComplexSubclass(1.0, 2.0), 1.0, 2.0),
111+
(ManagedNativeComplexSubclass(1.0, 2.0), 1.0, 2.0),
94112
),
95113
code='''int isNaN(double d) {
96114
return d != d;
@@ -122,6 +140,8 @@ class TestPyComplex(CPyExtTestCase):
122140
lambda: (
123141
(complex(1.0, 2.0), ),
124142
(DummyComplexSubclass(2.0, 3.0), ),
143+
(NativeComplexSubclass(1.0, 2.0),),
144+
(ManagedNativeComplexSubclass(1.0, 2.0),),
125145
),
126146
code='''
127147
PyObject* wrap_PyComplex_cval(PyObject* obj) {
@@ -143,6 +163,8 @@ class TestPyComplex(CPyExtTestCase):
143163
(complex(0.0, 2.0), ),
144164
(complex(1.0, 2.0), ),
145165
(DummyComplexSubclass(2.0, 3.0), ),
166+
(NativeComplexSubclass(1.0, 2.0),),
167+
(ManagedNativeComplexSubclass(1.0, 2.0),),
146168
("10.0", ),
147169
),
148170
resultspec="f",
@@ -157,6 +179,8 @@ class TestPyComplex(CPyExtTestCase):
157179
(complex(0.0, 2.0), ),
158180
(complex(1.0, 2.0), ),
159181
(DummyComplexSubclass(2.0, 3.0), ),
182+
(NativeComplexSubclass(1.0, 2.0),),
183+
(ManagedNativeComplexSubclass(1.0, 2.0),),
160184
("10.0", ),
161185
),
162186
resultspec="f",
@@ -176,3 +200,35 @@ class TestPyComplex(CPyExtTestCase):
176200
arguments=["double r", "double i"],
177201
cmpfunc=unhandled_error_compare
178202
)
203+
204+
205+
class TestNativeComplex:
206+
def test_builtins_on_subclass(self):
207+
for t in [NativeComplexSubclass, ManagedNativeComplexSubclass]:
208+
c = t(2, 3)
209+
assert is_native_object(c)
210+
assert type(c) is t
211+
assert c.real == 2
212+
assert c.imag == 3
213+
assert type(complex(c)) is complex
214+
assert complex(c) == 2 + 3j
215+
assert c == 2 + 3j
216+
assert t(2) == 2
217+
assert t(2.4) == 2.4
218+
219+
def assert_op_same(f):
220+
assert f(t(2, 3)) == f(2 + 3j)
221+
222+
assert_op_same(abs)
223+
assert_op_same(repr)
224+
assert_op_same(format)
225+
assert_op_same(bool)
226+
assert_op_same(hash)
227+
assert_op_same(operator.pos)
228+
assert_op_same(operator.neg)
229+
assert_op_same(lambda x: x + (1 + 2j))
230+
assert_op_same(lambda x: x - (1 + 2j))
231+
assert_op_same(lambda x: x * (1 + 2j))
232+
assert_op_same(lambda x: x / (1 + 2j))
233+
assert_op_same(lambda x: x ** (1 + 2j))
234+
assert_op_same(lambda x: x.conjugate())

0 commit comments

Comments
 (0)