String

RString

String の実体は struct RString であり、ruby.h で定義されている。

struct RString {
    struct RBasic basic;
    long len;
    char *ptr;
    VALUE orig;
};
ptr と len がコア。文字列の実体 char 配列へのポインタが ptr であり、 その長さを len に保持する。

また orig は要求時コピーのために使う。例えば次のようなコードがあったと しよう。

10000.times do
  puts 'this string will not be changed'
end
このコードでは同じ文字列が10000回必要になるが、そのたびに生成して いると遅くなりすぎる。しかし、Ruby では破壊的メソッドによって文字列 自体を変更することができるので、最初に作った(C の)文字列をそのまま 使っているわけにもいかない。そういうわけで、変更が起こるまでは同じ char[] を使っておいて、変更された時点で char[] だけをコピーする、 というようになっている。ただしこの作業が行われるのはコードに埋め 込まれている文字列(リテラル)だけで、そのほかの String には最初から 専用の文字列が用意される。

しかしこのへんの状況は 1.7 で大きく変わりつつある。第一の変化はこの 要求時コピーを全ての文字列で使えるようにしようという動きだ。substr する時にオリジナルの文字列にフラグを立てて、orig にはそのオリジナルを 格納する。そして ptr と len はその orig のものを使う。ということを しているようである。これまでそのようなことをしていなかったのは、 文字列が NUL 終端であることを期待する拡張モジュールなどへの配慮が あるようだ。

第二に多言語化である。正確に言うとマルチエンコーディングだ。現在の Ruby は ASCII か日本語用エンコーディング一個のどちらかで決め打ちに しているわけだが、そうではなくていくつものエンコーディングを同時に 使えるようにしようというのだ。これをやるためにはどうにかして RString にエンコーディングの情報を格納しなければいけない。

だがそこで問題になるのが RVALUE 構造体のサイズである。 GC の章で説明したように、各オブジェクトが使える のはポインタ三つ分なのだが、RString はもうその三つを使い果たして しまっている。そこにどうやってエンコーディング情報を格納するかだが、 ひとつには orig を使う方法が挙げられている。つまり orig では RString ではない、エンコーディング格納用の構造体を指しておくのだ。両者の 区別は basic->flags でつければよい。

と言ってもこのへんはまだまだ流動的だ。実際にどうなるかは、現在実装中 の M17N Ruby が出てきてからでないとわからないだろう。