Friday, June 05, 2009

Comparing CVS revision numbers with Perl

Update: see a faster version here. However, make sure that you've nailed the problem down before starting to optimize. (The profiler is your friend)

The code below was only lightly tested and isn’t all that efficient, so use it at your own risk. It returns –1 is the first version is smaller, 1 if it is bigger and 0 if they are equal. I needed it for crunching some CVS logs and I couldn’t find anything on CPAN:

use strict;
use warnings;
use Test::More tests => 8;

is(cmp_cvs_tags('1.1', '1.1'),    0);
is(cmp_cvs_tags('1.1', '1.1.1'), -1);
is(cmp_cvs_tags('1.1', '1.2'),   -1);
is(cmp_cvs_tags('1.2', '1.2'),    0);
is(cmp_cvs_tags('1.2', '1.3'),   -1);

is(cmp_cvs_tags('1.1.1', '1.1'), 1);
is(cmp_cvs_tags('1.2',   '1.1'), 1);
is(cmp_cvs_tags('1.3',   '1.1'), 1);

sub cmp_cvs_tags {
  my ($a, $b) = @_;
  my @a_lst = split /\./, $a;
  my @b_lst = split /\./, $b;
  
  my $i = 0;
  while (1) {
    return 1  if (exists($a_lst[$i])  && !exists($b_lst[$i]));
    return -1 if (!exists($a_lst[$i]) && exists($b_lst[$i]));
    return 0  if (!exists($a_lst[$i]) && !exists($b_lst[$i]));
    if ($a_lst[$i] == $b_lst[$i]) {
      ++$i;
      next;
    }
    return $a_lst[$i] <=> $b_lst[$i];
  } 
}

No comments:

Post a Comment