File Coverage

blib/lib/Tree/Binary2.pm
Criterion Covered Total %
statement 105 109 96.3
branch 38 40 95.0
condition 9 9 100.0
subroutine 13 17 76.4
pod 4 4 100.0
total 169 179 94.4


line stmt bran cond sub pod time code
1             package Tree::Binary2;
2              
3 3     3   3888 use 5.006;
  3         12  
4              
5 3     3   17 use base 'Tree';
  3         4  
  3         1616  
6 3     3   22 use strict;
  3         6  
  3         55  
7 3     3   12 use warnings;
  3         6  
  3         77  
8              
9 3     3   16 use Scalar::Util qw( blessed );
  3         6  
  3         1395  
10              
11             our $VERSION = '1.16';
12              
13             sub _init {
14 46     46   61 my $self = shift;
15 46         116 $self->SUPER::_init( @_ );
16              
17             # Make this class a complete binary tree,
18             # filling in with Tree::Null as appropriate.
19             $self->{_children}->[$_] = $self->_null
20 46         112 for 0 .. 1;
21              
22 46         69 return $self;
23             }
24              
25             sub left {
26 108     108 1 412 my $self = shift;
27 108         178 return $self->_set_get_child( 0, @_ );
28             }
29              
30             sub right {
31 106     106 1 433 my $self = shift;
32 106         172 return $self->_set_get_child( 1, @_ );
33             }
34              
35             sub _set_get_child {
36 214     214   264 my $self = shift;
37 214         239 my $index = shift;
38              
39 214 100       319 if ( @_ ) {
40 24         29 my $node = shift;
41 24 100       66 $node = $self->_null unless $node;
42              
43 24         42 my $old = $self->children->[$index];
44 24         42 $self->children->[$index] = $node;
45              
46 24 100       51 if ( $node ) {
47 22         59 $node->_set_parent( $self );
48 22         49 $node->_set_root( $self->root );
49 22         48 $node->_fix_depth;
50             }
51              
52 24 100       61 if ( $old ) {
53 2         5 $old->_set_parent( $old->_null );
54 2         5 $old->_set_root( $old->_null );
55 2         5 $old->_fix_depth;
56             }
57              
58 24         66 $self->_fix_height;
59 24         58 $self->_fix_width;
60              
61 24         90 return $self;
62             }
63             else {
64 190         274 return $self->children->[$index];
65             }
66             }
67              
68             sub _clone_children {
69 22     22   34 my ($self, $clone) = @_;
70              
71 22         29 @{ $clone->{_children} } = ();
  22         35  
72 22         32 $clone->add_child({}, map { $_->clone } @{ $self->{_children} });
  44         146  
  22         36  
73             }
74              
75             sub children {
76 443     443 1 533 my $self = shift;
77 443 50       668 if ( @_ ) {
78 0         0 my @idx = @_;
79 0         0 return @{$self->{_children}}[@idx];
  0         0  
80             }
81             else {
82 443 100 100     1832 if ( caller->isa( __PACKAGE__ ) || $self->isa( scalar(caller) ) ) {
83 438 100       1101 return wantarray ? @{$self->{_children}} : $self->{_children};
  200         811  
84             }
85             else {
86 5         8 return grep { $_ } @{$self->{_children}};
  10         29  
  5         13  
87             }
88             }
89             }
90              
91 3     3   23 use constant IN_ORDER => 4;
  3         6  
  3         1691  
92              
93             # One of the things we have to do in a traversal is to remove all of the
94             # Tree::Null elements that are appended to the tree to make this a complete
95             # binary tree. The user isn't going to expect them, because they're an
96             # internal nicety.
97              
98             sub traverse {
99 89     89 1 3124 my $self = shift;
100 89         150 my $order = shift;
101 89 100       165 $order = $self->PRE_ORDER unless $order;
102              
103 89 100       134 if ( wantarray ) {
104 79 100       140 if ( $order == $self->IN_ORDER ) {
105 54         95 return grep { $_ } (
  222         344  
106             $self->left->traverse( $order ),
107             $self,
108             $self->right->traverse( $order ),
109             );
110             }
111             else {
112 25         77 return grep { $_ } $self->SUPER::traverse( $order );
  99         167  
113             }
114             }
115             else {
116 10         15 my $closure;
117              
118 10 100       46 if ( $order eq $self->IN_ORDER ) {
    100          
    100          
    50          
119 2         5 my @list = $self->traverse( $order );
120              
121             $closure = sub {
122 20 100   0   66 return unless @list;
123 18         26 return shift @list;
124 2         9 };
125             }
126             elsif ( $order eq $self->PRE_ORDER ) {
127 4         5 my $next_node = $self;
128 4         8 my @stack = ( $self );
129 4         8 my @next_meth = ( 0 );
130              
131 4         6 my @meths = qw( left right );
132             $closure = sub {
133 40     0   142 my $node = $next_node;
134 40 100       96 return unless $node;
135 36         44 $next_node = undef;
136              
137 36   100     109 while ( @stack && !$next_node ) {
138 76   100     201 while ( @next_meth && $next_meth[0] == 2 ) {
139 36         41 shift @stack;
140 36         89 shift @next_meth;
141             }
142              
143 76 100       124 if ( @stack ) {
144 72         102 my $meth = $meths[ $next_meth[0]++ ];
145 72         131 $next_node = $stack[0]->$meth;
146 72 100       139 next unless $next_node;
147 32         49 unshift @stack, $next_node;
148 32         95 unshift @next_meth, 0;
149             }
150             }
151              
152 36         64 return $node;
153 4         19 };
154             }
155             elsif ( $order eq $self->POST_ORDER ) {
156 2         6 my @list = $self->traverse( $order );
157              
158             $closure = sub {
159 20 100   0   67 return unless @list;
160 18         25 return shift @list;
161 2         8 };
162             #my @stack = ( $self );
163             #my @next_idx = ( 0 );
164             #while ( @{ $stack[0]->{_children} } ) {
165             # unshift @stack, $stack[0]->{_children}[0];
166             # unshift @next_idx, 0;
167             #}
168             #
169             #$closure = sub {
170             # my $node = $stack[0] || return;
171             #
172             # shift @stack; shift @next_idx;
173             # $next_idx[0]++;
174             #
175             # while ( @stack && exists $stack[0]->{_children}[ $next_idx[0] ] ) {
176             # unshift @stack, $stack[0]->{_children}[ $next_idx[0] ];
177             # unshift @next_idx, 0;
178             # }
179             #
180             # return $node;
181             #};
182             }
183             elsif ( $order eq $self->LEVEL_ORDER ) {
184 2         5 my @nodes = ($self);
185             $closure = sub {
186 20     0   58 my $node = shift @nodes;
187 20 100       34 return unless $node;
188 18         21 push @nodes, grep { $_ } @{$node->{_children}};
  36         55  
  18         31  
189 18         27 return $node;
190 2         8 };
191             }
192             else {
193 0         0 return $self->error( "traverse(): '$order' is an illegal traversal order" );
194             }
195              
196 10         78 return $closure;
197             }
198             }
199              
200             1;
201             __END__