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