Skip to content

Instantly share code, notes, and snippets.

@nnutter
Last active August 29, 2015 14:01
Show Gist options
  • Save nnutter/8be0c937fb810d185fd3 to your computer and use it in GitHub Desktop.
Save nnutter/8be0c937fb810d185fd3 to your computer and use it in GitHub Desktop.
package Sorter;
use strict;
use warnings;
my @chromosome = (1..22, 'X', 'Y', 'MT');
# don't leave it up to humans unless you need to!
sub index_of {
my $i = 0;
return map { $_ => $i++ } @_;
}
my %index = index_of(@chromosome);
# uses function prototype to avoid using the "magic" $a/$b vars
sub by_chromosome_proto($$) {
return ($index{$_[0]} <=> $index{$_[1]});
}
# uses fully qualified variable names to get a/b from calling package
sub by_chromosome_reflect {
# Improvements by abrummet:
# - Avoid indexing into result of caller by calling in scaler context.
# - Avoid string interpolation of $an by dereferencing instead.
my $caller_package = caller;
my ($an, $bn) = map { join('::', $caller_package, $_) } qw(a b);
no strict 'refs';
return ($index{$$an} <=> $index{$$bn});
}
# create a closure to "cache" calculation of fully qualified a/b, by abrummet
sub by_chromosome_closure {
my $caller_package = caller;
my ($an, $bn) = map { join('::', $caller_package, $_) } qw(a b);
no strict 'refs';
return sub {
return $index{$$an} <=> $index{$$bn};
}
}
package main;
use strict;
use warnings;
use Benchmark qw(cmpthese :hireswallclock);
use Test::More tests => 3;
my @input = qw(2 4 6 X 1 3 5);
my @expected = qw(1 2 3 4 5 6 X);
my $by_chromosome_closure = Sorter::by_chromosome_closure();
is_deeply([sort Sorter::by_chromosome_proto @input], \@expected, 'by_chromosome_proto worked');
is_deeply([sort Sorter::by_chromosome_reflect @input], \@expected, 'by_chromosome_reflect worked');
is_deeply([sort $by_chromosome_closure @input], \@expected, 'by_chromosome_export worked');
cmpthese(-3, {
proto => sub { sort Sorter::by_chromosome_proto @input },
reflect => sub { sort Sorter::by_chromosome_reflect @input },
scalar_caller_deref_closure => sub { sort $by_chromosome_closure @input },
});
@nnutter
Copy link
Author

nnutter commented May 22, 2014

Revision 6 introduced the several improvement to by_chromosome_reflect and added by_chromosome_closure thanks to abrummet. I think I would just default to using the prototyped function and if performance was critical I would need to look into XS as well.

Revision 6 output:

1..3
ok 1 - by_chromosome_proto worked
ok 2 - by_chromosome_reflect worked
ok 3 - by_chromosome_export worked
                                  Rate scalar_caller_deref_closure proto reflect
scalar_caller_deref_closure 14224575/s                          --   -1%     -4%
proto                       14374025/s                          1%    --     -3%
reflect                     14753962/s                          4%    3%      --

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment