I am trying to create an iterator that wraps another one. Let us assume that we have this iterator that returns l
times the array a
:
struct Foo
a::Array{Float64,1}
l::Int
end
Base.iterate(foo::Foo) = iterate(foo,0)
function Base.iterate(foo::Foo,state::Int)
if foo.l == state
nothing
else
k = state + 1
(foo.a,k)
end
end
My goal is to implement another iterator that wraps previous one:
struct Bar
foo::Foo
end
function Base.iterate(bar::Bar)
foonext = iterate(bar.foo)
iterate(bar,foonext)
end
function Base.iterate(bar::Bar,state)
if state == nothing
nothing
else
(fooi,foostate) = state
foonext = iterate(bar.foo,foostate)
(fooi,foonext)
end
end
Iterating over instances of Foo
works fine (as expected):
function run(x)
for xi in x
end
end
foo = Foo([1.2,3.2,1.1],10000000)
@time run(foo)
@time run(foo)
0.288515 seconds (12.11 k allocations: 750.146 KiB)
0.274807 seconds (4 allocations: 160 bytes)
The problems is that by iterating instances of Bar
I get unwanted memory allocation:
bar = Bar(foo)
@time run(bar)
@time run(bar)
0.795432 seconds (10.02 M allocations: 306.389 MiB, 3.56% gc time)
0.669443 seconds (10.00 M allocations: 305.176 MiB, 0.99% gc time)
I would say that the code above is type stable…what I am missing?
Thanks in advance for the help!