File Coverage

blib/lib/Tree/RB/Node.pm
Criterion Covered Total %
statement 82 91 90.1
branch 18 30 60.0
condition 17 23 73.9
subroutine 22 23 95.6
pod 8 13 61.5
total 147 180 81.6


line stmt bran cond sub pod time code
1             package Tree::RB::Node;
2            
3 7     7   958 use strict;
  7         12  
  7         294  
4 7     7   43 use Carp;
  7         13  
  7         493  
5 7     7   3626 use Tree::RB::Node::_Constants;
  7         20  
  7         700  
6 7     7   45 use vars qw( $VERSION @EXPORT_OK );
  7         10  
  7         1484  
7            
8             require Exporter;
9             *import = \&Exporter::import;
10             @EXPORT_OK = qw[set_color color_of parent_of left_of right_of];
11            
12             $VERSION = '0.2';
13            
14             my %attribute = (
15             key => _KEY,
16             val => _VAL,
17             color => _COLOR,
18             parent => _PARENT,
19             left => _LEFT,
20             right => _RIGHT,
21             );
22            
23             sub _accessor {
24 42     42   51 my $index = shift;
25             return sub {
26 76     76   830 my $self = shift;
27 76 100       171 if (@_) {
28 11         23 $self->[$index] = shift;
29             }
30 76         303 return $self->[$index];
31 42         305 };
32             }
33            
34             while(my($at, $idx) = each %attribute) {
35 7     7   46 no strict 'refs';
  7         21  
  7         3756  
36             *$at = _accessor($idx);
37             }
38            
39             sub new {
40 45     45 1 7457 my $class = shift;
41 45         76 my $obj = [];
42            
43 45 50       120 if (@_) {
44 45         89 $obj->[_KEY] = shift;
45 45         90 $obj->[_VAL] = shift;
46             }
47 45         155 return bless $obj, $class;
48             }
49            
50             sub min {
51 29     29 1 34 my $self = shift;
52 29         78 while ($self->[_LEFT]) {
53 32         84 $self = $self->[_LEFT];
54             }
55 29         77 return $self;
56             }
57            
58             sub max {
59 16     16 1 29 my $self = shift;
60 16         57 while ($self->[_RIGHT]) {
61 18         43 $self = $self->[_RIGHT];
62             }
63 16         60 return $self;
64             }
65            
66             sub leaf {
67 67     67 1 144 my $self = shift;
68 67   100     284 while (my $any_child = $self->[_LEFT] || $self->[_RIGHT]) {
69 40         175 $self = $any_child;
70             }
71 67         105 return $self;
72             }
73            
74             sub successor {
75 46     46 1 56 my $self = shift;
76 46 100       129 if ($self->[_RIGHT]) {
77 14         36 return $self->[_RIGHT]->min;
78             }
79 32         47 my $parent = $self->[_PARENT];
80 32   100     276 while ($parent && $parent->[_RIGHT] && $self == $parent->[_RIGHT]) {
      100        
81 20         32 $self = $parent;
82 20         132 $parent = $parent->[_PARENT];
83             }
84 32         98 return $parent;
85             }
86            
87             sub predecessor {
88 16     16 1 25 my $self = shift;
89 16 100       104 if ($self->[_LEFT]) {
90 5         21 return $self->[_LEFT]->max;
91             }
92 11         16 my $parent = $self->[_PARENT];
93 11   66     97 while ($parent && $parent->[_LEFT] && $self == $parent->[_LEFT]) {
      100        
94 9         16 $self = $parent;
95 9         126 $parent = $parent->[_PARENT];
96             }
97 11         53 return $parent;
98             }
99            
100             sub as_lol {
101 0     0 1 0 my $self = shift;
102 0   0     0 my $node = shift || $self;
103 0         0 my $aref;
104 0 0       0 push @$aref,
105             $node->[_LEFT]
106             ? $self->as_lol($node->[_LEFT])
107             : '*';
108 0 0       0 push @$aref,
109             $node->[_RIGHT]
110             ? $self->as_lol($node->[_RIGHT])
111             : '*';
112 0 0       0 my $color = ($node->[_COLOR] == RED ? 'R' : 'B');
113 7     7   53 no warnings 'uninitialized';
  7         9  
  7         1071  
114 0         0 push @$aref, "$color:$node->[_KEY]";
115 0         0 return $aref;
116             }
117            
118             sub strip {
119 45     45 1 61 my $self = shift;
120 45         47 my $callback = shift;
121            
122 45         41 my $x = $self;
123 45         99 while($x) {
124 65         112 my $leaf = $x->leaf;
125 65         302 $x = $leaf->[_PARENT];
126            
127             # detach $leaf from the (sub)tree
128 7     7   50 no warnings "uninitialized";
  7         12  
  7         2544  
129 65 100       187 if($leaf == $x->[_LEFT]) {
130 14         31 undef $x->[_LEFT];
131             }
132             else {
133 51         79 undef $x->[_RIGHT];
134             }
135 65         77 undef $leaf->[_PARENT];
136 65 50       252 if($callback) {
137 0         0 $callback->($leaf);
138             }
139            
140 65 100 33     227 if(!$x->[_LEFT] && !$x->[_RIGHT]) {
141 56         417 $x = $x->[_PARENT];
142             }
143             }
144             }
145            
146 44     44   1310 sub DESTROY { $_[0]->strip; }
147            
148             # Null aware accessors to assist with rebalancings during insertion and deletion
149             #
150             # A weird case of Java to the rescue!
151             # These are inspired by http://www.javaresearch.org/source/jdk142/java/util/TreeMap.java.html
152             # which was found via http://en.wikipedia.org/wiki/Red-black_tree#Implementations
153            
154             sub set_color {
155 6     6 0 7 my ($node, $color) = @_;
156 6 50       41 if($node) {
157 6   100     19 $node->[_COLOR] = $color || BLACK;
158             }
159             }
160            
161             sub color_of {
162 8 100   8 0 36 $_[0] ? $_[0]->[_COLOR] : BLACK;
163             }
164            
165             sub parent_of {
166 3 50   3 0 11 $_[0] ? $_[0]->[_PARENT] : undef;
167             }
168            
169             sub left_of {
170 3 50   3 0 11 $_[0] ? $_[0]->[_LEFT] : undef;
171             }
172            
173             sub right_of {
174 1 50   1 0 7 $_[0] ? $_[0]->[_RIGHT] : undef;
175             }
176            
177            
178             1; # Magic true value required at end of module
179             __END__