Data::Uniqidのsuniqidって変ですよね
cpanあたりにあったData::Uniqidというモジュールの話。大雑把にいえば、ユニークなIDをBase62で生成してくれるものなのですが、その中に、賞味期限が1日程度のユニークIDを生成してくれるsuniqidというものがあります。このsuniqidなんですが、ときどき長さゼロの文字列を返してくださるので、中身をみてみると、こんな感じでした。
gettimeofday()は、use Time::HiRes qw( gettimeofday usleep );してますので、エポックからの秒数とそのときのマイクロ秒を配列で返すものになります。$vは、見てのとおり、6桁のマイクロ秒とエポックからの秒数の下5桁を取ったものとプロセスIDを繋いだものです。マイクロ秒部分とプロセスID部分は6桁に満たない場合0がパディングされます。
ここで妙なのが、エポックからの秒数の下5桁をとっているsubstr($s,-5)なのですが、1日が86400秒なので、それなりに5桁以下になることってありますよね。しかも、この部分は%5dなので、substr($s,-5)が5桁未満の場合、$vはスペースで隙間の空いた数字列になるわけです。で、これがbase62()に渡されるわけなんですが、それがこれです。
こんなのにスペースで隙間のある数字列渡したら、($n,$v)=$v->bdiv($p[$i]);の$n,$vが共にNaNになって、$uに連結される文字は0にしかならない。結局、$u=~s/^0+//;なんてしたら、そんな場合、長さ0の文字列にしかならないし。
なんで、こんな仕様なんでしょうね。
sub suniqid { ########################################### get unique id ##### my($s,$us)=gettimeofday(); my($v)=sprintf("%06d%5d%06d",$us,substr($s,-5),$$); return(&base62($v)); }
gettimeofday()は、use Time::HiRes qw( gettimeofday usleep );してますので、エポックからの秒数とそのときのマイクロ秒を配列で返すものになります。$vは、見てのとおり、6桁のマイクロ秒とエポックからの秒数の下5桁を取ったものとプロセスIDを繋いだものです。マイクロ秒部分とプロセスID部分は6桁に満たない場合0がパディングされます。
ここで妙なのが、エポックからの秒数の下5桁をとっているsubstr($s,-5)なのですが、1日が86400秒なので、それなりに5桁以下になることってありますよね。しかも、この部分は%5dなので、substr($s,-5)が5桁未満の場合、$vはスペースで隙間の空いた数字列になるわけです。で、これがbase62()に渡されるわけなんですが、それがこれです。
sub base62() { ################################################### Base62 ##### my($s)=@_; my(@c)=('0'..'9','a'..'z','A'..'Z'); my(@p,$u,$v,$i,$n); my($m)=20; $p[0]=1; for $i (1..$m) { $p[$i]=Math::BigInt->new($p[$i-1]); $p[$i]=$p[$i]->bmul(62); } $v=Math::BigInt->new($s); for ($i=$m;$i>=0;$i--) { $v=Math::BigInt->new($v); ($n,$v)=$v->bdiv($p[$i]); $u.=$c[$n]; } $u=~s/^0+//; return($u); }
こんなのにスペースで隙間のある数字列渡したら、($n,$v)=$v->bdiv($p[$i]);の$n,$vが共にNaNになって、$uに連結される文字は0にしかならない。結局、$u=~s/^0+//;なんてしたら、そんな場合、長さ0の文字列にしかならないし。
なんで、こんな仕様なんでしょうね。
個人的には、%5dが%05dの間違いか、Mike Wesemannのワナかのどちらかではないかと思ってるだけなんですが…。
by *生保単独* (2008-10-19 03:48)