From 8a52ea42877c5d0fe3d9b6c2bc4387bceb7ea9b0 Mon Sep 17 00:00:00 2001 From: Rafael Fourquet Date: Sat, 10 Oct 2020 14:13:24 +0200 Subject: [PATCH] faster replace on Dict and Set (#33739) This optimizes replace and replace! functions on Dict (and Set) based on the internals. --- base/set.jl | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/base/set.jl b/base/set.jl index 23b313c8080fd..40b32ddddd3ba 100644 --- a/base/set.jl +++ b/base/set.jl @@ -683,3 +683,46 @@ function _replace!(new::Callable, res::AbstractArray, A::AbstractArray, count::I end res end + +### specialization for Dict / Set + +function _replace!(new::Callable, t::Dict{K,V}, A::Dict{K,V}, count::Int) where {K,V} + # we ignore A, which is supposed to be equal to the destination t, + # as it can generally be faster to just replace inline + count == 0 && return t + c = 0 + news = Pair{K,V}[] + i = skip_deleted_floor!(t) + @inbounds while i != 0 + k1, v1 = t.keys[i], t.vals[i] + x1 = Pair{K,V}(k1, v1) + x2 = new(x1) + if x1 !== x2 + k2, v2 = first(x2), last(x2) + if isequal(k1, k2) + t.keys[i] = k2 + t.vals[i] = v2 + t.age += 1 + else + _delete!(t, i) + push!(news, x2) + end + c += 1 + c == count && break + end + i = i == typemax(Int) ? 0 : skip_deleted(t, i+1) + end + for n in news + push!(t, n) + end + t +end + +function _replace!(new::Callable, t::Set{T}, ::Set{T}, count::Int) where {T} + _replace!(t.dict, t.dict, count) do kv + k = first(kv) + k2 = new(k) + k2 === k ? kv : k2 => nothing + end + t +end