I am using a custom iterator that delegates into a struct to obtain the iterative grist, say a vector. I think it is appropriate to check if the current state (like an index) exceeds the length of the delegatee.
I do not want to recalculate the vector’s length at each iteration, and keeping the length in the struct does not work for external reasons.
What is an appropriate way to define iterate
so that the next state returned is a tuple (total_length, next_index)
and have it all work? I would prefer that the state stay simple (a two tuple) rather than embed both in a struct.
struct Foo{T <: AbstractVector} # type for MWE
v::T
end
function Base.length(c::Foo)
@info "length was called, and it was darn expensive"
length(c.v)
end
function Base.iterate(c::Foo)
len = length(c)
len > 0 || return nothing
(c.v[1], (2, len))
end
Base.iterate(c::Foo, (i, len)) = i > len ? nothing : (c.v[i], (i+1, len))
then
julia> foreach(println, Foo(1:10))
[ Info: length was called, and it was darn expensive
1
2
3
4
5
6
7
8
9
10
But that said, I would just define a wrapper type that caches the length.
Doesn’t a vector know its length?
strings do not know their length
although I am not using strings here
You may have resolved this as Julia does, often – problem? no, its no problem.
The length I need is several layers deep into substructure while iterating on x
length(x.partsofx.vecparts.bluevec
). I don’t believe the levels of dot indirection are very costly – I do believe they are not ameanable to compile time prelocation.
thanks for that … I was looking for (c, (i, len))
I’ll benchmark both approaches.