diff --git a/src/base.jl b/src/base.jl index d3fde13..032a4d3 100644 --- a/src/base.jl +++ b/src/base.jl @@ -152,7 +152,7 @@ Get the number of leaves in the tree rooted at `node`. Leaf nodes have a breadth By default this recurses through all nodes in the tree and so may be slow if a more specialized method has not been implemented for the given type. """ -treebreadth(node) = isempty(children(node)) ? 1 : mapreduce(treebreadth, +, children(node)) +treebreadth(node) = ischildrenempty(children(node)) ? 1 : mapreduce(treebreadth, +, children(node)) """ @@ -163,7 +163,7 @@ Get the maximum depth from `node` to any of its descendants. Leaf nodes have a h By default this recurses through all nodes in the tree and so may be slow if a more specialized method has not been implemented for the given type. """ -treeheight(node) = isempty(children(node)) ? 0 : 1 + mapreduce(treeheight, max, children(node)) +treeheight(node) = ischildrenempty(children(node)) ? 0 : 1 + mapreduce(treeheight, max, children(node)) """ descendleft(node) @@ -173,7 +173,7 @@ Descend from the node `node` to the first encountered leaf node by recursively c """ function descendleft(node) ch = children(node) - isempty(ch) && return node + ischildrenempty(ch) && return node descendleft(first(ch)) end @@ -273,3 +273,15 @@ function StableNode{T}(𝒻, node) where {T} StableNode{T}(convert(T, 𝒻(node)), map(n -> StableNode{T}(𝒻, n), children(node))) end +# isempty check for children that is consistent with interface +# without this the fallback isempty can waste a call to iterate +# tested the test (ch===()) but it ended up being slopwer +ischildrenempty(@nospecialize ch::Tuple) = (@inline; ch == ()) + +#fallback definition +ischildrenempty(ch) = (@inline; isempty(ch)) + + + + + diff --git a/src/cursors.jl b/src/cursors.jl index d3393d2..0b47487 100644 --- a/src/cursors.jl +++ b/src/cursors.jl @@ -283,7 +283,7 @@ struct StableCursor{N,S} <: TreeCursor{N,N} # note that this very deliberately takes childstatetype(n) and *not* childstatetype(p) # this is because p may be nothing StableCursor(::Nothing, n, st) = new{typeof(n),childstatetype(n)}(nothing, n, st) - + # this method is important for eliminating expensive calls to childstatetype StableCursor(p::StableCursor{N,S}, n, st) where {N,S} = new{N,S}(p, n, st) end @@ -374,3 +374,7 @@ TreeCursor(::NodeTypeUnknown, ::NonIndexedChildren, ::ParentLinks, ::ImplicitSib # extra methods to resolve ambiguity TreeCursor(::NodeTypeUnknown, ::IndexedChildren, ::StoredParents, ::StoredSiblings, node) = TrivialCursor(node) TreeCursor(::NodeTypeUnknown, ::NonIndexedChildren, ::StoredParents, ::StoredSiblings, node) = TrivialCursor(node) + +function ischildrenempty(x::TreeCursor) + (ischildrenempty ∘ children ∘ nodevalue)(x) +end \ No newline at end of file diff --git a/src/iteration.jl b/src/iteration.jl index f0ffbb9..c4623e2 100644 --- a/src/iteration.jl +++ b/src/iteration.jl @@ -107,7 +107,7 @@ initial(::Type{PreOrderState}, node) = PreOrderState(node) function next(f, s::PreOrderState) if f(nodevalue(s.cursor)) ch = children(s.cursor) - isempty(ch) || return instance(PreOrderState, first(ch)) + ischildrenempty(ch) || return instance(PreOrderState, first(ch)) end csr = s.cursor @@ -376,7 +376,7 @@ Base.iterate(ti::StatelessBFS) = (ti.root, []) function _descend_left(inds, next_node, level) while length(inds) ≠ level ch = children(next_node) - isempty(ch) && break + ischildrenempty(ch) && break push!(inds, 1) next_node = first(ch) end diff --git a/src/printing.jl b/src/printing.jl index 083d971..b902470 100644 --- a/src/printing.jl +++ b/src/printing.jl @@ -208,7 +208,7 @@ function print_tree(printnode::Function, io::IO, node; c = children(node) # No children? - isempty(c) && return + ischildrenempty(c) && return # Reached max depth? if depth ≥ maxdepth