ハッシュの使い方

Rubyの拡張ライブラリを作ってはいるが、どこかの何かを見て勉強した、というわけでもなく。ほぼ我流。
強いて言うならREADME.EXT.jaとかRubyのソースとかStarRubyのソースとかを見て勉強した。
今日はDXRubyの実行速度を改善できたのでそのメモ。


DXRubyのWindow.drawExはハッシュキーを持つ。
Cの拡張ライブラリでRubyのHashはrb_hash_aref(obj, key)で値を取れて、現行のDXRubyもそれを使っている。
この関数は参照したキーが無い場合にHashオブジェクトのdefault=で定義された値を返す。設定していなければQnil。
この機能を実現するために、rb_hash_arefでは内部でrb_funcallを呼び出す。Rubyシステム経由でHash#defaultを呼び出している。
これが遅い。
Cでの拡張ライブラリは、用途としては
Rubyでできないことをする
・高速処理をする
に分かれるが、特に後者の場合はRubyシステムを経由しない処理の構築が重要なポイントになる。
DXRubyFrameworkもその方向性で速度を稼いでいるのだが、長いこと止まっているな。ネタを温めているからそのうち新しいモノを作る日も来るだろう。
ともかく、rb_hash_arefを呼ぶ必要があるとハッシュのデータを取得するのがとんでもない負荷になる。
だからDXRubyではdrawExを分けて作って、ハッシュを扱わない高速なメソッドとして色々用意していたわけだ。


で、さっき発見したのがrb_hash_lookupで、これはキーが無かったときにrb_funcallを呼ばずに無条件でQnilを返す。
っていうかQnilを返してくれないと困るロジックを組んでるから、drawExに渡すハッシュにdefaultで変なのを設定されると豪快にバグる。
従って、rb_hash_arefをやめてrb_hash_lookupを使うように修正することで、不具合の解消とともに、大幅な高速化ができる。とりあえず当社比でWindow.drawExによる描画が3〜4割ぐらいは速くなった。それぐらい遅かった。
これはDXRuby1.0.8に取り込まねばなるまい。


まあ、勉強不足といえばミモフタモナイわけだが。
README.EXT.jaにHashの説明が無いのが痛いのかな。