#!/usr/bin/env perl use warnings; use strict; use Benchmark qw':all'; my %rot = ( 'A' => 'N','B' => 'O','C' => 'P','D' => 'Q','E' => 'R','F' => 'S', 'G' => 'T','H' => 'U','I' => 'V','J' => 'W','K' => 'X','L' => 'Y', 'M' => 'Z','N' => 'A','O' => 'B','P' => 'C','Q' => 'D','R' => 'E', 'S' => 'F','T' => 'G','U' => 'H','V' => 'I','W' => 'J','X' => 'K', 'Y' => 'L','Z' => 'M','a' => 'n','b' => 'o','c' => 'p','d' => 'q', 'e' => 'r','f' => 's','g' => 't','h' => 'u','i' => 'v','j' => 'w', 'k' => 'x','l' => 'y','m' => 'z','n' => 'a','o' => 'b','p' => 'c', 'q' => 'd','r' => 'e','s' => 'f','t' => 'g','u' => 'h','v' => 'i', 'w' => 'j','x' => 'k','y' => 'l','z' => 'm', ); our(%sub, @subname); sub rot13sub { my($name, $code) = @_; push @subname, $name; $sub{$name} = $code; } #### # The original subroutine rot13sub "orig", sub { # as close as possible to source project's code join '', map { exists $rot{$_} ? $rot{$_} : $_ } split('',shift); }; # Firstly, let's fill in the defaults in the hash table so that we # can use a hash slice my %rotd = %rot; exists($rotd{$_}) or $rotd{$_} = $_ for map chr, 0 .. 255; rot13sub "hashslice-s", sub { join '', @rotd{split('',shift)}; }; #### # Two variants instead of the split rot13sub "hashslice-m", sub { my ($x) = @_; my @t = $x =~ /./gs; join '', @rotd{@t}; }; rot13sub "hashslice-u", sub { my ($x) = @_; join '', @rotd{unpack "(a)*", $x}; }; #### # Now let's use an array slice instead of a hash my @rot = do { my $c; map { $c = chr($_); exists $rot{$c} ? ord($rot{$c}) : $_ } 0 .. 255; }; rot13sub "arrayslice", sub { pack "C*", @rot[unpack("C*", $_[0])]; }; # Now let's try some solutions with s, as demerphq has suggested. # The first one has to know the exact character range to be replaced. rot13sub "gsub-class", sub { (my $s = $_[0]) =~ s/([a-zA-Z])/$rot{$1}/g; $s; }; rot13sub "gsub-dot", sub { (my $s = $_[0]) =~ s/(.)/$rotd{$1}/gs; $s; }; # Now your tr equivalent rot13sub "tr", sub { (my $s = shift) =~ tr/a-zA-Z/n-za-mN-ZA-M/; $s; }; #### # First, check correctness. This is important. our $data = join "", ; our $correct = &{$sub{"orig"}}($data); print $correct; { for my $name (@subname) { my $result = &{$sub{$name}}($data); $correct eq $result or die "error: subroutine $name produces incorrect result"; } warn "all ok"; } # Next, compare them. { cmpthese(-5, {map { my($name, $sub) = ($_, $sub{$_}); $name, sub { my $r = &$sub($data); } } @subname}); } __DATA__ Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vivamus luctus nulla sed tellus. Sed vitae sapien in elit vestibulum faucibus. Maecenas sollicitudin, magna quis vestibulum convallis, ligula nulla fringilla augue, nec rutrum dolor quam vel justo. Vivamus nisi odio, ullamcorper sed, venenatis id, imperdiet eleifend, neque. Vivamus justo felis, euismod in, convallis auctor, egestas id, purus. In rutrum nisi in lectus. Aliquam elementum placerat dui. Integer ut pede sit amet magna pulvinar placerat. Maecenas massa lorem, lobortis ut, adipiscing at, suscipit nec, lectus. Curabitur mattis adipiscing sem. Mauris pharetra vehicula eros. Sed pellentesque elit laoreet augue. Cras non tellus. Quisque volutpat lectus in sem. Fusce vulputate justo ut pede. Aliquam ante pede, tempor in, dictum in, blandit eu, sapien. Morbi vestibulum, metus eu auctor vulputate, nulla lectus condimentum nisi, ac pulvinar ligula nunc in felis. Curabitur id orci ac est luctus molestie. #### Rate orig hashslice-m gsub-dot hashslice-s gsub-class hashslice-u arrayslice tr orig 962/s -- -20% -30% -40% -43% -58% -82% -99% hashslice-m 1206/s 25% -- -12% -25% -29% -47% -78% -99% gsub-dot 1372/s 43% 14% -- -15% -19% -40% -75% -99% hashslice-s 1605/s 67% 33% 17% -- -5% -30% -70% -99% gsub-class 1687/s 75% 40% 23% 5% -- -26% -69% -99% hashslice-u 2278/s 137% 89% 66% 42% 35% -- -58% -98% arrayslice 5414/s 463% 349% 295% 237% 221% 138% -- -96% tr 148174/s 15308% 12184% 10701% 9135% 8681% 6403% 2637% --