From 68e842d95baca1b82ac3f6289436bb5ae5adf8f6 Mon Sep 17 00:00:00 2001 From: Nicholas R Dinsmore Date: Mon, 14 Nov 2022 19:25:19 -0500 Subject: [PATCH 1/5] isemptychild working --- src/base.jl | 17 ++++++++++++++--- src/cursors.jl | 4 ++++ src/iteration.jl | 4 ++-- src/printing.jl | 2 +- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/base.jl b/src/base.jl index d3fde13..1d5f592 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) = isemptychild(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) = isemptychild(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 + isemptychild(ch) && return node descendleft(first(ch)) end @@ -273,3 +273,14 @@ function StableNode{T}(𝒻, node) where {T} StableNode{T}(convert(T, 𝒻(node)), map(n -> StableNode{T}(𝒻, n), children(node))) end + +isemptychild(ch::Tuple) = ch == () +function isemptychild(ch) + isempty(ch) +end + +function isemptychild(x::AbstractArray) + length(x) == 0 +end + + diff --git a/src/cursors.jl b/src/cursors.jl index d3393d2..3112b80 100644 --- a/src/cursors.jl +++ b/src/cursors.jl @@ -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 isemptychild(x::TreeCursor) + isemptychild(children(nodevalue(x))) +end \ No newline at end of file diff --git a/src/iteration.jl b/src/iteration.jl index f0ffbb9..1a510f0 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)) + isemptychild(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 + isemptychild(ch) && break push!(inds, 1) next_node = first(ch) end diff --git a/src/printing.jl b/src/printing.jl index 083d971..36355e6 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 + isemptychild(c) && return # Reached max depth? if depth ≥ maxdepth From 38741f83faee17fb0511c1cd768b73d8640d8582 Mon Sep 17 00:00:00 2001 From: Nicholas R Dinsmore Date: Mon, 14 Nov 2022 19:37:16 -0500 Subject: [PATCH 2/5] Change to ischildrenempty --- src/base.jl | 19 +++++++++---------- src/cursors.jl | 4 ++-- src/iteration.jl | 4 ++-- src/printing.jl | 2 +- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/base.jl b/src/base.jl index 1d5f592..5fc932b 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) = isemptychild(children(node)) ? 1 : mapreduce(treebreadth, +, children(node)) +treebreadth(node) = ischildenempty(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) = isemptychild(children(node)) ? 0 : 1 + mapreduce(treeheight, max, children(node)) +treeheight(node) = ischildenempty(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) - isemptychild(ch) && return node + ischildenempty(ch) && return node descendleft(first(ch)) end @@ -273,14 +273,13 @@ function StableNode{T}(𝒻, node) where {T} StableNode{T}(convert(T, 𝒻(node)), map(n -> StableNode{T}(𝒻, n), children(node))) end +#isempty check that is consistent with interface +ischildenempty(ch::Tuple) = ch == () -isemptychild(ch::Tuple) = ch == () -function isemptychild(ch) - isempty(ch) -end +#fallback definition +ischildenempty(ch) = isempty(ch) + +ischildenempty(x::AbstractArray) = length(x) == 0 -function isemptychild(x::AbstractArray) - length(x) == 0 -end diff --git a/src/cursors.jl b/src/cursors.jl index 3112b80..b74d2b6 100644 --- a/src/cursors.jl +++ b/src/cursors.jl @@ -375,6 +375,6 @@ TreeCursor(::NodeTypeUnknown, ::NonIndexedChildren, ::ParentLinks, ::ImplicitSib TreeCursor(::NodeTypeUnknown, ::IndexedChildren, ::StoredParents, ::StoredSiblings, node) = TrivialCursor(node) TreeCursor(::NodeTypeUnknown, ::NonIndexedChildren, ::StoredParents, ::StoredSiblings, node) = TrivialCursor(node) -function isemptychild(x::TreeCursor) - isemptychild(children(nodevalue(x))) +function ischildenempty(x::TreeCursor) + ischildenempty(children(nodevalue(x))) end \ No newline at end of file diff --git a/src/iteration.jl b/src/iteration.jl index 1a510f0..f9ccf85 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) - isemptychild(ch) || return instance(PreOrderState, first(ch)) + ischildenempty(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) - isemptychild(ch) && break + ischildenempty(ch) && break push!(inds, 1) next_node = first(ch) end diff --git a/src/printing.jl b/src/printing.jl index 36355e6..aec5e3b 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? - isemptychild(c) && return + ischildenempty(c) && return # Reached max depth? if depth ≥ maxdepth From ffd6e290a389daf13c888369661ec75c5f9e3f59 Mon Sep 17 00:00:00 2001 From: Nicholas R Dinsmore Date: Tue, 15 Nov 2022 09:21:43 -0500 Subject: [PATCH 3/5] Cleanup --- src/base.jl | 5 +++-- src/builtins.jl | 8 ++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/base.jl b/src/base.jl index 5fc932b..ab40909 100644 --- a/src/base.jl +++ b/src/base.jl @@ -273,13 +273,14 @@ function StableNode{T}(𝒻, node) where {T} StableNode{T}(convert(T, 𝒻(node)), map(n -> StableNode{T}(𝒻, n), children(node))) end -#isempty check that is consistent with interface +# isempty check for children that is consistent with interface +# without this the fallback isempty can waste a call to iterate ischildenempty(ch::Tuple) = ch == () #fallback definition ischildenempty(ch) = isempty(ch) -ischildenempty(x::AbstractArray) = length(x) == 0 + diff --git a/src/builtins.jl b/src/builtins.jl index 8553cc9..5648df5 100644 --- a/src/builtins.jl +++ b/src/builtins.jl @@ -9,3 +9,11 @@ children(x::Expr) = x.args children(p::Pair) = (p[2],) children(dict::AbstractDict) = pairs(dict) + +# ischildrenempty definition for built in type +ischildenempty(x::AbstractArray) = length(x) == 0 + +ischildenempty(x::AbstractDict) = length(x) == 0 + +# Pairs is an AbstractDict so this is covered under that efintion +# ischildenempty(x::Pairs) = length(x) == 0 From ff36304ec1167577b6f0fa7db79d156b5331a469 Mon Sep 17 00:00:00 2001 From: Nicholas R Dinsmore Date: Tue, 15 Nov 2022 13:03:13 -0500 Subject: [PATCH 4/5] Final cleanup --- src/base.jl | 5 +++-- src/builtins.jl | 8 -------- src/cursors.jl | 4 ++-- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/base.jl b/src/base.jl index ab40909..3bb4b65 100644 --- a/src/base.jl +++ b/src/base.jl @@ -275,10 +275,11 @@ end # isempty check for children that is consistent with interface # without this the fallback isempty can waste a call to iterate -ischildenempty(ch::Tuple) = ch == () +# tested the test (ch===()) but it ended up being slopwer +ischildenempty(@nospecialize ch::Tuple) = (@inline; ch == ()) #fallback definition -ischildenempty(ch) = isempty(ch) +ischildenempty(ch) = (@inline; isempty(ch)) diff --git a/src/builtins.jl b/src/builtins.jl index 5648df5..8553cc9 100644 --- a/src/builtins.jl +++ b/src/builtins.jl @@ -9,11 +9,3 @@ children(x::Expr) = x.args children(p::Pair) = (p[2],) children(dict::AbstractDict) = pairs(dict) - -# ischildrenempty definition for built in type -ischildenempty(x::AbstractArray) = length(x) == 0 - -ischildenempty(x::AbstractDict) = length(x) == 0 - -# Pairs is an AbstractDict so this is covered under that efintion -# ischildenempty(x::Pairs) = length(x) == 0 diff --git a/src/cursors.jl b/src/cursors.jl index b74d2b6..b14d6c3 100644 --- a/src/cursors.jl +++ b/src/cursors.jl @@ -376,5 +376,5 @@ TreeCursor(::NodeTypeUnknown, ::IndexedChildren, ::StoredParents, ::StoredSiblin TreeCursor(::NodeTypeUnknown, ::NonIndexedChildren, ::StoredParents, ::StoredSiblings, node) = TrivialCursor(node) function ischildenempty(x::TreeCursor) - ischildenempty(children(nodevalue(x))) -end \ No newline at end of file + (ischildenempty ∘ children ∘ nodevalue)(x) +end \ No newline at end of file From 459b597795e83ac6480fc52993839930d0f547cb Mon Sep 17 00:00:00 2001 From: Nicholas R Dinsmore Date: Mon, 16 Jan 2023 12:43:24 -0500 Subject: [PATCH 5/5] Fix spelling --- src/base.jl | 10 +++++----- src/cursors.jl | 8 ++++---- src/iteration.jl | 4 ++-- src/printing.jl | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/base.jl b/src/base.jl index 3bb4b65..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) = ischildenempty(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) = ischildenempty(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) - ischildenempty(ch) && return node + ischildrenempty(ch) && return node descendleft(first(ch)) end @@ -276,10 +276,10 @@ 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 -ischildenempty(@nospecialize ch::Tuple) = (@inline; ch == ()) +ischildrenempty(@nospecialize ch::Tuple) = (@inline; ch == ()) #fallback definition -ischildenempty(ch) = (@inline; isempty(ch)) +ischildrenempty(ch) = (@inline; isempty(ch)) diff --git a/src/cursors.jl b/src/cursors.jl index b14d6c3..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 @@ -375,6 +375,6 @@ TreeCursor(::NodeTypeUnknown, ::NonIndexedChildren, ::ParentLinks, ::ImplicitSib TreeCursor(::NodeTypeUnknown, ::IndexedChildren, ::StoredParents, ::StoredSiblings, node) = TrivialCursor(node) TreeCursor(::NodeTypeUnknown, ::NonIndexedChildren, ::StoredParents, ::StoredSiblings, node) = TrivialCursor(node) -function ischildenempty(x::TreeCursor) - (ischildenempty ∘ children ∘ nodevalue)(x) -end \ No newline at end of file +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 f9ccf85..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) - ischildenempty(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) - ischildenempty(ch) && break + ischildrenempty(ch) && break push!(inds, 1) next_node = first(ch) end diff --git a/src/printing.jl b/src/printing.jl index aec5e3b..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? - ischildenempty(c) && return + ischildrenempty(c) && return # Reached max depth? if depth ≥ maxdepth