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   3769 use 5.006;
  3         10  
4              
5 3     3   16 use base 'Tree';
  3         4  
  3         1530  
6 3     3   20 use strict;
  3         6  
  3         56  
7 3     3   12 use warnings;
  3         5  
  3         78  
8              
9 3     3   14 use Scalar::Util qw( blessed );
  3         4  
  3         1360  
10              
11             our $VERSION = '1.14';
12              
13             sub _init {
14 46     46   62 my $self = shift;
15 46         122 $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         117 for 0 .. 1;
21              
22 46         75 return $self;
23             }
24              
25             sub left {
26 108     108 1 444 my $self = shift;
27 108         183 return $self->_set_get_child( 0, @_ );
28             }
29              
30             sub right {
31 106     106 1 439 my $self = shift;
32 106         176 return $self->_set_get_child( 1, @_ );
33             }
34              
35             sub _set_get_child {
36 214     214   248 my $self = shift;
37 214         249 my $index = shift;
38              
39 214 100       328 if ( @_ ) {
40 24         36 my $node = shift;
41 24 100       65 $node = $self->_null unless $node;
42              
43 24         43 my $old = $self->children->[$index];
44 24         41 $self->children->[$index] = $node;
45              
46 24 100       51 if ( $node ) {
47 22         66 $node->_set_parent( $self );
48 22         49 $node->_set_root( $self->root );
49 22         44 $node->_fix_depth;
50             }
51              
52 24 100       47 if ( $old ) {
53 2         6 $old->_set_parent( $old->_null );
54 2         6 $old->_set_root( $old->_null );
55 2         5 $old->_fix_depth;
56             }
57              
58 24         64 $self->_fix_height;
59 24         61 $self->_fix_width;
60              
61 24         88 return $self;
62             }
63             else {
64 190         275 return $self->children->[$index];
65             }
66             }
67              
68             sub _clone_children {
69 22     22   36 my ($self, $clone) = @_;
70              
71 22         29 @{ $clone->{_children} } = ();
  22         37  
72 22         33 $clone->add_child({}, map { $_->clone } @{ $self->{_children} });
  44         152  
  22         38  
73             }
74              
75             sub children {
76 443     443 1 541 my $self = shift;
77 443 50       671 if ( @_ ) {
78 0         0 my @idx = @_;
79 0         0 return @{$self->{_children}}[@idx];
  0         0  
80             }
81             else {
82 443 100 100     1879 if ( caller->isa( __PACKAGE__ ) || $self->isa( scalar(caller) ) ) {
83 438 100       1086 return wantarray ? @{$self->{_children}} : $self->{_children};
  200         859  
84             }
85             else {
86 5         8 return grep { $_ } @{$self->{_children}};
  10         26  
  5         12  
87             }
88             }
89             }
90              
91 3     3   36 use constant IN_ORDER => 4;
  3         7  
  3         1515  
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 3446 my $self = shift;
100 89         157 my $order = shift;
101 89 100       195 $order = $self->PRE_ORDER unless $order;
102              
103 89 100       140 if ( wantarray ) {
104 79 100       142 if ( $order == $self->IN_ORDER ) {
105 54         82 return grep { $_ } (
  222         326  
106             $self->left->traverse( $order ),
107             $self,
108             $self->right->traverse( $order ),
109             );
110             }
111             else {
112 25         84 return grep { $_ } $self->SUPER::traverse( $order );
  99         162  
113             }
114             }
115             else {
116 10         13 my $closure;
117              
118 10 100       48 if ( $order eq $self->IN_ORDER ) {
    100          
    100          
    50          
119 2         7 my @list = $self->traverse( $order );
120              
121             $closure = sub {
122 20 100   0   66 return unless @list;
123 18         28 return shift @list;
124 2         10 };
125             }
126             elsif ( $order eq $self->PRE_ORDER ) {
127 4         4 my $next_node = $self;
128 4         8 my @stack = ( $self );
129 4         8 my @next_meth = ( 0 );
130              
131 4         8 my @meths = qw( left right );
132             $closure = sub {
133 40     0   130 my $node = $next_node;
134 40 100       68 return unless $node;
135 36         39 $next_node = undef;
136              
137 36   100     98 while ( @stack && !$next_node ) {
138 76   100     216 while ( @next_meth && $next_meth[0] == 2 ) {
139 36         47 shift @stack;
140 36         87 shift @next_meth;
141             }
142              
143 76 100       131 if ( @stack ) {
144 72         105 my $meth = $meths[ $next_meth[0]++ ];
145 72         126 $next_node = $stack[0]->$meth;
146 72 100       136 next unless $next_node;
147 32         46 unshift @stack, $next_node;
148 32         118 unshift @next_meth, 0;
149             }
150             }
151              
152 36         62 return $node;
153 4         20 };
154             }
155             elsif ( $order eq $self->POST_ORDER ) {
156 2         14 my @list = $self->traverse( $order );
157              
158             $closure = sub {
159 20 100   0   69 return unless @list;
160 18         26 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   59 my $node = shift @nodes;
187 20 100       35 return unless $node;
188 18         22 push @nodes, grep { $_ } @{$node->{_children}};
  36         56  
  18         28  
189 18         40 return $node;
190 2         9 };
191             }
192             else {
193 0         0 return $self->error( "traverse(): '$order' is an illegal traversal order" );
194             }
195              
196 10         74 return $closure;
197             }
198             }
199              
200             1;
201             __END__