line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Net::IPTrie; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
51320
|
use warnings; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
40
|
|
4
|
1
|
|
|
1
|
|
5
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
30
|
|
5
|
1
|
|
|
1
|
|
6
|
use Carp; |
|
1
|
|
|
|
|
14
|
|
|
1
|
|
|
|
|
131
|
|
6
|
1
|
|
|
1
|
|
1805
|
use NetAddr::IP; |
|
1
|
|
|
|
|
67413
|
|
|
1
|
|
|
|
|
81
|
|
7
|
1
|
|
|
1
|
|
580
|
use Net::IPTrie::Node; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
30
|
|
8
|
1
|
|
|
1
|
|
15
|
use vars qw($VERSION); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
253
|
|
9
|
|
|
|
|
|
|
$VERSION = '0.7'; |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
1; |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=head1 NAME |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
Net::IPTrie - Perl module for building IPv4 and IPv6 address space hierarchies |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
=head1 SYNOPSIS |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
use Net::IPTrie; |
20
|
|
|
|
|
|
|
my $tr = Net::IPTrie->new(version=>4); # IPv4 |
21
|
|
|
|
|
|
|
my $n = $tr->add(address=>'10.0.0.0', prefix=>8); |
22
|
|
|
|
|
|
|
my $a = $tr->add(address=>'10.0.0.1', data=>$data) # prefix defaults to 32 |
23
|
|
|
|
|
|
|
$a->parent->address eq $n->address and print "$a is within $n"; |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
# Addresses can be provided in integer (decimal) format |
26
|
|
|
|
|
|
|
# 10.0.0.7 == 167772167 |
27
|
|
|
|
|
|
|
my $b = $tr->add(iaddress=>'167772167', data=>'blah'); |
28
|
|
|
|
|
|
|
if ( my $c = $tr->find(address=>"10.0.0.7" ) { |
29
|
|
|
|
|
|
|
print $c->data; # should print "blah" |
30
|
|
|
|
|
|
|
} |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
# If the IP does not exist: |
33
|
|
|
|
|
|
|
my $d = $tr->find(address=>"10.0.0.8") |
34
|
|
|
|
|
|
|
print $d->address; # should print "10.0.0.0", which is the closest parent block |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
=head1 DESCRIPTION |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
This module uses a radix tree (or trie) to quickly build the hierarchy of a given address space |
39
|
|
|
|
|
|
|
(both IPv4 and IPv6). This allows the user to perform fast subnet or routing lookups. |
40
|
|
|
|
|
|
|
It is implemented exclusively in Perl. |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=head1 CLASS METHODS |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=head2 new - Class Constructor |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
Arguments: |
47
|
|
|
|
|
|
|
Hash with the following keys: |
48
|
|
|
|
|
|
|
version - IP version (4|6) |
49
|
|
|
|
|
|
|
Returns: |
50
|
|
|
|
|
|
|
New Net::IPTrie object |
51
|
|
|
|
|
|
|
Examples: |
52
|
|
|
|
|
|
|
my $tr = Net::IPTrie->new(version=>4); |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
=cut |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
sub new { |
57
|
2
|
|
|
2
|
1
|
773
|
my ($proto, %argv) = @_; |
58
|
2
|
50
|
|
|
|
10
|
croak "Missing required parameters: version" unless defined $argv{version}; |
59
|
2
|
|
33
|
|
|
13
|
my $class = ref($proto) || $proto; |
60
|
2
|
|
|
|
|
6
|
my $self = {}; |
61
|
2
|
100
|
|
|
|
11
|
if ( $argv{version} == 4 ){ |
|
|
50
|
|
|
|
|
|
62
|
1
|
|
|
|
|
5
|
$self->{_size} = 32; |
63
|
|
|
|
|
|
|
}elsif ( $argv{version} == 6 ){ |
64
|
|
|
|
|
|
|
# IPv6 numbers are larger than what a normal integer can hold |
65
|
1
|
|
|
1
|
|
3125
|
use bigint; |
|
1
|
|
|
|
|
5001
|
|
|
1
|
|
|
|
|
7
|
|
66
|
1
|
|
|
|
|
4
|
$self->{_size} = 128; |
67
|
|
|
|
|
|
|
}else{ |
68
|
0
|
|
|
|
|
0
|
croak("Invalid IP version: $argv{version}"); |
69
|
|
|
|
|
|
|
} |
70
|
2
|
|
|
|
|
7
|
$self->{_version} = $argv{version}; |
71
|
2
|
|
|
|
|
19
|
$self->{_trie} = Net::IPTrie::Node->new(); |
72
|
2
|
|
|
|
|
5
|
bless $self, $class; |
73
|
2
|
|
|
|
|
8
|
return $self; |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
############################################################################ |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
=head1 INSTANCE METHODS |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
=head2 version - Set or get IP version (4 or 6) |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
Arguments: |
83
|
|
|
|
|
|
|
IP version (4 or 6) - optional |
84
|
|
|
|
|
|
|
Returns: |
85
|
|
|
|
|
|
|
version (4 or 6) |
86
|
|
|
|
|
|
|
Examples: |
87
|
|
|
|
|
|
|
print $tr->version; |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
=cut |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
sub version { |
92
|
12
|
|
|
12
|
1
|
24
|
my ($self, $v) = @_; |
93
|
12
|
50
|
|
|
|
53
|
croak "version is an instance method" unless ref($self); |
94
|
|
|
|
|
|
|
|
95
|
12
|
50
|
|
|
|
32
|
$self->{_version} = $v if ( defined $v ); |
96
|
12
|
|
|
|
|
50
|
return $self->{_version}; |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
############################################################################ |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
=head2 size - Set or get IP size (32 or 128) |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
Arguments: |
104
|
|
|
|
|
|
|
Size (32 or 128) - optional |
105
|
|
|
|
|
|
|
Returns: |
106
|
|
|
|
|
|
|
Address size in bits (32 or 128) |
107
|
|
|
|
|
|
|
Examples: |
108
|
|
|
|
|
|
|
print $tr->size; |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
=cut |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
sub size { |
113
|
585
|
|
|
585
|
1
|
26560
|
my ($self, $s) = @_; |
114
|
585
|
50
|
|
|
|
1253
|
croak "size is an instance method" unless ref($self); |
115
|
585
|
50
|
|
|
|
1192
|
$self->{_size} = $s if ( defined $s ); |
116
|
585
|
|
|
|
|
2280
|
return $self->{_size}; |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
############################################################################ |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
=head2 find - Find an IP object in the trie |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
If the given IP does not exist, there are two options: |
124
|
|
|
|
|
|
|
a) If the "deep" flag is off, the closest covering IP block is returned. This is |
125
|
|
|
|
|
|
|
the default behavior. |
126
|
|
|
|
|
|
|
b) If the "deep" flag is on, the node where the searched IP should be inserted is returned. |
127
|
|
|
|
|
|
|
This is basically only useful for the "add" method. |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
Arguments: |
130
|
|
|
|
|
|
|
Hash with following keys: |
131
|
|
|
|
|
|
|
address - String (i.e. "10.0.0.1") address |
132
|
|
|
|
|
|
|
iaddress - Integer (i.e. "167772161") address, IPv4 or IPv6. |
133
|
|
|
|
|
|
|
prefix - Prefix Length (optional - defaults to host mask) |
134
|
|
|
|
|
|
|
deep - Flag (optional). If not found, return the node where object should be inserted. |
135
|
|
|
|
|
|
|
Returns: |
136
|
|
|
|
|
|
|
Net::IPTrie::Node object. |
137
|
|
|
|
|
|
|
Examples: |
138
|
|
|
|
|
|
|
my $n = $tr->find("10.0.0.1", 32); |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
=cut |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
sub find { |
143
|
12
|
|
|
12
|
1
|
1467
|
my ($self, %argv) = @_; |
144
|
12
|
50
|
|
|
|
42
|
croak "find is an instance method" unless ref($self); |
145
|
|
|
|
|
|
|
|
146
|
12
|
|
|
|
|
42
|
my ($address, $iaddress, $prefix, $deep) = @argv{'address', 'iaddress', 'prefix', 'deep'}; |
147
|
12
|
50
|
66
|
|
|
66
|
croak "Missing required arguments: address or iaddress" |
148
|
|
|
|
|
|
|
unless (defined $address || defined $iaddress); |
149
|
|
|
|
|
|
|
|
150
|
12
|
100
|
|
|
|
43
|
$prefix = $self->size unless ( defined $prefix ); |
151
|
12
|
|
|
|
|
26
|
my $p = $self->{_trie}; # pointer that starts at the root |
152
|
12
|
|
|
|
|
34
|
my $bit = $self->size; # Start at the most significant bit |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
# Convert string address into integer if necessary |
155
|
12
|
100
|
66
|
|
|
42
|
if ( defined $address && !defined $iaddress ){ |
156
|
3
|
|
|
|
|
12
|
$iaddress = $self->_ip2int($address); |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
|
159
|
12
|
|
|
|
|
81
|
while ( $bit > $self->size - $prefix ){ |
160
|
471
|
|
|
|
|
54365
|
$bit--; |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
# bit comparison. |
163
|
471
|
100
|
|
|
|
13586
|
my $r = ($iaddress & 2**$bit) == 0 ? 'left' : 'right'; |
164
|
|
|
|
|
|
|
|
165
|
471
|
100
|
|
|
|
233986
|
if ( !defined $p->$r ){ |
166
|
164
|
100
|
|
|
|
1378
|
if ( $deep ){ |
167
|
|
|
|
|
|
|
# Insert new node |
168
|
163
|
|
|
|
|
561
|
$p->$r(Net::IPTrie::Node->new(up=>$p)); |
169
|
|
|
|
|
|
|
}else{ |
170
|
|
|
|
|
|
|
# Just return the closest covering IP block |
171
|
1
|
50
|
|
|
|
24
|
if ( $p->iaddress ){ |
172
|
0
|
|
|
|
|
0
|
return $p; |
173
|
|
|
|
|
|
|
}else{ |
174
|
1
|
|
|
|
|
15
|
return $p->parent; |
175
|
|
|
|
|
|
|
} |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
# Walk one step down the tree |
180
|
470
|
|
|
|
|
13025
|
$p = $p->$r; |
181
|
|
|
|
|
|
|
|
182
|
470
|
100
|
100
|
|
|
12935
|
if ( defined $p->iaddress ){ |
|
|
100
|
|
|
|
|
|
183
|
|
|
|
|
|
|
# If the address matches, return node |
184
|
17
|
100
|
100
|
|
|
452
|
if ( $p->iaddress == $iaddress && $p->prefix == $prefix ){ |
185
|
1
|
|
|
|
|
37
|
return $p; |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
}elsif ( !$deep && ($bit == $self->size - $prefix) ){ |
188
|
|
|
|
|
|
|
# This is a deleted node |
189
|
1
|
|
|
|
|
7
|
return $p->parent; |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
} |
192
|
|
|
|
|
|
|
# We fell off the bottom. We tell where to create a new node. |
193
|
9
|
|
|
|
|
1513
|
return $p; |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
############################################################################ |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
=head2 add - Add an IP to the trie |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
Arguments: |
201
|
|
|
|
|
|
|
Hash with following keys: |
202
|
|
|
|
|
|
|
address - String address, IPv4 or IPv6 (i.e. "10.0.0.1") |
203
|
|
|
|
|
|
|
iaddress - Integer address, IPv4 or IPv6 (i.e. "167772161") |
204
|
|
|
|
|
|
|
prefix - Prefix Length (optional - defaults to host mask) |
205
|
|
|
|
|
|
|
data - Data (optional) |
206
|
|
|
|
|
|
|
Returns: |
207
|
|
|
|
|
|
|
New Net::IPTrie::Node object |
208
|
|
|
|
|
|
|
Examples: |
209
|
|
|
|
|
|
|
my $n = $tr->add(address=>"10.0.0.1", prefix=>32, data=>\$data); |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
=cut |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
sub add { |
214
|
9
|
|
|
9
|
1
|
5040
|
my ($self, %argv) = @_; |
215
|
9
|
50
|
|
|
|
40
|
croak "add is an instance method" unless ref($self); |
216
|
|
|
|
|
|
|
|
217
|
9
|
|
|
|
|
29
|
my ($address, $iaddress, $prefix, $data) = @argv{'address', 'iaddress', 'prefix', 'data'}; |
218
|
9
|
50
|
66
|
|
|
40
|
croak "Missing required arguments: address\n" |
219
|
|
|
|
|
|
|
unless ( defined $address || defined $iaddress ); |
220
|
|
|
|
|
|
|
|
221
|
9
|
100
|
|
|
|
32
|
$prefix = $self->size unless ( defined $prefix ); |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
# Convert string address into integer if necessary |
224
|
9
|
100
|
66
|
|
|
76
|
if ( defined $address && !defined $iaddress ){ |
|
|
50
|
33
|
|
|
|
|
225
|
8
|
|
|
|
|
31
|
$iaddress = $self->_ip2int($address); |
226
|
|
|
|
|
|
|
}elsif ( defined $iaddress && !defined $address ){ |
227
|
1
|
|
|
|
|
6
|
$address = $self->_int2ip($iaddress); |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
|
230
|
9
|
|
|
|
|
303
|
my $n = $self->find(iaddress=>$iaddress, prefix=>$prefix, deep=>1); |
231
|
|
|
|
|
|
|
|
232
|
9
|
50
|
33
|
|
|
234
|
unless ( defined $n->iaddress && $n->iaddress == $iaddress ){ |
233
|
9
|
|
|
|
|
262
|
$n->iaddress($iaddress); |
234
|
9
|
|
|
|
|
243
|
$n->address($address); |
235
|
9
|
|
|
|
|
238
|
$n->prefix($prefix); |
236
|
9
|
|
|
|
|
234
|
$n->data($data); |
237
|
|
|
|
|
|
|
} |
238
|
9
|
|
|
|
|
167
|
return $n; |
239
|
|
|
|
|
|
|
} |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
############################################################################ |
243
|
|
|
|
|
|
|
=head2 traverse - Traverse every node in the tree |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
Arguments: |
246
|
|
|
|
|
|
|
root - node object (optional - defaults to tree root) |
247
|
|
|
|
|
|
|
code - coderef (will be passed the Net::IPTrie::Node object to act upon) |
248
|
|
|
|
|
|
|
mode - (depth_first only, for now) |
249
|
|
|
|
|
|
|
Returns: |
250
|
|
|
|
|
|
|
Number of actual IP nodes visited |
251
|
|
|
|
|
|
|
Examples: |
252
|
|
|
|
|
|
|
# Store all IP nodes in an array, ordered. |
253
|
|
|
|
|
|
|
my $list = (); |
254
|
|
|
|
|
|
|
my $code = sub { push @$list, shift @_ }; |
255
|
|
|
|
|
|
|
my $count = $tr->traverse(code=>$code); |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
=cut |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
sub traverse { |
260
|
1
|
|
|
1
|
0
|
1371
|
my ($self, %argv) = @_; |
261
|
1
|
50
|
|
|
|
7
|
croak "traverse is an instance method" unless ref($self); |
262
|
1
|
|
|
|
|
4
|
my ($root, $code, $mode) = @argv{'root', 'code', 'mode'}; |
263
|
|
|
|
|
|
|
|
264
|
1
|
|
33
|
|
|
12
|
my $p = $root || $self->{_trie}; |
265
|
1
|
|
|
|
|
3
|
my $count = 0; |
266
|
1
|
|
|
|
|
4
|
$mode |= 'depth_first'; |
267
|
1
|
50
|
|
|
|
4
|
if ( $mode eq 'depth_first' ){ |
268
|
1
|
|
|
|
|
7
|
$self->_depth_first(node=>$p, code=>$code, count=>\$count); |
269
|
|
|
|
|
|
|
}else{ |
270
|
0
|
|
|
|
|
0
|
croak "Unknown climb mode: $mode"; |
271
|
|
|
|
|
|
|
} |
272
|
1
|
|
|
|
|
13
|
return $count; |
273
|
|
|
|
|
|
|
} |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
############################################################################ |
277
|
|
|
|
|
|
|
# |
278
|
|
|
|
|
|
|
# PRIVATE METHODS |
279
|
|
|
|
|
|
|
# |
280
|
|
|
|
|
|
|
############################################################################ |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
############################################################################ |
284
|
|
|
|
|
|
|
# _ip2int - Convert string IP to integer |
285
|
|
|
|
|
|
|
# |
286
|
|
|
|
|
|
|
# Arguments: |
287
|
|
|
|
|
|
|
# IP address in string format ('10.0.0.1') |
288
|
|
|
|
|
|
|
# Returns: |
289
|
|
|
|
|
|
|
# IP address in integer format |
290
|
|
|
|
|
|
|
# Examples: |
291
|
|
|
|
|
|
|
# my $number = $tr->ip2int('10.0.0.1'); |
292
|
|
|
|
|
|
|
# |
293
|
|
|
|
|
|
|
sub _ip2int { |
294
|
11
|
|
|
11
|
|
19
|
my ($self, $ip) = @_; |
295
|
11
|
|
|
|
|
17
|
my $nip; |
296
|
11
|
100
|
|
|
|
47
|
if ( $self->version == 4 ){ |
297
|
7
|
|
|
|
|
51
|
$nip = NetAddr::IP->new($ip); |
298
|
|
|
|
|
|
|
}else{ |
299
|
4
|
|
|
|
|
37
|
$nip = NetAddr::IP->new6($ip); |
300
|
|
|
|
|
|
|
} |
301
|
11
|
50
|
|
|
|
2506
|
croak "Invalid IP: $ip" unless $nip; |
302
|
11
|
|
|
|
|
2997
|
return $nip->numeric; |
303
|
|
|
|
|
|
|
} |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
############################################################################ |
306
|
|
|
|
|
|
|
# _int2ip - Convert integer IP to string |
307
|
|
|
|
|
|
|
# |
308
|
|
|
|
|
|
|
# Arguments: |
309
|
|
|
|
|
|
|
# IP address in integer format |
310
|
|
|
|
|
|
|
# Returns: |
311
|
|
|
|
|
|
|
# IP address in string format |
312
|
|
|
|
|
|
|
# Examples: |
313
|
|
|
|
|
|
|
# my $dottedquad = $tr->_int2ip(167772161); |
314
|
|
|
|
|
|
|
# |
315
|
|
|
|
|
|
|
sub _int2ip { |
316
|
1
|
|
|
1
|
|
2
|
my ($self, $int) = @_; |
317
|
1
|
|
|
|
|
3
|
my $nip; |
318
|
1
|
50
|
|
|
|
4
|
if ( $self->version == 4 ){ |
319
|
1
|
|
|
|
|
11
|
$nip = NetAddr::IP->new($int); |
320
|
|
|
|
|
|
|
}else{ |
321
|
0
|
|
|
|
|
0
|
$nip = NetAddr::IP->new6($int); |
322
|
|
|
|
|
|
|
} |
323
|
1
|
50
|
|
|
|
44
|
croak "Invalid IP integer: $int" unless $nip; |
324
|
1
|
|
|
|
|
288
|
return $nip->addr; |
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
############################################################################ |
328
|
|
|
|
|
|
|
# _depth_first - Recursively visit each node in depth-first mode |
329
|
|
|
|
|
|
|
# |
330
|
|
|
|
|
|
|
# Arguments: |
331
|
|
|
|
|
|
|
# Hash with following key/value pairs: |
332
|
|
|
|
|
|
|
# node - Starting node |
333
|
|
|
|
|
|
|
# code - coderef (will be passed the Net::IPTrie::Node object to act upon) |
334
|
|
|
|
|
|
|
# count - Scalar reference |
335
|
|
|
|
|
|
|
# Returns: |
336
|
|
|
|
|
|
|
# Examples: |
337
|
|
|
|
|
|
|
# |
338
|
|
|
|
|
|
|
# |
339
|
|
|
|
|
|
|
sub _depth_first { |
340
|
36
|
|
|
36
|
|
1225
|
my ($self, %argv) = @_; |
341
|
36
|
|
|
|
|
67
|
my ($n, $code, $count) = @argv{'node', 'code', 'count'}; |
342
|
|
|
|
|
|
|
|
343
|
36
|
100
|
|
|
|
744
|
if ( $n->address ){ |
344
|
5
|
50
|
33
|
|
|
60
|
if ( defined $code && ref($code) eq "CODE" ){ |
345
|
|
|
|
|
|
|
# execute code |
346
|
5
|
|
|
|
|
13
|
$code->($n); |
347
|
|
|
|
|
|
|
} |
348
|
5
|
|
|
|
|
17
|
$$count++; |
349
|
|
|
|
|
|
|
} |
350
|
36
|
100
|
|
|
|
870
|
$self->_depth_first(node=>$n->left, code=>$code, count=>$count) if ( defined $n->left ); |
351
|
36
|
100
|
|
|
|
922
|
$self->_depth_first(node=>$n->right, code=>$code, count=>$count) if ( defined $n->right ); |
352
|
|
|
|
|
|
|
} |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
=head1 AUTHOR |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
Carlos Vicente |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
=head1 SEE ALSO |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
Net::IPTrie::Node |
361
|
|
|
|
|
|
|
Net::Patricia |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
=head1 LICENCE AND COPYRIGHT |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
Copyright (c) 2007-2010, Carlos Vicente . All rights reserved. |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
This module is free software; you can redistribute it and/or |
368
|
|
|
|
|
|
|
modify it under the same terms as Perl itself. See L. |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
=head1 DISCLAIMER OF WARRANTY |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY |
374
|
|
|
|
|
|
|
FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN |
375
|
|
|
|
|
|
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES |
376
|
|
|
|
|
|
|
PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER |
377
|
|
|
|
|
|
|
EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
378
|
|
|
|
|
|
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE |
379
|
|
|
|
|
|
|
ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH |
380
|
|
|
|
|
|
|
YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL |
381
|
|
|
|
|
|
|
NECESSARY SERVICING, REPAIR, OR CORRECTION. |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING |
384
|
|
|
|
|
|
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR |
385
|
|
|
|
|
|
|
REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE |
386
|
|
|
|
|
|
|
LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, |
387
|
|
|
|
|
|
|
OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE |
388
|
|
|
|
|
|
|
THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING |
389
|
|
|
|
|
|
|
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A |
390
|
|
|
|
|
|
|
FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF |
391
|
|
|
|
|
|
|
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF |
392
|
|
|
|
|
|
|
SUCH DAMAGES. |
393
|
|
|
|
|
|
|
=cut |