Skip to content

Instantly share code, notes, and snippets.

@tpapp
Last active September 20, 2018 07:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tpapp/f0cfb7fceaee5823c1afc0a1f4019ca9 to your computer and use it in GitHub Desktop.
Save tpapp/f0cfb7fceaee5823c1afc0a1f4019ca9 to your computer and use it in GitHub Desktop.
MWE for collecting using a functional style
# define an iterator with unknown type and length
struct MyItr N::Int end
Base.IteratorSize(::Type{MyItr}) = Base.SizeUnknown()
Base.IteratorEltype(::Type{MyItr}) = Base.EltypeUnknown()
function Base.iterate(itr::MyItr, state = 1)
if state > itr.N
nothing
else
val = state == 200 ? missing : state
(val, state + 1)
end
end
# "functional" implementation
store(collection::Vector{T}, elt::S) where {T, S <: T} =
(push!(collection, elt); (collection, false))
store(collection, elt) = (vcat(collection, elt), true)
function mycollect_fun(itr)
y = iterate(itr)
y ≡ nothing && error("not allowed")
elt, state = y
_mycollect_fun([elt], itr, state)
end
function _mycollect_fun(collection, itr, state)
while true
y = iterate(itr, state)
y ≡ nothing && return collection
elt, state = y
collection, changed = store(collection, elt)
changed && return _mycollect_fun(collection, itr, state)
end
end
# "stateful" implementation
canstore(collection::Vector{T}, elt::S) where {T, S <: T} = true
canstore(collection, elt) = false
store!(collection::Vector{T}, elt::S) where {T, S <: T} = push!(collection, elt)
function expand(collection::Vector{T}, elt::S) where {T,S}
U = Base.promote_typejoin(T, S)
newcollection = Vector{U}(undef, length(collection))
copyto!(newcollection, collection)
push!(newcollection, elt)
newcollection
end
function mycollect_mut(itr)
y = iterate(itr)
y ≡ nothing && error("not allowed")
elt, state = y
_mycollect_mut([elt], itr, state)
end
function _mycollect_mut(collection, itr, state)
while true
y = iterate(itr, state)
y ≡ nothing && return collection
elt, state = y
!canstore(collection, elt) && return _mycollect_mut(expand(collection, elt), itr, state)
store!(collection, elt)
end
end
# "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
using BenchmarkTools
itr = MyItr(1000)
@btime collect($itr);
@btime mycollect_fun($itr);
@btime mycollect_mut($itr);
@btime mycollect_funeq($itr);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment