tokuhirom's blog.

'; DROP DATABASE database();

XSレベルで引数をチェックする

XS レベルで undef がわたされたかどうかを確認するには SvOK() をつかえばいいです。

       SvOK    Returns a U32 value indicating whether the value is an SV. It
               also tells whether the value is defined or not.

                       U32     SvOK(SV* sv)

これをつかって、

#define MYASSERT(expr)                                           \
    if (!(expr)) {                                               \
        if (SvTRUE(get_sv("TokyoCabinet::DEBUG", FALSE))) {      \
            Perl_croak(aTHX_ "TokyoCabinet: invalid parameter"); \
        }                                                        \
        XSRETURN_UNDEF;                                          \
    }

などと定義しておくと、

MYASSERT( SvOK(key) && SvOK(val) );

のようにつかえます。これでもう安心です。

perl xs では、typemap という仕組みをつかって、変換表をもちいた型の自動変換を引数と返り値にかけられます。これをつかって

foo(const char *str)

などと定義してしまうと、typemap が勝手に SvPV を実行してしまって、undef かどうかをチェックできないので

foo(SV* _str)
PREINIT:
  char *str;
CODE:
  MYASSERT( SvOK(_str) );
  str = SvPV_nolen(_str);

などという風に、引数では SV* をうけとるようにして、undef かどうかのチェックをしてから明示的に char * に変換するとよいです。

なお、引数の数は、xsubpp が勝手にチェックしてくれるので気にする必要はありません。

parrot で簡単な pir をかいてみる

pir は、parrot 用の超高級マクロアセンブラっぽいなにかだとおもっておけばいい。

hello world はこう。

.sub main :main
    print "Hello, PIR world!\n"
.end

1000 回ぐらいループをまわしたときの時間をはかるスクリプトはこう。

.sub main :main
    time $N0
    $I0 = 0
START:
    if $I0>1000 goto END
    $I0 += 1
    goto START
END:
    time $N1
    $N1 -= $N0
    print $N1
    print "\n"
.end

ちなみに結果は 5.81741333007812e-05 sec とか。perl5 だと 7.29560852050781e-05 sec とか。
rakudo だと 0.676993131637573 sec とか。

rakudo が遅すぎて、逆に、どうやったらここまで遅くなるのかと疑問におもう。

IO::Socket::INET を perl6 で。

use v6;
use IO::Socket::INET;

my $sock = IO::Socket::INET.new();
$sock.open('google.com', 80);
$sock.send("GET / HTTP/1.0\r\n\r\n");  
say $sock.recv();
$sock.close();

rakudo の dev-release の 2009-04 版では IO::Socket::INET もつかえるようになったので、ためしにつかってみた。

rakudo は parrot の上でうごく perl6 実装。parrot は perl6 のために実装された VM だけど、ターゲットとしてはあらゆる言語が parrot の上でうごくことを理想としている。

両方ともまだまだ開発途上だけど、1ヶ月に一回 dev-release されてる。

rakudo をためすには

# 依存してるものをいろいろいれる。debian lenny じゃない場合は適当に自分でいれてください
aptitude install build-essential libicu38-dev subversion git-core
# rakudo を github からもってくる
git clone git://github.com/rakudo/rakudo.git

cd rakudo
# parrot を svn co しつつ、設定もろもろ
perl Configure.pl --gen-parrot
# コンパイルまくり
make

# できあがったらこういう風にあそべるよ
./perl6 -e "say 'Hello, world!'"

現状としては

  • 意外とうごく
  • 昔にくらべると試すのが超簡単
  • まだ perl6 の spec を満たしてない
  • 死ぬほど遅い。for (0..1000) { } が 0.6 sec ぐらいかかる

といったかんじ?