I have defined a tree made of ‘nodes’ and ‘leaves’ as follows. Each leaf has a vector of indices that I would like to iterate under certain conditions.
using AbstractTrees
struct BVH
name::String
children::Union{Nothing, Tuple{BVH, BVH}}
indices::Union{Nothing, Vector{Int64}}
end
BVH(n::String, l::BVH, r::BVH) = BVH(n, (l,r), nothing) # construct a node
BVH(n::String, inds::Vector{Int64}) = BVH(n, nothing, inds) # construct a leaf
Base.show(io::IO, b::BVH) = print(io, isnothing(b.children) ? "Leaf-" : "Node-", b.name)
AbstractTrees.children(bvh::BVH) = isnothing(bvh.children) ? [] : bvh.children
function indices(b::BVH)
isnothing(b.children) && return (i for i in b.indices)
isnothing(b.indices) && return Iterators.flatten(indices(c) for c in b.children)
end
bvh = BVH("root", BVH("1",BVH("2", [1,2,3]),BVH("3", BVH("4", [4,5,6]), BVH("5",[7,8,9]))),BVH("6",[10,11,12]))
I do get with this example 2 allocations.
julia> print_tree(bvh)
Node-root
├─ Node-1
│ ├─ Leaf-2
│ └─ Node-3
│ ├─ Leaf-4
│ └─ Leaf-5
└─ Leaf-6
julia> collect(indices(bvh))
12-element Vector{Int64}:
1
...
12
julia> @btime indices($bvh)
23.416 ns (2 allocations: 64 bytes)
Of course @code_warntype
shows me that the problem has to do with the different kind of generator I am returning.
Union{Base.Generator{Nothing, typeof(identity)}, Base.Generator{Vector{Int64}, typeof(identity)}}
Is there a any way to achieving the goal without allocations? Thanks.