Skip to content

Commit 8ce1668

Browse files
authored
Merge pull request #5 from cjdoris/c
adds julia.SetValue
2 parents 4d9a418 + 3d2d610 commit 8ce1668

File tree

6 files changed

+345
-4
lines changed

6 files changed

+345
-4
lines changed

src/cpython/CPython.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ include("juliaany.jl")
6060
include("juliaiterator.jl")
6161
include("juliatype.jl")
6262
include("juliadict.jl")
63+
include("juliaset.jl")
6364
include("juliaarray.jl")
6465
include("juliavector.jl")
6566
include("juliamodule.jl")

src/cpython/collections.jl

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,49 @@ for n in [:Container, :Hashable, :Iterable, :Iterator, :Reversible, :Generator,
3434
end
3535
end
3636

37+
"""
38+
PyIterable_Collect(xs::PyPtr, T::Type, [skip=false]) :: Vector{T}
39+
40+
Convert the elements of `xs` to type `T` and collect them into a vector.
41+
On error, an empty vector is returned.
42+
43+
If `skip` then elements which cannot be converted to a `T` are skipped over,
44+
instead of raising an error. Other errors are still propagated.
45+
"""
46+
PyIterable_Collect(xso::PyPtr, ::Type{T}, skip::Bool=false) where {T} = begin
47+
xs = T[]
48+
it = PyObject_GetIter(xso)
49+
isnull(it) && return xs
50+
try
51+
while true
52+
xo = PyIter_Next(it)
53+
if !isnull(xo)
54+
if skip
55+
r = PyObject_TryConvert(xo, T)
56+
Py_DecRef(xo)
57+
r == -1 && (empty!(xs); break)
58+
r == 0 && continue
59+
else
60+
r = PyObject_Convert(xo, T)
61+
Py_DecRef(xo)
62+
r == -1 && (empty!(xs); break)
63+
end
64+
x = takeresult(T)
65+
push!(xs, x)
66+
else
67+
PyErr_IsSet() && empty!(xs)
68+
break
69+
end
70+
end
71+
catch err
72+
empty!(xs)
73+
PyErr_SetJuliaError(err)
74+
finally
75+
Py_DecRef(it)
76+
end
77+
return xs
78+
end
79+
3780
PyIterable_ConvertRule_vector(o, ::Type{S}) where {S<:Vector} = begin
3881
it = PyObject_GetIter(o)
3982
isnull(it) && return -1

src/cpython/complex.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ PyComplexable_TryConvertRule_convert(o, ::Type{S}) where {S} = begin
2626
end
2727

2828
PyComplexable_TryConvertRule_tryconvert(o, ::Type{S}) where {S} = begin
29-
x = PyComplexable_AsComplex(o)
29+
x = PyComplex_AsComplex(o)
3030
ism1(x) && PyErr_IsSet() && return -1
3131
putresult(tryconvert(S, x))
3232
end

src/cpython/juliaset.jl

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
const PyJuliaSetValue_Type__ref = Ref(PyPtr())
2+
PyJuliaSetValue_Type() = begin
3+
ptr = PyJuliaSetValue_Type__ref[]
4+
if isnull(ptr)
5+
c = []
6+
base = PyJuliaAnyValue_Type()
7+
isnull(base) && return PyPtr()
8+
t = fill(PyType_Create(c,
9+
name = "julia.SetValue",
10+
base = base,
11+
methods = [
12+
(name="add", flags=Py_METH_O, meth=pyjlset_add),
13+
(name="clear", flags=Py_METH_NOARGS, meth=pyjlset_clear),
14+
(name="copy", flags=Py_METH_NOARGS, meth=pyjlset_copy),
15+
(name="difference", flags=Py_METH_O, meth=pyjlset_difference),
16+
(name="difference_update", flags=Py_METH_O, meth=pyjlset_difference_update),
17+
(name="discard", flags=Py_METH_O, meth=pyjlset_discard),
18+
(name="intersection", flags=Py_METH_O, meth=pyjlset_intersection),
19+
(name="intersection_update", flags=Py_METH_O, meth=pyjlset_intersection_update),
20+
# (name="isdisjoint", flags=Py_METH_O, meth=pyjlset_isdisjoint),
21+
# (name="issubset", flags=Py_METH_O, meth=pyjlset_issubset),
22+
# (name="issuperset", flags=Py_METH_O, meth=pyjlset_issuperset),
23+
(name="pop", flags=Py_METH_NOARGS, meth=pyjlset_pop),
24+
(name="remove", flags=Py_METH_O, meth=pyjlset_remove),
25+
(name="symmetric_difference", flags=Py_METH_O, meth=pyjlset_symmetric_difference),
26+
(name="symmetric_difference_update", flags=Py_METH_O, meth=pyjlset_symmetric_difference_update),
27+
(name="union", flags=Py_METH_O, meth=pyjlset_union),
28+
(name="update", flags=Py_METH_O, meth=pyjlset_update),
29+
],
30+
as_number = (
31+
or = pyjlset_or,
32+
and = pyjlset_and,
33+
xor = pyjlset_xor,
34+
subtract = pyjlset_sub,
35+
inplace_or = pyjlset_ior,
36+
inplace_and = pyjlset_iand,
37+
inplace_xor = pyjlset_ixor,
38+
inplace_subtract = pyjlset_isub,
39+
),
40+
))
41+
ptr = PyPtr(pointer(t))
42+
err = PyType_Ready(ptr)
43+
ism1(err) && return PyPtr()
44+
abc = PyMutableSetABC_Type()
45+
isnull(abc) && return PyPtr()
46+
ism1(PyABC_Register(ptr, abc)) && return PyPtr()
47+
PYJLGCCACHE[ptr] = push!(c, t)
48+
PyJuliaSetValue_Type__ref[] = ptr
49+
end
50+
ptr
51+
end
52+
53+
PyJuliaSetValue_New(x::AbstractSet) = PyJuliaValue_New(PyJuliaSetValue_Type(), x)
54+
PyJuliaValue_From(x::AbstractSet) = PyJuliaSetValue_New(x)
55+
56+
pyjlset_add(xo::PyPtr, vo::PyPtr) = begin
57+
x = PyJuliaValue_GetValue(xo)::AbstractSet
58+
ism1(PyObject_Convert(vo, eltype(x))) && return PyPtr()
59+
v = takeresult(eltype(x))
60+
try
61+
push!(x, v)
62+
PyNone_New()
63+
catch err
64+
PyErr_SetJuliaError(err)
65+
PyPtr()
66+
end
67+
end
68+
69+
pyjlset_discard(xo::PyPtr, vo::PyPtr) = begin
70+
x = PyJuliaValue_GetValue(xo)::AbstractSet
71+
r = PyObject_TryConvert(vo, eltype(x))
72+
r == -1 && return PyPtr()
73+
r == 0 && return PyNone_New()
74+
v = takeresult(eltype(x))
75+
try
76+
delete!(x, v)
77+
PyNone_New()
78+
catch err
79+
PyErr_SetJuliaError(err)
80+
PyPtr()
81+
end
82+
end
83+
84+
pyjlset_clear(xo::PyPtr, _::PyPtr) = begin
85+
x = PyJuliaValue_GetValue(xo)::AbstractSet
86+
try
87+
empty!(x)
88+
PyNone_New()
89+
catch err
90+
PyErr_SetJuliaError(err)
91+
PyPtr()
92+
end
93+
end
94+
95+
pyjlset_copy(xo::PyPtr, _::PyPtr) = begin
96+
x = PyJuliaValue_GetValue(xo)::AbstractSet
97+
try
98+
PyObject_From(copy(x))
99+
catch err
100+
PyErr_SetJuliaError(err)
101+
PyPtr()
102+
end
103+
end
104+
105+
pyjlset_pop(xo::PyPtr, _::PyPtr) = begin
106+
x = PyJuliaValue_GetValue(xo)::AbstractSet
107+
try
108+
if isempty(x)
109+
PyErr_SetString(PyExc_KeyError(), "pop from an empty set")
110+
PyPtr()
111+
else
112+
PyObject_From(pop!(x))
113+
end
114+
catch err
115+
PyErr_SetJuliaError(err)
116+
PyPtr()
117+
end
118+
end
119+
120+
pyjlset_remove(xo::PyPtr, vo::PyPtr) = begin
121+
x = PyJuliaValue_GetValue(xo)::AbstractSet
122+
r = PyObject_TryConvert(vo, eltype(x))
123+
if r == -1
124+
return PyPtr()
125+
elseif r == 0
126+
PyErr_SetObject(PyExc_KeyError(), vo)
127+
return PyPtr()
128+
end
129+
v = takeresult(eltype(x))
130+
try
131+
if v in x
132+
delete!(x, v)
133+
PyNone_New()
134+
else
135+
PyErr_SetObject(PyExc_KeyError(), vo)
136+
PyPtr()
137+
end
138+
catch err
139+
PyErr_SetJuliaError(err)
140+
PyPtr()
141+
end
142+
end
143+
144+
pyjlset_ibinop_named(xo, yo, op, skip) = begin
145+
x = PyJuliaValue_GetValue(xo)::AbstractSet
146+
y = PyIterable_Collect(yo, eltype(x), skip)
147+
isempty(y) && PyErr_IsSet() && return PyPtr()
148+
try
149+
op(x, y)
150+
PyNone_New()
151+
catch err
152+
PyErr_SetJuliaError(err)
153+
PyPtr()
154+
end
155+
end
156+
pyjlset_update(xo, yo) = pyjlset_ibinop_named(xo, yo, union!, false)
157+
pyjlset_difference_update(xo, yo) = pyjlset_ibinop_named(xo, yo, setdiff!, true)
158+
pyjlset_symmetric_difference_update(xo, yo) = pyjlset_ibinop_named(xo, yo, symdiff!, false)
159+
pyjlset_intersection_update(xo, yo) = pyjlset_ibinop_named(xo, yo, intersect!, true)
160+
161+
pyjlset_ibinop_operator(xo, yo, op, skip) = begin
162+
r = PySetABC_Check(yo)
163+
r == -1 && return PyPtr()
164+
r == 0 && return PyNotImplemented_New()
165+
x = PyJuliaValue_GetValue(xo)::AbstractSet
166+
y = PyIterable_Collect(yo, eltype(x), skip)
167+
isempty(y) && PyErr_IsSet() && return PyPtr()
168+
try
169+
PyObject_From(op(x, y))
170+
catch err
171+
PyErr_SetJuliaError(err)
172+
PyPtr()
173+
end
174+
end
175+
pyjlset_ior(xo, yo) = pyjlset_ibinop_operator(xo, yo, union!, false)
176+
pyjlset_isub(xo, yo) = pyjlset_ibinop_operator(xo, yo, setdiff!, true)
177+
pyjlset_ixor(xo, yo) = pyjlset_ibinop_operator(xo, yo, symdiff!, false)
178+
pyjlset_iand(xo, yo) = pyjlset_ibinop_operator(xo, yo, intersect!, true)
179+
180+
pyjlset_binop_generic(xo::PyPtr, yo::PyPtr, op) = begin
181+
xo2 = PySet_New(xo)
182+
isnull(xo2) && return PyPtr()
183+
yo2 = PySet_New(yo)
184+
isnull(yo2) && (Py_DecRef(xo2); return PyPtr())
185+
ro = op(xo2, yo2)
186+
Py_DecRef(xo2)
187+
Py_DecRef(yo2)
188+
ro
189+
end
190+
pyjlset_or_generic(xo, yo) = pyjlset_binop_generic(xo, yo, PyNumber_InPlaceOr)
191+
pyjlset_xor_generic(xo, yo) = pyjlset_binop_generic(xo, yo, PyNumber_InPlaceXor)
192+
pyjlset_and_generic(xo, yo) = pyjlset_binop_generic(xo, yo, PyNumber_InPlaceAnd)
193+
pyjlset_sub_generic(xo, yo) = pyjlset_binop_generic(xo, yo, PyNumber_InPlaceSubtract)
194+
195+
pyjlset_binop_special(xo::PyPtr, yo::PyPtr, op) = begin
196+
x = PyJuliaValue_GetValue(xo)::AbstractSet
197+
y = PyJuliaValue_GetValue(yo)::AbstractSet
198+
try
199+
PyObject_From(op(x, y))
200+
catch err
201+
PyErr_SetJuliaError(err)
202+
PyPtr()
203+
end
204+
end
205+
pyjlset_or_special(xo, yo) = pyjlset_binop_special(xo, yo, union)
206+
pyjlset_xor_special(xo, yo) = pyjlset_binop_special(xo, yo, symdiff)
207+
pyjlset_and_special(xo, yo) = pyjlset_binop_special(xo, yo, intersect)
208+
pyjlset_sub_special(xo, yo) = pyjlset_binop_special(xo, yo, setdiff)
209+
210+
pyjlset_binop_operator(xo::PyPtr, yo::PyPtr, gop, sop) = begin
211+
t = PyJuliaSetValue_Type()
212+
isnull(t) && return PyPtr()
213+
if (r=PyObject_IsInstance(xo, t); ism1(r) && return PyPtr(); r!=0)
214+
if (r=PyObject_IsInstance(yo, t); ism1(r) && return PyPtr(); r!=0)
215+
sop(xo, yo)
216+
elseif (r=PySetABC_Check(yo); ism1(r) && return PyPtr(); r!=0)
217+
gop(xo, yo)
218+
else
219+
PyNotImplemented_New()
220+
end
221+
elseif (r=PyObject_IsInstance(yo, t); ism1(r) && return PyPtr(); r!=0)
222+
if (r=PySetABC_Check(xo); ism1(r) && return PyPtr(); r!=0)
223+
gop(xo, yo)
224+
else
225+
PyNotImplemented_New()
226+
end
227+
else
228+
PyNotImplemented_New()
229+
end
230+
end
231+
pyjlset_or(xo, yo) = pyjlset_binop_operator(xo, yo, pyjlset_or_generic, pyjlset_or_special)
232+
pyjlset_xor(xo, yo) = pyjlset_binop_operator(xo, yo, pyjlset_xor_generic, pyjlset_xor_special)
233+
pyjlset_and(xo, yo) = pyjlset_binop_operator(xo, yo, pyjlset_and_generic, pyjlset_and_special)
234+
pyjlset_sub(xo, yo) = pyjlset_binop_operator(xo, yo, pyjlset_sub_generic, pyjlset_sub_special)
235+
236+
pyjlset_binop_named(xo, yo, gop, sop) = begin
237+
t = PyJuliaSetValue_Type()
238+
isnull(t) && return PyPtr()
239+
if (r=PyObject_IsInstance(yo, t); ism1(r) && return PyPtr(); r!=0)
240+
sop(xo, yo)
241+
elseif (r=PySetABC_Check(yo); ism1(r) && return PyPtr(); r!=0)
242+
gop(xo, yo)
243+
else
244+
PyNotImplemented_New()
245+
end
246+
end
247+
pyjlset_union(xo, yo) = pyjlset_binop_named(xo, yo, pyjlset_or_generic, pyjlset_or_special)
248+
pyjlset_symmetric_difference(xo, yo) = pyjlset_binop_named(xo, yo, pyjlset_xor_generic, pyjlset_xor_special)
249+
pyjlset_intersection(xo, yo) = pyjlset_binop_named(xo, yo, pyjlset_and_generic, pyjlset_and_special)
250+
pyjlset_difference(xo, yo) = pyjlset_binop_named(xo, yo, pyjlset_sub_generic, pyjlset_sub_special)

src/cpython/newtype.jl

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,53 @@ end
2828
### PROTOCOLS
2929

3030
PyNumberMethods_Create(c, x::PyNumberMethods) = x
31-
PyNumberMethods_Create(c; opts...) = C.PyNumberMethods(; [k => (v isa Ptr ? v : v isa Base.CFunction ? cacheptr!(c, v) : error()) for (k,v) in pairs(opts)]...)
31+
PyNumberMethods_Create(c;
32+
add=C_NULL, subtract=C_NULL, multiply=C_NULL, remainder=C_NULL, divmod=C_NULL, power=C_NULL,
33+
negative=C_NULL, positive=C_NULL, absolute=C_NULL, bool=C_NULL, invert=C_NULL,
34+
lshift=C_NULL, rshift=C_NULL, and=C_NULL, or=C_NULL, xor=C_NULL, int=C_NULL, float=C_NULL,
35+
inplace_add=C_NULL, inplace_subtract=C_NULL, inplace_multiply=C_NULL,
36+
inplace_remainder=C_NULL, inplace_power=C_NULL, inplace_lshift=C_NULL, inplace_rshift=C_NULL,
37+
inplace_and=C_NULL, inplace_xor=C_NULL, inplace_or=C_NULL, floordivide=C_NULL,
38+
truedivide=C_NULL, inplace_floordivide=C_NULL, inplace_truedivide=C_NULL, index=C_NULL,
39+
matrixmultiply=C_NULL, inplace_matrixmultiply=C_NULL
40+
) =
41+
PyNumberMethods(
42+
add = @cachefuncptr!(c, add, PyPtr, (PyPtr, PyPtr)),
43+
subtract = @cachefuncptr!(c, subtract, PyPtr, (PyPtr, PyPtr)),
44+
multiply = @cachefuncptr!(c, multiply, PyPtr, (PyPtr, PyPtr)),
45+
remainder = @cachefuncptr!(c, remainder, PyPtr, (PyPtr, PyPtr)),
46+
divmod = @cachefuncptr!(c, divmod, PyPtr, (PyPtr, PyPtr)),
47+
power = @cachefuncptr!(c, power, PyPtr, (PyPtr, PyPtr, PyPtr)),
48+
negative = @cachefuncptr!(c, negative, PyPtr, (PyPtr,)),
49+
positive = @cachefuncptr!(c, positive, PyPtr, (PyPtr,)),
50+
absolute = @cachefuncptr!(c, absolute, PyPtr, (PyPtr,)),
51+
bool = @cachefuncptr!(c, bool, Cint, (PyPtr,)),
52+
invert = @cachefuncptr!(c, invert, PyPtr, (PyPtr,)),
53+
lshift = @cachefuncptr!(c, lshift, PyPtr, (PyPtr, PyPtr)),
54+
rshift = @cachefuncptr!(c, rshift, PyPtr, (PyPtr, PyPtr)),
55+
and = @cachefuncptr!(c, and, PyPtr, (PyPtr, PyPtr)),
56+
xor = @cachefuncptr!(c, xor, PyPtr, (PyPtr, PyPtr)),
57+
or = @cachefuncptr!(c, or, PyPtr, (PyPtr, PyPtr)),
58+
int = @cachefuncptr!(c, int, PyPtr, (PyPtr,)),
59+
float = @cachefuncptr!(c, float, PyPtr, (PyPtr,)),
60+
inplace_add = @cachefuncptr!(c, inplace_add, PyPtr, (PyPtr, PyPtr)),
61+
inplace_subtract = @cachefuncptr!(c, inplace_subtract, PyPtr, (PyPtr, PyPtr)),
62+
inplace_multiply = @cachefuncptr!(c, inplace_multiply, PyPtr, (PyPtr, PyPtr)),
63+
inplace_remainder = @cachefuncptr!(c, inplace_remainder, PyPtr, (PyPtr, PyPtr)),
64+
inplace_power = @cachefuncptr!(c, inplace_power, PyPtr, (PyPtr, PyPtr, PyPtr)),
65+
inplace_lshift = @cachefuncptr!(c, inplace_lshift, PyPtr, (PyPtr, PyPtr)),
66+
inplace_rshift = @cachefuncptr!(c, inplace_rshift, PyPtr, (PyPtr, PyPtr)),
67+
inplace_and = @cachefuncptr!(c, inplace_and, PyPtr, (PyPtr, PyPtr)),
68+
inplace_xor = @cachefuncptr!(c, inplace_xor, PyPtr, (PyPtr, PyPtr)),
69+
inplace_or = @cachefuncptr!(c, inplace_or, PyPtr, (PyPtr, PyPtr)),
70+
floordivide = @cachefuncptr!(c, floordivide, PyPtr, (PyPtr, PyPtr)),
71+
truedivide = @cachefuncptr!(c, truedivide, PyPtr, (PyPtr, PyPtr)),
72+
inplace_floordivide = @cachefuncptr!(c, inplace_floordivide, PyPtr, (PyPtr, PyPtr)),
73+
inplace_truedivide = @cachefuncptr!(c, inplace_truedivide, PyPtr, (PyPtr, PyPtr)),
74+
index = @cachefuncptr!(c, index, PyPtr, (PyPtr,)),
75+
matrixmultiply = @cachefuncptr!(c, matrixmultiply, PyPtr, (PyPtr, PyPtr)),
76+
inplace_matrixmultiply = @cachefuncptr!(c, inplace_matrixmultiply, PyPtr, (PyPtr, PyPtr)),
77+
)
3278
PyNumberMethods_Create(c, x::Dict) = PyNumberMethods_Create(c; x...)
3379
PyNumberMethods_Create(c, x::NamedTuple) = PyNumberMethods_Create(c; x...)
3480

src/cpython/object.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,8 @@ PyObject_TryConvert_CompileRule(::Type{T}, t::PyPtr) where {T} = begin
155155
end
156156
if xb != PyPtr()
157157
push!(basetypes, xt)
158-
push!(basemros, [xb; PyType_MROAsVector(xt)])
158+
xmro = PyType_MROAsVector(xt)
159+
push!(basemros, xb in xmro ? xmro : [xb; xmro])
159160
end
160161
end
161162
for b in basetypes[2:end]
@@ -176,7 +177,7 @@ PyObject_TryConvert_CompileRule(::Type{T}, t::PyPtr) where {T} = begin
176177
break
177178
end
178179
end
179-
ok || error("Fatal inheritence error: could not merge MROs")
180+
ok || error("Fatal inheritence error: could not merge MROs (alltypes=$alltypes, basemros=$basemros)")
180181
# add it to the list
181182
push!(alltypes, b)
182183
# remove it from consideration

0 commit comments

Comments
 (0)