Data::Util (Scalar::Util::Refから改名+α)

Data::Util
こんな汎用的な名前を付けてしまっていいのだろうかと思いつつリリース。

sv_derived_from()はもっと高速に実装できるはず,というアイデアを取り込んでみました*1
use Data::Utilするときに-fast_isaオプションをつけると,UNIVERSAL::isaを高速版なバージョンで上書きします。高速版はUNIVERSAL::isaと比較するとこんな感じ。実行環境はPerl 5.8.5 on Linuxで,5.10以降だともう少しだけ速くなるはずです。

[Data-Util-0.02_01]$ perl -Mblib example/isa_bench.pl
Benchmark: UNIVERSAL::isa vs. Data::Util::fast_isa

For Foo=HASH(0x94ac538)
             Rate original fast_isa
original 114688/s       --     -32%
fast_isa 168658/s      47%       --

For Foo::X::X=HASH(0x95ba458)
             Rate original fast_isa
original  84328/s       --     -27%
fast_isa 114975/s      36%       --

For Unrelated=HASH(0x95bb2fc)
             Rate original fast_isa
original  87061/s       --     -29%
fast_isa 122880/s      41%       --

とまあ,けっこう速いです。

以下ベンチマークコード:

#!perl -w

use strict;
use Benchmark qw(:all);

use Data::Util qw(neat);

BEGIN{
	*UNIVERSAL::fast_isa = \&Data::Util::fast_isa;
}

BEGIN{
	package Base;
	sub new{
		bless {} => shift;
	}
	
	package Foo;
	our @ISA = qw(Base);
	package Foo::X;
	our @ISA = qw(Foo);
	package Foo::X::X;
	our @ISA = qw(Foo::X);

	package Unrelated;
	our @ISA = qw(Base);
}

print "Perl $] on $^O\n";
print "Benchmark: UNIVERSAL::isa vs. Data::Util::fast_isa\n";

foreach my $x (
#	qw(Foo Foo::X::X Unrelated),
	Foo->new, Foo::X::X->new, Unrelated->new){

	print "\nFor ", neat($x), "\n";
	cmpthese -1 => {
		'original' => sub{
			for(1 .. 10){
				if($x->isa('Foo')){
					;
				}
			}
		},
		'fast_isa' => sub{
			for(1 .. 10){
				if($x->fast_isa('Foo')){
					;
				}
			}
		},
	};
}
__END__

*1:元のエントリだと3倍速くなったとあるけど,Cygwinでない環境で試すと流石にそこまで速くはなりませんでした。