perlinterval-tree

Set::IntervalTree acting weirdly when I add nodes through a loop in perl


I am trying to use the Set::IntervalTree module and I think it is giving me the same node pointers if I insert the elements in a loop.

If I insert them outside a loop sequentially one after the another the nodes are inserted fine and the find / find_window calls works perfectly. But on the nodes which were added in the loop, the find functions give strange results.

#!/usr/bin/perl

use Set::IntervalTree;
my $tree = Set::IntervalTree->new;

$tree->insert("60:70", 60, 70);
$tree->insert("70:80", 70, 80);
$tree->insert("80:90", 80, 90);

for(my $i = 0; $i < 60; $i=$i+10)
{
    $j = $i+10;
    print "$i".":"."$j\n";
    $tree->insert("$i".":"."$j", $i, $i+10);
}

print $tree->str;

my $results1 = $tree->fetch(25, 28);
my $window = $tree->fetch_window(25,250);
my @arr1 = @$results1;
print " @arr1 found.\n";

my $results2 = $tree->fetch(65, 68);
my @arr2 = @$results2;
print " @arr2 found.\n";

This is the output. Check the node pointers.. the ones added from the loop have same pointers and they return wrong interval (which i guess is due to the same pointer values.)

Node:0x9905b20, k=0, h=9, mH=9  l->key=NULL  r->key=NULL  p->key=10  color=BLACK
Node:0x9905b20, k=10, h=19, mH=29  l->key=0  r->key=20  p->key=30  color=RED
Node:0x9905b20, k=20, h=29, mH=29  l->key=NULL  r->key=NULL  p->key=10  color=BLACK
Node:0x9905b20, k=30, h=39, mH=89  l->key=10  r->key=70  p->key=NULL  color=BLACK
Node:0x9905b20, k=40, h=49, mH=49  l->key=NULL  r->key=NULL  p->key=50  color=RED
Node:0x9905b20, k=50, h=59, mH=69  l->key=40  r->key=60  p->key=70  color=BLACK
Node:0x98c6270, k=60, h=69, mH=69  l->key=NULL  r->key=NULL  p->key=50  color=RED
Node:0x98fd138, k=70, h=79, mH=89  l->key=50  r->key=80  p->key=30  color=RED
Node:0x98fd078, k=80, h=89, mH=89  l->key=NULL  r->key=NULL  p->key=70  color=BLACK

 50:60 found.
 60:70 found.

Solution

  • It looks like you have to use a Perl scalar variable if you are calling insert from an inner block. If you use an interpolated string it will be discarded and overwritten by the subsequent execution of the block.

    This code seems to work fine. Please always use strict and use warnings on all your programs - particularly those you are asking for help with.

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    use Set::IntervalTree;
    my $tree = Set::IntervalTree->new;
    
    for (my $i = 0; $i <= 80; $i += 10) {
        my $name = sprintf '%02d:%02d', $i, $i+10;
        $tree->insert($name, $i, $i+10);
    }
    
    my $results1 = $tree->fetch(25, 28);
    print "@$results1 found\n";
    
    my $results2 = $tree->fetch(65, 68);
    print "@$results2 found\n";
    

    output

    20:30 found
    60:70 found