Skip to content

Commit 5d01e24

Browse files
committed
Modernize traversal internals
Use Ruby 3.1 features and lighter traversal mechanics for readability and performance. Replace shift-based stacks and queues with more efficient patterns, drop nils in level traversal, and use pattern matching and count where clearer.
1 parent 25d879e commit 5d01e24

3 files changed

Lines changed: 26 additions & 13 deletions

File tree

lib/tree.rb

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -604,7 +604,8 @@ def freeze_tree!
604604
def [](name_or_index)
605605
raise ArgumentError, 'Name_or_index needs to be provided!' if name_or_index.nil?
606606

607-
if name_or_index.is_a?(Integer)
607+
case name_or_index
608+
in Integer
608609
@children[name_or_index]
609610
else
610611
@children_hash[name_or_index]
@@ -631,12 +632,14 @@ def each # :yields: node
631632
node_stack = [self] # Start with this node
632633

633634
until node_stack.empty?
634-
current = node_stack.shift # Pop the top-most node
635+
current = node_stack.pop # Pop the top-most node
635636
next unless current # Might be 'nil' (esp. for binary trees)
636637

637638
yield current # and process it
638639
# Stack children of the current node at top of the stack
639-
node_stack = current.children.concat(node_stack)
640+
current.children.reverse_each do |child|
641+
node_stack << child if child
642+
end
640643
end
641644

642645
self if block_given?
@@ -680,7 +683,9 @@ def postordered_each
680683
peek_node.visited = true
681684
# Add the children to the stack. Use the marking structure.
682685
marked_children =
683-
peek_node.node.children.compact.map { |node| marked_node.new(node, false) }
686+
peek_node.node.children.filter_map do |node|
687+
marked_node.new(node, false) if node
688+
end
684689
node_stack = marked_children.concat(node_stack)
685690
next
686691
else
@@ -707,15 +712,19 @@ def breadth_each
707712
return to_enum(:breadth_each) unless block_given?
708713

709714
node_queue = [self] # Create a queue with self as the initial entry
715+
queue_index = 0
710716

711717
# Use a queue to do breadth traversal
712-
until node_queue.empty?
713-
node_to_traverse = node_queue.shift
718+
while queue_index < node_queue.length
719+
node_to_traverse = node_queue[queue_index]
720+
queue_index += 1
714721
next unless node_to_traverse
715722

716723
yield node_to_traverse
717724
# Enqueue the children from left to right.
718-
node_to_traverse.children { |child| node_queue.push child if child }
725+
node_to_traverse.children.each do |child|
726+
node_queue << child if child
727+
end
719728
end
720729

721730
self if block_given?
@@ -779,7 +788,7 @@ def each_level
779788
level = [self]
780789
until level.empty?
781790
yield level
782-
level = level.map(&:children).flatten
791+
level = level.flat_map(&:children).filter_map { |child| child }
783792
end
784793
self
785794
else

lib/tree/utils/hash_converter.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,12 @@ def from_hash(hash)
106106

107107
root, children = hash.first
108108

109-
raise ArgumentError, 'Invalid child. Must be nil or hash.'\
110-
unless [Hash, NilClass].any? { |c| children.is_a? c }
109+
case children
110+
in Hash | nil
111+
# OK
112+
else
113+
raise ArgumentError, 'Invalid child. Must be nil or hash.'
114+
end
111115

112116
node = new(*root)
113117
node.add_from_hash(children) unless children.nil?

lib/tree/utils/metrics_methods.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ module TreeMetricsHandler
5151
# Size:: Total number nodes in the subtree including this node.
5252
#
5353
# @return [Integer] Total number of nodes in this (sub)tree.
54-
def size
55-
inject(0) { |sum, node| sum + 1 if node }
56-
end
54+
def size
55+
count
56+
end
5757

5858
# @!attribute [r] length
5959
# Convenience synonym for {#size}.

0 commit comments

Comments
 (0)