It seems that simply testing if a new collection was allocated with isequal
generates super-efficient code, eg
# "functional" implementation take 2
store!_or_widen(collection::Vector{T}, elt::S) where {T, S <: T} = push!(collection, elt)
store!_or_widen(collection, elt) = vcat(collection, elt)
function mycollect_funeq(itr)
y = iterate(itr)
y ≡ nothing && error("not allowed")
elt, state = y
_mycollect_funeq([elt], itr, state)
end
function _mycollect_funeq(collection, itr, state)
while true
y = iterate(itr, state)
y ≡ nothing && return collection
elt, state = y
expanded = store!_or_widen(collection, elt)
expanded ≡ collection || return _mycollect_funeq(expanded, itr, state)
end
end
benchmarks as
julia> @btime collect($itr);
60.238 μs (14 allocations: 30.94 KiB)
julia> @btime mycollect_fun($itr);
37.332 μs (1520 allocations: 70.88 KiB)
julia> @btime mycollect_mut($itr);
41.366 μs (990 allocations: 46.30 KiB)
julia> @btime mycollect_funeq($itr); # this is the new one
28.801 μs (520 allocations: 39.64 KiB)