海野秀之(うんのひでゆき)の外部記憶
Twitter (twilog) / RSS / アンテナ / ぶくま
CD 買いにいかなあかん → こおた。聞くのがたのしみ。
『オブジェクト指向スクリプト言語 Ruby』をみながら、 拡張ライブラリを書いてみた。
Ruby は拡張ライブラリを書きやすい(そのために実行速度が犠牲になっている面すらある) と聞いた(読んだ)ことはあったのだが、実際に書いたことはなかった。 書いてみたら、いや、本当に書きやすい。
/* extlibsample.c To create ExtLibSample.so: ruby -r mkmf -e 'create_makefile("ExtLibSample")' and make */ #include "ruby.h" #include <math.h> /* First example: def euclid_norm_2d(x, y) # x, y: Float. sqrt(x*x + y*y) end */ static VALUE euclid_norm_2d(self, vx, vy) VALUE self, vx, vy; { double x, y; Check_Type(vx, T_FLOAT); Check_Type(vy, T_FLOAT); x = RFLOAT(vx)->value; y = RFLOAT(vy)->value; return rb_float_new(sqrt(x * x + y * y)); } /* Second example: def euclid_norm(a) # a: Array. sum = 0 a.each {|v| v = v.float; sum += v*v} sqrt(sum) end */ static VALUE euclid_norm(self, a) VALUE self, a; { int i, size; double v, sum = 0.0; VALUE t; Check_Type(a, T_ARRAY); size = FIX2INT(rb_funcall(a, rb_intern("size"), 0)); for(i = 0; i < size; i++){ t = rb_funcall(a, rb_intern("[]"), 1, INT2FIX(i)); t = rb_funcall(t, rb_intern("to_f"), 0); v = RFLOAT(t)->value; sum += v * v; } return rb_float_new(sqrt(sum)); } Init_ExtLibSample() { VALUE mExtLibSample = rb_define_module("ExtLibSample"); rb_define_module_function(mExtLibSample, "euclid_norm_2d", euclid_norm_2d, 2); rb_define_module_function(mExtLibSample, "euclid_norm", euclid_norm, 1); }
呪文をいっぱい唱える必要がなくて、ありがたい。
書いてみたのは、まったく実用的でない、練習のための例ですが、 以下のことがらを含んでいます。
Ruby オブジェクトの型チェック | Check_Type(obj, T_FLOAT) |
Ruby Float → C double | RFLOAT(obj)->value |
C double → Ruby Float | rb_float_new((double) x) |
Ruby Fixnum → C int | FIX2INT(obj) |
C int → Ruby Fixnum | INT2FIX(1) |
Ruby オブジェクトのメソッド呼び出し | rb_funcall(obj, rb_intern("[]"), 1, INT2FIX(i)) |
モジュール関数の追加 | (略) |
動かしてみるには、次のようにします:
% ruby -r mkmf -e 'create_makefile("ExtLibSample")' % gmake % irb irb(main):001:0> require 'ExtLibSample' => true irb(main):002:0> include ExtLibSample => Object irb(main):003:0> euclid_norm_2d(2.0, 3.0) => 3.60555127546399 irb(main):004:0> euclid_norm([1.0, 2.0, 3.0]) => 3.74165738677394
『オブジェクト指向スクリプト言語 Ruby』の8章に書かれている内容を まったく知らないとつらいかな。
ところで、 ワード境界にアラインされた C オブジェクトのポインタ値が偶数になるというのは 言語仕様の一部ではないような気がするのだが(未確認)、 それが奇数になるようなアーキテクチャを思いつかない。 ワード長が9バイトとか?