Skip to content

Commit 828a2ec

Browse files
rfourquetStefanKarpinski
authored andcommitted
issubset: don't create a Set out of dicts (#32003)
1 parent 0ef07f8 commit 828a2ec

File tree

2 files changed

+39
-9
lines changed

2 files changed

+39
-9
lines changed

base/abstractset.jl

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -251,16 +251,15 @@ true
251251
issubset, ,
252252

253253
function issubset(l, r)
254-
if haslength(r)
255-
rlen = length(r)
256-
if isa(l, AbstractSet)
257-
# check l for too many unique elements
258-
length(l) > rlen && return false
254+
if haslength(r) && (isa(l, AbstractSet) || !hasfastin(r))
255+
rlen = length(r) # conditions above make this length computed only when needed
256+
# check l for too many unique elements
257+
if isa(l, AbstractSet) && length(l) > rlen
258+
return false
259259
end
260-
# if r is big enough, convert it to a Set
261-
# threshold empirically determined by repeatedly
262-
# sampling using these two methods (see #26198)
263-
if rlen > 70 && !isa(r, AbstractSet)
260+
# when `in` would be too slow and r is big enough, convert it to a Set
261+
# this threshold was empirically determined (cf. #26198)
262+
if !hasfastin(r) && rlen > 70
264263
return issubset(l, Set(r))
265264
end
266265
end
@@ -270,6 +269,19 @@ function issubset(l, r)
270269
return true
271270
end
272271

272+
"""
273+
hasfastin(T)
274+
275+
Determine whether the computation `x ∈ collection` where `collection::T` can be considered
276+
as a "fast" operation (typically constant or logarithmic complexity).
277+
The definition `hasfastin(x) = hasfastin(typeof(x))` is provided for convenience so that instances
278+
can be passed instead of types.
279+
However the form that accepts a type argument should be defined for new types.
280+
"""
281+
hasfastin(::Type) = false
282+
hasfastin(::Union{Type{<:AbstractSet},Type{<:AbstractDict},Type{<:AbstractRange}}) = true
283+
hasfastin(x) = hasfastin(typeof(x))
284+
273285
(l, r) = r l
274286

275287
## strict subset comparison

test/sets.jl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,24 @@ end
347347
# symdiff must NOT uniquify
348348
@test symdiff([1, 2, 1]) == symdiff!([1, 2, 1]) == [2]
349349
@test symdiff([1, 2, 1], [2, 2]) == symdiff!([1, 2, 1], [2, 2]) == [2]
350+
351+
# Base.hasfastin
352+
@test all(Base.hasfastin, Any[Dict(1=>2), Set(1), BitSet(1), 1:9, 1:2:9,
353+
Dict, Set, BitSet, UnitRange, StepRange])
354+
@test !any(Base.hasfastin, Any[[1, 2, 3], "123",
355+
Array, String])
356+
357+
# tests for Dict
358+
d1 = Dict(1=>nothing, 2=>nothing)
359+
d2 = Dict(1=>nothing, 3=>nothing)
360+
d3 = Dict(1=>nothing, 2=>nothing, 3=>nothing)
361+
@test d3 == merge(d1, d2)
362+
@test !issubset(d1, d2)
363+
@test !issubset(d2, d1)
364+
@test !issubset(d3, d1)
365+
@test !issubset(d3, d2)
366+
@test issubset(d1, d3)
367+
@test issubset(d2, d3)
350368
end
351369

352370
@testset "unique" begin

0 commit comments

Comments
 (0)