R
Rainer Weikusat
Instead of trying another explanation of the 'it is a name given to a
value' versus 'it is a register' issue, I thought I should rather try
an example.
Introductory remarks: The subroutine whose code is included below
takes two sorted lists of 'DNS [reverse] domain objects' as arguments
(represented as references to arrays[*]) and is supposed to produce an
output list of all objects on the first input list which don't
'conflict' with the items on the filter list. One application this is
put to is to determine which RFC1918 reverse zones still need to be
'terminated' on some DNS server, given a list of reverse domains
configured by a customer which may cover some or all of the RFC1918
address space(s).
The subroutine could be regarded as a software emulation of a
seriously 'high-level' special purpose IC performing the same
operation. In particular, it has a set of 'working registers'
(represented as my variables) whose contents change as the algorithm
proceeds. This is something totally different from 'assigning a
[transient] name to a value' and not at all closely related to
'programming a general purpose IC using its machine language'.
The return value of the net_compare method call is stored using list
assignment because this method returns a list of two values in some
cases, the first of which is interesting to this subroutine ('is it
before or behind') the second ('is it immediately adjacent to the
other object') is used by another subroutine.
[*] Contrary to another, immensely popular myth, using linked
lists instead of arrays, based on using anonymous 2-element
arrays for representing 'cons cells', is actually faster for
algorithms like this, especially if the lists become
large. For this particular case, they're expected to be small
and the operation performed infrequently (whenever someone
changes the configuration in the GUI), hence, the more
convenient approach was chosen.
sub filter_against
{
my ($in, $filter) = @_;
my ($in_item, $in_pos, $filter_item, $filter_pos);
my (@out, $step_in, $step_filter, $rc);
$in_pos = 0;
$in_item = $in->[0];
$step_in = sub {
last LOOP if ++$in_pos == @$in;
$in_item = $in->[$in_pos];
};
$filter_pos = 0;
$filter_item = $filter->[0];
$step_filter = sub {
last LOOP if ++$filter_pos == @$filter;
$filter_item = $filter->[$filter_pos];
};
LOOP: {
($rc) = $in_item->net_compare($filter_item);
p_alloc('in %s, filter %s, rc %u',
$in_item, $filter_item, $rc);
given ($rc) {
when (R_AFTER) {
push(@out, $in_item);
&$step_in;
}
when ([R_BEFORE, R_SUB]) {
&$step_filter;
}
when ([R_SAME, R_SUPER]) {
p_alloc('%s: dropping %s (%s)', __func__,
$in_item, $filter_item);
&$step_in;
}
}
redo;
}
push(@out, @$in[$in_pos .. $#$in]);
return \@out;
}
[This code is copyrighted by my employer and cited here for
educational purposes].
value' versus 'it is a register' issue, I thought I should rather try
an example.
Introductory remarks: The subroutine whose code is included below
takes two sorted lists of 'DNS [reverse] domain objects' as arguments
(represented as references to arrays[*]) and is supposed to produce an
output list of all objects on the first input list which don't
'conflict' with the items on the filter list. One application this is
put to is to determine which RFC1918 reverse zones still need to be
'terminated' on some DNS server, given a list of reverse domains
configured by a customer which may cover some or all of the RFC1918
address space(s).
The subroutine could be regarded as a software emulation of a
seriously 'high-level' special purpose IC performing the same
operation. In particular, it has a set of 'working registers'
(represented as my variables) whose contents change as the algorithm
proceeds. This is something totally different from 'assigning a
[transient] name to a value' and not at all closely related to
'programming a general purpose IC using its machine language'.
The return value of the net_compare method call is stored using list
assignment because this method returns a list of two values in some
cases, the first of which is interesting to this subroutine ('is it
before or behind') the second ('is it immediately adjacent to the
other object') is used by another subroutine.
[*] Contrary to another, immensely popular myth, using linked
lists instead of arrays, based on using anonymous 2-element
arrays for representing 'cons cells', is actually faster for
algorithms like this, especially if the lists become
large. For this particular case, they're expected to be small
and the operation performed infrequently (whenever someone
changes the configuration in the GUI), hence, the more
convenient approach was chosen.
sub filter_against
{
my ($in, $filter) = @_;
my ($in_item, $in_pos, $filter_item, $filter_pos);
my (@out, $step_in, $step_filter, $rc);
$in_pos = 0;
$in_item = $in->[0];
$step_in = sub {
last LOOP if ++$in_pos == @$in;
$in_item = $in->[$in_pos];
};
$filter_pos = 0;
$filter_item = $filter->[0];
$step_filter = sub {
last LOOP if ++$filter_pos == @$filter;
$filter_item = $filter->[$filter_pos];
};
LOOP: {
($rc) = $in_item->net_compare($filter_item);
p_alloc('in %s, filter %s, rc %u',
$in_item, $filter_item, $rc);
given ($rc) {
when (R_AFTER) {
push(@out, $in_item);
&$step_in;
}
when ([R_BEFORE, R_SUB]) {
&$step_filter;
}
when ([R_SAME, R_SUPER]) {
p_alloc('%s: dropping %s (%s)', __func__,
$in_item, $filter_item);
&$step_in;
}
}
redo;
}
push(@out, @$in[$in_pos .. $#$in]);
return \@out;
}
[This code is copyrighted by my employer and cited here for
educational purposes].